Lumiera  0.pre.03
»edit your freedom«
gen-node.hpp
Go to the documentation of this file.
1 /*
2  GEN-NODE.hpp - generic node element for tree like data representation
3 
4  Copyright (C) Lumiera.org
5  2015, Hermann Vosseler <Ichthyostega@web.de>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 */
22 
23 
102 #ifndef LIB_DIFF_GEN_NODE_H
103 #define LIB_DIFF_GEN_NODE_H
104 
105 
106 #include "lib/error.hpp"
107 #include "lib/idi/entry-id.hpp"
108 #include "lib/time/timevalue.hpp"
109 #include "lib/diff/record.hpp"
110 #include "lib/variant.hpp"
111 #include "lib/util.hpp"
112 
113 #include <optional>
114 #include <utility>
115 #include <string>
116 #include <deque>
117 
118 namespace lib {
119 namespace diff{
120 
121  namespace error = lumiera::error;
122 
123  struct GenNode;
124  struct Ref;
125 
127  template<>
129  {
130  using Storage = std::vector<GenNode>;
131  using ElmIter = typename Storage::const_iterator;
132 
135  using Access = GenNode const&;
136  };
137 
138 
139 
140 
141  using Rec = Record<GenNode>;
142  using RecRef = RecordRef<GenNode>;
143  using MakeRec = Rec::Mutator;
144  using DataValues = meta::Types<int
145  ,int64_t
146  ,short
147  ,char
148  ,bool
149  ,double
150  ,string
151  ,time::Time
152  ,time::Offset
155  ,hash::LuidH
156  ,RecRef
157  ,Rec
158  >;
159 
160 
161 
162  class DataCap
163  : public Variant<DataValues>
164  {
165  public:
166  template<typename X>
167  DataCap(X&& x)
168  : Variant<DataValues>(std::forward<X>(x))
169  { }
170 
172  DataCap(DataCap const&) =default;
173  DataCap(DataCap&&) =default;
174  DataCap(DataCap& o)
175  : DataCap((DataCap const&)o)
176  { }
177 
178  DataCap& operator= (DataCap const&) =default;
179  DataCap& operator= (DataCap&&) =default;
180 
181  bool matchData (DataCap const&) const;
182  bool matchNum (int64_t) const;
183  bool matchTxt (string const&) const;
184  bool matchTime (time::TimeValue) const;
185  bool matchBool (bool) const;
186  bool matchDbl (double) const;
187  bool matchLuid (hash::LuidH) const;
188  bool matchRec (RecRef const&) const;
189  bool matchRec (Rec const&) const;
190 
191  struct Locator;
192  Locator expand() const;
193 
194  operator string() const;
195 
196  template<typename X>
197  X& get();
198  template<typename X>
199  X const& get() const;
200 
202  Rec::scopeIter
203  childIter() const
204  {
205  const Rec* rec = unConst(this)->maybeGet<Rec>();
206  if (!rec)
207  return Rec::scopeIter();
208  else
209  return rec->scope();
210  }
211 
213  bool isNested() const;
214 
216  string recordType() const;
217 
219  template<typename X>
220  std::optional<X>
221  retrieveAttribute (string key) const;
222 
223  bool hasAttribute (string key) const;
224 
225  private:
226  Rec* maybeAccessNestedRec();
227  };
228 
229 
231  struct GenNode
232  {
233  class ID
234  : public idi::BareEntryID
235  {
236  friend struct GenNode;
237 
238  template<typename X>
239  ID (X*, string const& symbolicID)
240  : idi::BareEntryID (symbolicID,
241  idi::getTypeHash<X>())
242  { }
243 
244  ID (idi::BareEntryID&& rawD)
245  : idi::BareEntryID{move (rawD)}
246  { }
247 
248  public:
249  explicit
250  ID (GenNode const& node)
251  : ID(node.idi)
252  { }
253 
254  // standard copy operations acceptable
255 
256  operator string() const
257  {
258  return "ID(\""+getSym()+"\")";
259  }
260  };
261 
262 
263  //------GenNode Data fields---
264 
265  ID idi;
266  DataCap data;
267 
268 
269  template<typename X>
270  GenNode(X&& val)
271  : idi(&val, buildChildID<X>())
272  , data(std::forward<X>(val))
273  { }
274 
275  template<typename X>
276  GenNode(string const& symbolicID, X&& val)
277  : idi(&val, symbolicID)
278  , data(std::forward<X>(val))
279  { }
280 
281  GenNode(string const& symbolicID, const char* text)
282  : GenNode(symbolicID, string(text))
283  { }
284 
285  GenNode(const char* text)
286  : GenNode(string(text))
287  { }
288 
290  GenNode(GenNode const&) =default;
291  GenNode(GenNode&&) =default;
292  GenNode(GenNode& o) : GenNode((GenNode const&)o) { }
293  GenNode(Ref const& r);
294  GenNode(Ref & r);
295  GenNode(Ref && r);
296 
313  GenNode&
314  operator= (GenNode const& o)
315  {
316  if (&o != this)
317  {
318  data = o.data;
319  idi = o.idi;
320  }
321  return *this;
322  }
323 
324  GenNode&
325  operator= (GenNode&& o)
326  {
327  ASSERT (&o != this);
328  data = std::forward<DataCap>(o.data);
329  idi = std::forward<ID>(o.idi);
330  return *this;
331  }
332 
333  //note: NOT defining a swap operation, because swapping inline storage is pointless!
334 
335 
336 
337 
339  operator string() const
340  {
341  return "GenNode-"+string(idi)+"-"+string(data);
342  }
343 
344  bool
345  isNamed() const
346  {
347  return not util::startsWith (idi.getSym(), "_CHILD_");
348  }
349 
350  bool
351  isTypeID() const
352  {
353  return "type" == idi.getSym();
354  }
355 
356  template<typename X>
357  bool contains (X const& elm) const;
358 
359 
360  bool matches (GenNode const& o) const { return this->matches(o.idi); }
361  bool matches (ID const& id) const { return idi == id; }
362  bool matches (int number) const { return data.matchNum(number);}
363  bool matches (int64_t number) const { return data.matchNum(number);}
364  bool matches (short number) const { return data.matchNum(number);}
365  bool matches (char number) const { return data.matchNum(number);}
366  bool matches (double number) const { return data.matchDbl(number);}
367  bool matches (string text) const { return data.matchTxt(text);}
368  bool matches (const char* text) const { return data.matchTxt(text);}
369  bool matches (time::TimeValue t) const { return data.matchTime(t); }
370  bool matches (bool b) const { return data.matchBool(b); }
371  bool matches (hash::LuidH h) const { return data.matchLuid(h); }
372  bool matches (RecRef const& ref) const { return data.matchRec(ref); }
373  bool matches (Rec const& rec) const { return data.matchRec(rec); }
374 
375  class ScopeExplorer;
376 
377  struct ScopeExplorerIterator;
379 
380  iterator begin() ;
381  iterator begin() const;
382  iterator end() ;
383  iterator end() const;
384 
385 
387 
395  friend ChildDataIter
396  childData (GenNode const& n)
397  {
398  return ChildDataIter{ n.data.childIter()
399  , [](GenNode const& child) ->DataCap const&
400  {
401  return child.data;
402  }
403  };
404  }
405 
406  friend ChildDataIter
407  childData (Rec::scopeIter&& scopeIter)
408  {
409  return ChildDataIter{ std::forward<Rec::scopeIter>(scopeIter)
410  , [](GenNode const& child) ->DataCap const&
411  {
412  return child.data;
413  }
414  };
415  }
416 
417 
418  friend string
419  name (GenNode const& node)
420  {
421  return node.idi.getSym();
422  }
423 
424  friend bool
425  operator== (GenNode const& n1, GenNode const& n2)
426  {
427  return n1.idi == n2.idi
428  && n1.data.matchData(n2.data);
429  }
430 
431  friend bool
432  operator!= (GenNode const& n1, GenNode const& n2)
433  {
434  return not (n1 == n2);
435  }
436 
450  {
451  bool
452  operator() (GenNode const& left, GenNode const& right) const
453  {
454  return left.idi.getSym() < right.idi.getSym();
455  }
456  };
457 
459  template<typename X>
460  static GenNode
461  asAttribute (idi::BareEntryID && rawID, X&& payload)
462  {
463  return GenNode{ID{move (rawID)}, DataCap{forward<X> (payload)}};
464  }
465 
468  template<typename X>
469  std::optional<X>
470  retrieveAttribute (string key) const;
471 
472  bool hasAttribute (string key) const;
473  bool isNested() const;
474  bool hasChildren() const;
475  Rec::scopeIter getChildren() const;
476 
477 
478 
479  protected:
481  GenNode (ID&& id, DataCap&& d)
482  : idi(std::move(id))
483  , data(std::move(d))
484  { }
485 
486  template<typename X>
487  static GenNode::ID
488  fabricateRefID (string const& symbolicID)
489  {
490  X* typeID(0);
491  return ID(typeID, symbolicID);
492  }
493 
494  private:
495  template<typename X>
496  static string
497  buildChildID()
498  {
499  return "_CHILD_" + idi::generateSymbolicID<X>();
500  }
501  };
502 
503 
505  string renderCompact (GenNode const&);
506  string renderCompact (RecRef const&);
507  string renderCompact (Rec const&);
508 
509 
510 
511 
512 
513 
521  template<typename ELM>
523  {
524  using Yes = lib::meta::Yes_t;
525  using No = lib::meta::No_t;
526 
527  template<class X>
528  static Yes check(typename variant::CanBuildFrom<X, DataValues>::Type*);
529  template<class X>
530  static No check(...);
531 
532  public:
533  static const bool value = (sizeof(Yes)==sizeof(check<ELM>(0)));
534  };
535 
536 
537 
538 
539  /* === iteration / recursive expansion === */
540 
541 
549  {
550  const GenNode* node_;
551  Rec::iterator scope_;
552 
553  Locator()
554  : node_(nullptr)
555  { }
556 
557  Locator(GenNode const& n)
558  : node_(&n)
559  { }
560 
561  Locator(Rec const& r)
562  : node_(nullptr)
563  , scope_(r.begin())
564  { }
565 
566  const GenNode *
567  get() const
568  {
569  return node_? node_
570  : scope_? scope_.operator->()
571  : nullptr;
572  }
573 
574  /* === Iteration control API for IterStateWrapper == */
575 
576  bool
577  checkPoint() const
578  {
579  return this->get();
580  }
581 
582  GenNode const&
583  yield() const
584  {
585  return *get();
586  }
587 
588  void
589  iterNext()
590  {
591  if (node_)
592  node_ = nullptr;
593  else
594  ++scope_;
595  }
596  };
597 
598 
605  {
607 
608  std::deque<ScopeIter> scopes_;
609 
610  public:
611  ScopeExplorer() { }
612  ScopeExplorer(GenNode const& n)
613  {
614  scopes_.emplace_back(n);
615  }
616 
617  size_t
618  depth() const
619  {
620  return scopes_.size();
621  }
622 
623  /* === Iteration control API for IterStateWrapper == */
624 
625  bool
626  checkPoint() const
627  {
628  return not scopes_.empty()
629  and bool(scopes_.back());
630  }
631 
632  GenNode const&
633  yield() const
634  {
635  return *(scopes_.back());
636  }
637 
638  void
639  iterNext()
640  {
641  ScopeIter& current = scopes_.back();
642  scopes_.emplace_back (current->data.expand());
643  ++current;
644  while (not scopes_.empty() and not scopes_.back())
645  scopes_.pop_back();
646  }
647 
648  friend bool
649  operator== (ScopeExplorer const& s1, ScopeExplorer const& s2)
650  {
651  return not s1.scopes_.empty()
652  && not s2.scopes_.empty()
653  && s1.scopes_.size() == s2.scopes_.size()
654  && s1.yield() == s2.yield();
655  }
656  };
657 
658 
660  inline DataCap::Locator
662  {
663  Rec* val = unConst(this)->maybeGet<Rec>();
664  if (!val)
665  return Locator();
666  else
667  return Locator(*val);
668  }
669 
670 
672  : IterStateWrapper<const GenNode, ScopeExplorer>
673  {
675 
676  size_t level() const { return unConst(this)->stateCore().depth(); }
677  };
678 
679 
680  inline GenNode::iterator GenNode::begin() { return iterator(*this); }
681  inline GenNode::iterator GenNode::begin() const { return iterator(*this); }
682  inline GenNode::iterator GenNode::end() { return iterator(); }
683  inline GenNode::iterator GenNode::end() const { return iterator(); }
684 
685  template<typename X>
686  inline bool
687  GenNode::contains (X const& elm) const
688  {
689  for (auto & n : *this)
690  if (n.matches(elm))
691  return true;
692  return false;
693  }
694 
695 
696 
697 
698  /* === References : special treatment on element access === */
699 
700  template<typename X>
701  inline X&
702  DataCap::get()
703  {
704  return Variant<DataValues>::get<X>();
705  }
706 
707  template<typename X>
708  inline X const&
709  DataCap::get() const
710  {
711  return Variant<DataValues>::get<X>();
712  }
713 
727  template<>
728  inline Rec&
729  DataCap::get()
730  {
731  Rec* rec = maybeGet<Rec>();
732  if (rec) return *rec;
733 
734  return Variant<DataValues>::get<RecRef>();
735  }
736 
737  template<>
738  inline Rec const&
739  DataCap::get() const
740  {
741  Rec* rec = unConst(this)->maybeGet<Rec>();
742  if (rec) return *rec;
743 
744  return Variant<DataValues>::get<RecRef>();
745  }
746 
748  inline Rec*
750  {
751  Rec* nested = maybeGet<Rec>();
752  if (!nested)
753  { // 2nd try: maybe we hold a reference?
754  RecRef* ref = maybeGet<RecRef>();
755  if (ref and not ref->empty())
756  nested = ref->get();
757  }
758  return nested;
759  }
760 
768  inline string
770  {
771  Rec* nested = unConst(this)->maybeAccessNestedRec();
772  return nested? nested->getType()
773  : util::BOTTOM_INDICATOR;
774  }
775 
776  inline bool
778  {
779  return nullptr != unConst(this)->maybeAccessNestedRec();
780  }
781 
782 
783  template<typename X>
784  inline std::optional<X>
785  DataCap::retrieveAttribute (string key) const
786  {
787  static_assert (not std::is_reference_v<X>
788  ,"optional access only possible by value");
789 
790  Rec* nested = unConst(this)->maybeAccessNestedRec();
791  if (nested and nested->hasAttribute (key))
792  {
793  DataCap const& nestedAttributeData = nested->get(key).data;
794  X* payload = unConst(nestedAttributeData).maybeGet<X>();
795  if (payload) return *payload; // Note: payload copied into optional
796  }
797  return std::nullopt;
798  }
799 
800  inline bool
801  DataCap::hasAttribute (string key) const
802  {
803  Rec* nested = unConst(this)->maybeAccessNestedRec();
804  return nested and nested->hasAttribute (key);
805  }
806 
807  template<typename X>
808  inline std::optional<X>
809  GenNode::retrieveAttribute (string key) const
810  {
811  return data.retrieveAttribute<X> (key);
812  }
813 
814  inline bool
815  GenNode::hasAttribute (string key) const
816  {
817  return data.hasAttribute (key);
818  }
819 
820  inline bool
821  GenNode::isNested() const
822  {
823  return data.isNested();
824  }
825 
826  inline bool
827  GenNode::hasChildren() const
828  {
829  return not isnil (data.childIter());
830  }
831 
832  inline Rec::scopeIter
833  GenNode::getChildren() const
834  {
835  return data.childIter();
836  }
837 
838 
839 
840 
841 
842 
849  struct Ref
850  : GenNode
851  {
855  explicit
856  Ref(string const& symbolicID)
857  : GenNode(fabricateRefID<Rec> (symbolicID)//note: seeds the type hash with Rec, not RecRef
858  , DataCap(RecRef())) // note: places NIL into the reference part
859  { }
860 
864  Ref(GenNode& oNode)
865  : GenNode(ID(oNode)
866  , DataCap(RecRef(oNode.data.get<Rec>())))
867  { }
868 
869  static const Ref I;
870  static const Ref NO;
871  static const Ref END;
872  static const Ref THIS;
873  static const Ref CHILD;
874  static const Ref ATTRIBS;
875  };
876 
877 
878  // slice down on copy construction...
879  inline GenNode::GenNode(Ref const& r) : idi(r.idi), data(r.data) { }
880  inline GenNode::GenNode(Ref & r) : idi(r.idi), data(r.data) { }
881  inline GenNode::GenNode(Ref && r) : idi(std::move(r.idi)),
882  data(std::move(r.data)) { }
883 
884 
885  /* === Specialisation to add fluent GenNode builder API to Record<GenNode> === */
886 
887  template<>
888  inline GenNode
889  MakeRec::genNode()
890  {
891  return GenNode{std::move(record_)};
892  }
893 
894  template<>
895  inline GenNode
896  MakeRec::genNode (idi::BareEntryID rawID)
897  {
898  return GenNode::asAttribute (std::move(rawID), std::move(record_));
899  }
900 
901  template<>
902  inline GenNode
903  MakeRec::genNode (string const& symbolicID)
904  {
905  return GenNode{symbolicID, std::move(record_)};
906  }
907 
908 
909  /* === Extension point to apply a tree-diff === */
910 
915  template<>
916  void MakeRec::buildMutator (BufferHandle buff);
917 
918 
919 
920  /* === Specialisation for handling of attributes in Record<GenNode> === */
921 
922  template<>
923  inline bool
924  Rec::isAttribute (GenNode const& attrib)
925  {
926  return attrib.isNamed();
927  }
928 
929  template<>
930  inline bool
931  Rec::isTypeID (GenNode const& attrib)
932  {
933  return attrib.isTypeID();
934  }
935 
936  template<>
937  inline string
938  Rec::extractTypeID (GenNode const& v)
939  {
940  return isTypeID(v)? v.data.get<string>()
941  : Rec::TYPE_NIL;
942  }
943 
944  template<>
945  inline string
946  Rec::extractKey (GenNode const& v)
947  {
948  return isAttribute(v)? v.idi.getSym()
949  : "";
950  }
951 
952  template<>
953  inline GenNode const&
954  Rec::extractVal (GenNode const& v)
955  {
956  return v;
957  }
958 
959  template<>
960  inline string
961  Rec::renderAttribute (GenNode const& a)
962  {
963  return a.idi.getSym() +" = "+ string(a.data);
964  }
965 
966  template<>
967  template<typename X>
968  inline GenNode
969  Rec::buildAttribute (string const& key, X&& payload)
970  {
971  return GenNode{key, forward<X>(payload)};
972  }
973 
974 
975 
976 }// namespace lib::diff
977 
978 namespace variant {
979  using diff::Rec;
980 
985  template<typename TYPES>
986  struct CanBuildFrom<diff::MakeRec, Node<Rec, TYPES>>
987  : std::true_type
988  {
989  using Type = Rec;
990  };
991 
992 }} // namespace lib::variant
993 #endif /*LIB_DIFF_GEN_NODE_H*/
static const Ref I
symbolic ID ref "_I_"
Definition: gen-node.hpp:869
type erased baseclass for building a combined hash and symbolic ID.
Definition: entry-id.hpp:142
metafunction to detect types able to be wrapped into a GenNode.
Definition: gen-node.hpp:522
Constructor for a specially crafted &#39;ref GenNode&#39;.
Definition: gen-node.hpp:849
bool isNested() const
determine if payload constitutes a nested scope ("object")
Definition: gen-node.hpp:777
friend ChildDataIter childData(GenNode const &n)
visit the data of nested child elements
Definition: gen-node.hpp:396
GenNode(ID &&id, DataCap &&d)
Definition: gen-node.hpp:481
std::optional< X > retrieveAttribute(string key) const
peek into the attributes of a nested Record
Definition: gen-node.hpp:785
Rec::scopeIter childIter() const
visit children of a nested Record<GenNode>
Definition: gen-node.hpp:203
Typesafe union record.
Definition: variant.hpp:224
STL namespace.
bool operator==(PtrDerefIter< I1 > const &il, PtrDerefIter< I2 > const &ir)
Supporting equality comparisons...
static const Ref CHILD
symbolic ID ref "_CHILD_"
Definition: gen-node.hpp:873
string renderCompact(Rec const &rec)
compact textual representation of a Record<GenNode> (»object«).
Definition: gen-node.cpp:299
Building block for monad-like depth-first expansion of a GenNode.
Definition: gen-node.hpp:604
iterator begin() const
default iteration exposes all data within this "object", starting with the attributes ...
Definition: record.hpp:318
Implementation namespace for support and library code.
Lumiera&#39;s internal time value datatype.
Definition: timevalue.hpp:308
Special collection to represent object-like data.
static const Ref END
symbolic ID ref "_END_"
Definition: gen-node.hpp:871
bool matchData(DataCap const &) const
Implementation of content equality test, delgating to content.
Definition: gen-node.cpp:87
allow for storage in ordered containers, ordering based on the human-readable ID within the GenNode...
Definition: gen-node.hpp:449
A typesafe union record to carry embedded values of unrelated type.
Another Lumiera Forward Iterator building block, based on incorporating a state type right into the i...
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
Iterator tool treating pulled data by a custom transformation (function)
Definition: itertools.hpp:763
wrapped record reference.
Definition: record.hpp:620
char Yes_t
helper types to detect the overload resolution chosen by the compiler
Definition: meta/util.hpp:104
Rec * maybeAccessNestedRec()
Definition: gen-node.hpp:749
std::optional< X > retrieveAttribute(string key) const
mismatch tolerant convenience shortcut to peek into the attributes of a nested Record ...
Definition: gen-node.hpp:809
static const Ref NO
symbolic ID ref "_NO_"
Definition: gen-node.hpp:870
void buildMutator(BufferHandle)
attachment point to receive and apply tree-diff changes.
Locator expand() const
Definition: gen-node.hpp:661
Lumiera error handling (C++ interface).
static GenNode asAttribute(idi::BareEntryID &&rawID, X &&payload)
fabricate a GenNode with the literally given ID
Definition: gen-node.hpp:461
Hash implementation based on a lumiera unique object id (LUID) When invoking the default ctor...
bool matches(GenNode const &o) const
Definition: gen-node.hpp:360
static const Ref ATTRIBS
symbolic ID ref "_ATTRIBS_"
Definition: gen-node.hpp:874
Offset measures a distance in time.
Definition: timevalue.hpp:367
string recordType() const
peek into the type field of a nested Record<GenNode>
Definition: gen-node.hpp:769
Duration is the internal Lumiera time metric.
Definition: timevalue.hpp:477
Ref(string const &symbolicID)
create an empty ID stand-in.
Definition: gen-node.hpp:856
Bare symbolic and hash ID used for accounting of asset like entries.
std::function< UICoord(Literal)> Locator
Locator is a functor to resolve to a topological location in the UI-tree.
A time interval anchored at a specific point in time.
Definition: timevalue.hpp:582
Ref(GenNode &oNode)
build reference to a Record, using the original ID
Definition: gen-node.hpp:864
a family of time value like entities and their relationships.
object-like record of data.
Definition: record.hpp:150
static const Ref THIS
symbolic ID ref "_THIS_"
Definition: gen-node.hpp:872
basic constant internal time value.
Definition: timevalue.hpp:142
GenNode const & Access
using const reference data access relevant for handling large subtrees
Definition: gen-node.hpp:135
Adapter for building an implementation of the »Lumiera Forward Iterator« concept. ...
ElementBoxWidget::Config::Qualifier name(string id)
define the name-ID displayed in the caption
generic data element node within a tree
Definition: gen-node.hpp:231