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)
5  2015, Hermann Vosseler <Ichthyostega@web.de>
6 
7   **Lumiera** is free software; you can redistribute it and/or modify it
8   under the terms of the GNU General Public License as published by the
9   Free Software Foundation; either version 2 of the License, or (at your
10   option) any later version. See the file COPYING for further details.
11 
12 */
13 
14 
93 #ifndef LIB_DIFF_GEN_NODE_H
94 #define LIB_DIFF_GEN_NODE_H
95 
96 
97 #include "lib/error.hpp"
98 #include "lib/idi/entry-id.hpp"
99 #include "lib/time/timevalue.hpp"
100 #include "lib/diff/record.hpp"
101 #include "lib/variant.hpp"
102 #include "lib/util.hpp"
103 
104 #include <optional>
105 #include <utility>
106 #include <string>
107 #include <deque>
108 
109 namespace lib {
110 namespace diff{
111 
112  namespace error = lumiera::error;
113 
114  struct GenNode;
115  struct Ref;
116 
118  template<>
120  {
121  using Storage = std::vector<GenNode>;
122  using ElmIter = typename Storage::const_iterator;
123 
126  using Access = GenNode const&;
127  };
128 
129 
130 
131 
132  using Rec = Record<GenNode>;
133  using RecRef = RecordRef<GenNode>;
134  using MakeRec = Rec::Mutator;
135  using DataValues = meta::Types<int
136  ,int64_t
137  ,short
138  ,char
139  ,bool
140  ,double
141  ,string
142  ,time::Time
143  ,time::Offset
146  ,hash::LuidH
147  ,RecRef
148  ,Rec
149  >;
150 
151 
152 
153  class DataCap
154  : public Variant<DataValues>
155  {
156  public:
157  template<typename X>
158  DataCap(X&& x)
159  : Variant<DataValues>(std::forward<X>(x))
160  { }
161 
163  DataCap(DataCap const&) =default;
164  DataCap(DataCap&&) =default;
165  DataCap(DataCap& o)
166  : DataCap((DataCap const&)o)
167  { }
168 
169  DataCap& operator= (DataCap const&) =default;
170  DataCap& operator= (DataCap&&) =default;
171 
172  bool matchData (DataCap const&) const;
173  bool matchNum (int64_t) const;
174  bool matchTxt (string const&) const;
175  bool matchTime (time::TimeValue) const;
176  bool matchBool (bool) const;
177  bool matchDbl (double) const;
178  bool matchLuid (hash::LuidH) const;
179  bool matchRec (RecRef const&) const;
180  bool matchRec (Rec const&) const;
181 
182  struct Locator;
183  Locator expand() const;
184 
185  operator string() const;
186 
187  template<typename X>
188  X& get();
189  template<typename X>
190  X const& get() const;
191 
193  Rec::scopeIter
194  childIter() const
195  {
196  const Rec* rec = unConst(this)->maybeGet<Rec>();
197  if (!rec)
198  return Rec::scopeIter();
199  else
200  return rec->scope();
201  }
202 
204  bool isNested() const;
205 
207  string recordType() const;
208 
210  template<typename X>
211  std::optional<X>
212  retrieveAttribute (string key) const;
213 
214  bool hasAttribute (string key) const;
215 
216  private:
217  Rec* maybeAccessNestedRec();
218  };
219 
220 
222  struct GenNode
223  {
224  class ID
225  : public idi::BareEntryID
226  {
227  friend struct GenNode;
228 
229  template<typename X>
230  ID (X*, string const& symbolicID)
231  : idi::BareEntryID (symbolicID,
232  idi::getTypeHash<X>())
233  { }
234 
235  ID (idi::BareEntryID&& rawD)
236  : idi::BareEntryID{move (rawD)}
237  { }
238 
239  public:
240  explicit
241  ID (GenNode const& node)
242  : ID(node.idi)
243  { }
244 
245  // standard copy operations acceptable
246 
247  operator string() const
248  {
249  return "ID(\""+getSym()+"\")";
250  }
251  };
252 
253 
254  //------GenNode Data fields---
255 
256  ID idi;
257  DataCap data;
258 
259 
260  template<typename X>
261  GenNode(X&& val)
262  : idi(&val, buildChildID<X>())
263  , data(std::forward<X>(val))
264  { }
265 
266  template<typename X>
267  GenNode(string const& symbolicID, X&& val)
268  : idi(&val, symbolicID)
269  , data(std::forward<X>(val))
270  { }
271 
272  GenNode(string const& symbolicID, const char* text)
273  : GenNode(symbolicID, string(text))
274  { }
275 
276  GenNode(const char* text)
277  : GenNode(string(text))
278  { }
279 
281  GenNode(GenNode const&) =default;
282  GenNode(GenNode&&) =default;
283  GenNode(GenNode& o) : GenNode((GenNode const&)o) { }
284  GenNode(Ref const& r);
285  GenNode(Ref & r);
286  GenNode(Ref && r);
287 
304  GenNode&
305  operator= (GenNode const& o)
306  {
307  if (&o != this)
308  {
309  data = o.data;
310  idi = o.idi;
311  }
312  return *this;
313  }
314 
315  GenNode&
316  operator= (GenNode&& o)
317  {
318  ASSERT (&o != this);
319  data = std::forward<DataCap>(o.data);
320  idi = std::forward<ID>(o.idi);
321  return *this;
322  }
323 
324  //note: NOT defining a swap operation, because swapping inline storage is pointless!
325 
326 
327 
328 
330  operator string() const
331  {
332  return "GenNode-"+string(idi)+"-"+string(data);
333  }
334 
335  bool
336  isNamed() const
337  {
338  return not util::startsWith (idi.getSym(), "_CHILD_");
339  }
340 
341  bool
342  isTypeID() const
343  {
344  return "type" == idi.getSym();
345  }
346 
347  template<typename X>
348  bool contains (X const& elm) const;
349 
350 
351  bool matches (GenNode const& o) const { return this->matches(o.idi); }
352  bool matches (ID const& id) const { return idi == id; }
353  bool matches (int number) const { return data.matchNum(number);}
354  bool matches (int64_t number) const { return data.matchNum(number);}
355  bool matches (short number) const { return data.matchNum(number);}
356  bool matches (char number) const { return data.matchNum(number);}
357  bool matches (double number) const { return data.matchDbl(number);}
358  bool matches (string text) const { return data.matchTxt(text);}
359  bool matches (const char* text) const { return data.matchTxt(text);}
360  bool matches (time::TimeValue t) const { return data.matchTime(t); }
361  bool matches (bool b) const { return data.matchBool(b); }
362  bool matches (hash::LuidH h) const { return data.matchLuid(h); }
363  bool matches (RecRef const& ref) const { return data.matchRec(ref); }
364  bool matches (Rec const& rec) const { return data.matchRec(rec); }
365 
366  class ScopeExplorer;
367 
368  struct ScopeExplorerIterator;
370 
371  iterator begin() ;
372  iterator begin() const;
373  iterator end() ;
374  iterator end() const;
375 
376 
378 
386  friend ChildDataIter
387  childData (GenNode const& n)
388  {
389  return ChildDataIter{ n.data.childIter()
390  , [](GenNode const& child) ->DataCap const&
391  {
392  return child.data;
393  }
394  };
395  }
396 
397  friend ChildDataIter
398  childData (Rec::scopeIter&& scopeIter)
399  {
400  return ChildDataIter{ std::forward<Rec::scopeIter>(scopeIter)
401  , [](GenNode const& child) ->DataCap const&
402  {
403  return child.data;
404  }
405  };
406  }
407 
408 
409  friend string
410  name (GenNode const& node)
411  {
412  return node.idi.getSym();
413  }
414 
415  friend bool
416  operator== (GenNode const& n1, GenNode const& n2)
417  {
418  return n1.idi == n2.idi
419  && n1.data.matchData(n2.data);
420  }
421 
422  friend bool
423  operator!= (GenNode const& n1, GenNode const& n2)
424  {
425  return not (n1 == n2);
426  }
427 
441  {
442  bool
443  operator() (GenNode const& left, GenNode const& right) const
444  {
445  return left.idi.getSym() < right.idi.getSym();
446  }
447  };
448 
450  template<typename X>
451  static GenNode
452  asAttribute (idi::BareEntryID && rawID, X&& payload)
453  {
454  return GenNode{ID{move (rawID)}, DataCap{forward<X> (payload)}};
455  }
456 
459  template<typename X>
460  std::optional<X>
461  retrieveAttribute (string key) const;
462 
463  bool hasAttribute (string key) const;
464  bool isNested() const;
465  bool hasChildren() const;
466  Rec::scopeIter getChildren() const;
467 
468 
469 
470  protected:
472  GenNode (ID&& id, DataCap&& d)
473  : idi(std::move(id))
474  , data(std::move(d))
475  { }
476 
477  template<typename X>
478  static GenNode::ID
479  fabricateRefID (string const& symbolicID)
480  {
481  X* typeID(0);
482  return ID(typeID, symbolicID);
483  }
484 
485  private:
486  template<typename X>
487  static string
488  buildChildID()
489  {
490  return "_CHILD_" + idi::generateSymbolicID<X>();
491  }
492  };
493 
494 
496  string renderCompact (GenNode const&);
497  string renderCompact (RecRef const&);
498  string renderCompact (Rec const&);
499 
500 
501 
502 
503 
504 
512  template<typename ELM>
514  {
515  using Yes = lib::meta::Yes_t;
516  using No = lib::meta::No_t;
517 
518  template<class X>
519  static Yes check(typename variant::CanBuildFrom<X, DataValues>::Type*);
520  template<class X>
521  static No check(...);
522 
523  public:
524  static const bool value = (sizeof(Yes)==sizeof(check<ELM>(0)));
525  };
526 
527 
528 
529 
530  /* === iteration / recursive expansion === */
531 
532 
540  {
541  const GenNode* node_;
542  Rec::iterator scope_;
543 
544  Locator()
545  : node_(nullptr)
546  { }
547 
548  Locator(GenNode const& n)
549  : node_(&n)
550  { }
551 
552  Locator(Rec const& r)
553  : node_(nullptr)
554  , scope_(r.begin())
555  { }
556 
557  const GenNode *
558  get() const
559  {
560  return node_? node_
561  : scope_? scope_.operator->()
562  : nullptr;
563  }
564 
565  /* === Iteration control API for IterStateWrapper == */
566 
567  bool
568  checkPoint() const
569  {
570  return this->get();
571  }
572 
573  GenNode const&
574  yield() const
575  {
576  return *get();
577  }
578 
579  void
580  iterNext()
581  {
582  if (node_)
583  node_ = nullptr;
584  else
585  ++scope_;
586  }
587  };
588 
589 
596  {
598 
599  std::deque<ScopeIter> scopes_;
600 
601  public:
602  ScopeExplorer() { }
603  ScopeExplorer(GenNode const& n)
604  {
605  scopes_.emplace_back(n);
606  }
607 
608  size_t
609  depth() const
610  {
611  return scopes_.size();
612  }
613 
614  /* === Iteration control API for IterStateWrapper == */
615 
616  bool
617  checkPoint() const
618  {
619  return not scopes_.empty()
620  and bool(scopes_.back());
621  }
622 
623  GenNode const&
624  yield() const
625  {
626  return *(scopes_.back());
627  }
628 
629  void
630  iterNext()
631  {
632  ScopeIter& current = scopes_.back();
633  scopes_.emplace_back (current->data.expand());
634  ++current;
635  while (not scopes_.empty() and not scopes_.back())
636  scopes_.pop_back();
637  }
638 
639  friend bool
640  operator== (ScopeExplorer const& s1, ScopeExplorer const& s2)
641  {
642  return not s1.scopes_.empty()
643  && not s2.scopes_.empty()
644  && s1.scopes_.size() == s2.scopes_.size()
645  && s1.yield() == s2.yield();
646  }
647  };
648 
649 
651  inline DataCap::Locator
653  {
654  Rec* val = unConst(this)->maybeGet<Rec>();
655  if (!val)
656  return Locator();
657  else
658  return Locator(*val);
659  }
660 
661 
663  : IterStateWrapper<ScopeExplorer>
664  {
665  using IterStateWrapper::IterStateWrapper;
666 
667  size_t level() const { return unConst(this)->stateCore().depth(); }
668  };
669 
670 
671  inline GenNode::iterator GenNode::begin() { return iterator(*this); }
672  inline GenNode::iterator GenNode::begin() const { return iterator(*this); }
673  inline GenNode::iterator GenNode::end() { return iterator(); }
674  inline GenNode::iterator GenNode::end() const { return iterator(); }
675 
676  template<typename X>
677  inline bool
678  GenNode::contains (X const& elm) const
679  {
680  for (auto & n : *this)
681  if (n.matches(elm))
682  return true;
683  return false;
684  }
685 
686 
687 
688 
689  /* === References : special treatment on element access === */
690 
691  template<typename X>
692  inline X&
693  DataCap::get()
694  {
695  return Variant<DataValues>::get<X>();
696  }
697 
698  template<typename X>
699  inline X const&
700  DataCap::get() const
701  {
702  return Variant<DataValues>::get<X>();
703  }
704 
718  template<>
719  inline Rec&
720  DataCap::get()
721  {
722  Rec* rec = maybeGet<Rec>();
723  if (rec) return *rec;
724 
725  return Variant<DataValues>::get<RecRef>();
726  }
727 
728  template<>
729  inline Rec const&
730  DataCap::get() const
731  {
732  Rec* rec = unConst(this)->maybeGet<Rec>();
733  if (rec) return *rec;
734 
735  return Variant<DataValues>::get<RecRef>();
736  }
737 
739  inline Rec*
741  {
742  Rec* nested = maybeGet<Rec>();
743  if (!nested)
744  { // 2nd try: maybe we hold a reference?
745  RecRef* ref = maybeGet<RecRef>();
746  if (ref and not ref->empty())
747  nested = ref->get();
748  }
749  return nested;
750  }
751 
759  inline string
761  {
762  Rec* nested = unConst(this)->maybeAccessNestedRec();
763  return nested? nested->getType()
764  : util::BOTTOM_INDICATOR;
765  }
766 
767  inline bool
769  {
770  return nullptr != unConst(this)->maybeAccessNestedRec();
771  }
772 
773 
774  template<typename X>
775  inline std::optional<X>
776  DataCap::retrieveAttribute (string key) const
777  {
778  static_assert (not std::is_reference_v<X>
779  ,"optional access only possible by value");
780 
781  Rec* nested = unConst(this)->maybeAccessNestedRec();
782  if (nested and nested->hasAttribute (key))
783  {
784  DataCap const& nestedAttributeData = nested->get(key).data;
785  X* payload = unConst(nestedAttributeData).maybeGet<X>();
786  if (payload) return *payload; // Note: payload copied into optional
787  }
788  return std::nullopt;
789  }
790 
791  inline bool
792  DataCap::hasAttribute (string key) const
793  {
794  Rec* nested = unConst(this)->maybeAccessNestedRec();
795  return nested and nested->hasAttribute (key);
796  }
797 
798  template<typename X>
799  inline std::optional<X>
800  GenNode::retrieveAttribute (string key) const
801  {
802  return data.retrieveAttribute<X> (key);
803  }
804 
805  inline bool
806  GenNode::hasAttribute (string key) const
807  {
808  return data.hasAttribute (key);
809  }
810 
811  inline bool
812  GenNode::isNested() const
813  {
814  return data.isNested();
815  }
816 
817  inline bool
818  GenNode::hasChildren() const
819  {
820  return not isnil (data.childIter());
821  }
822 
823  inline Rec::scopeIter
824  GenNode::getChildren() const
825  {
826  return data.childIter();
827  }
828 
829 
830 
831 
832 
833 
840  struct Ref
841  : GenNode
842  {
846  explicit
847  Ref(string const& symbolicID)
848  : GenNode(fabricateRefID<Rec> (symbolicID)//note: seeds the type hash with Rec, not RecRef
849  , DataCap(RecRef())) // note: places NIL into the reference part
850  { }
851 
855  Ref(GenNode& oNode)
856  : GenNode(ID(oNode)
857  , DataCap(RecRef(oNode.data.get<Rec>())))
858  { }
859 
860  static const Ref I;
861  static const Ref NO;
862  static const Ref END;
863  static const Ref THIS;
864  static const Ref CHILD;
865  static const Ref ATTRIBS;
866  };
867 
868 
869  // slice down on copy construction...
870  inline GenNode::GenNode(Ref const& r) : idi(r.idi), data(r.data) { }
871  inline GenNode::GenNode(Ref & r) : idi(r.idi), data(r.data) { }
872  inline GenNode::GenNode(Ref && r) : idi(std::move(r.idi)),
873  data(std::move(r.data)) { }
874 
875 
876  /* === Specialisation to add fluent GenNode builder API to Record<GenNode> === */
877 
878  template<>
879  inline GenNode
880  MakeRec::genNode()
881  {
882  return GenNode{std::move(record_)};
883  }
884 
885  template<>
886  inline GenNode
887  MakeRec::genNode (idi::BareEntryID rawID)
888  {
889  return GenNode::asAttribute (std::move(rawID), std::move(record_));
890  }
891 
892  template<>
893  inline GenNode
894  MakeRec::genNode (string const& symbolicID)
895  {
896  return GenNode{symbolicID, std::move(record_)};
897  }
898 
899 
900  /* === Extension point to apply a tree-diff === */
901 
906  template<>
907  void MakeRec::buildMutator (BufferHandle buff);
908 
909 
910 
911  /* === Specialisation for handling of attributes in Record<GenNode> === */
912 
913  template<>
914  inline bool
915  Rec::isAttribute (GenNode const& attrib)
916  {
917  return attrib.isNamed();
918  }
919 
920  template<>
921  inline bool
922  Rec::isTypeID (GenNode const& attrib)
923  {
924  return attrib.isTypeID();
925  }
926 
927  template<>
928  inline string
929  Rec::extractTypeID (GenNode const& v)
930  {
931  return isTypeID(v)? v.data.get<string>()
932  : Rec::TYPE_NIL;
933  }
934 
935  template<>
936  inline string
937  Rec::extractKey (GenNode const& v)
938  {
939  return isAttribute(v)? v.idi.getSym()
940  : "";
941  }
942 
943  template<>
944  inline GenNode const&
945  Rec::extractVal (GenNode const& v)
946  {
947  return v;
948  }
949 
950  template<>
951  inline string
952  Rec::renderAttribute (GenNode const& a)
953  {
954  return a.idi.getSym() +" = "+ string(a.data);
955  }
956 
957  template<>
958  template<typename X>
959  inline GenNode
960  Rec::buildAttribute (string const& key, X&& payload)
961  {
962  return GenNode{key, forward<X>(payload)};
963  }
964 
965 
966 
967 }// namespace lib::diff
968 
969 namespace variant {
970  using diff::Rec;
971 
976  template<typename TYPES>
977  struct CanBuildFrom<diff::MakeRec, Node<Rec, TYPES>>
978  : std::true_type
979  {
980  using Type = Rec;
981  };
982 
983 }} // namespace lib::variant
984 #endif /*LIB_DIFF_GEN_NODE_H*/
static const Ref I
symbolic ID ref "_I_"
Definition: gen-node.hpp:860
type erased baseclass for building a combined hash and symbolic ID.
Definition: entry-id.hpp:133
metafunction to detect types able to be wrapped into a GenNode.
Definition: gen-node.hpp:513
Constructor for a specially crafted &#39;ref GenNode&#39;.
Definition: gen-node.hpp:840
bool isNested() const
determine if payload constitutes a nested scope ("object")
Definition: gen-node.hpp:768
friend ChildDataIter childData(GenNode const &n)
visit the data of nested child elements
Definition: gen-node.hpp:387
GenNode(ID &&id, DataCap &&d)
Definition: gen-node.hpp:472
std::optional< X > retrieveAttribute(string key) const
peek into the attributes of a nested Record
Definition: gen-node.hpp:776
Rec::scopeIter childIter() const
visit children of a nested Record<GenNode>
Definition: gen-node.hpp:194
Typesafe union record.
Definition: variant.hpp:215
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:864
string renderCompact(Rec const &rec)
compact textual representation of a Record<GenNode> (»object«).
Definition: gen-node.cpp:290
Building block for monad-like depth-first expansion of a GenNode.
Definition: gen-node.hpp:595
iterator begin() const
default iteration exposes all data within this "object", starting with the attributes ...
Definition: record.hpp:309
Implementation namespace for support and library code.
Lumiera&#39;s internal time value datatype.
Definition: timevalue.hpp:299
Special collection to represent object-like data.
static const Ref END
symbolic ID ref "_END_"
Definition: gen-node.hpp:862
bool matchData(DataCap const &) const
Implementation of content equality test, delgating to content.
Definition: gen-node.cpp:78
allow for storage in ordered containers, ordering based on the human-readable ID within the GenNode...
Definition: gen-node.hpp:440
A typesafe union record to carry embedded values of unrelated type.
Another Lumiera Forward Iterator building block, based on incorporating a state type as »*State Core*...
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:754
wrapped record reference.
Definition: record.hpp:612
char Yes_t
helper types to detect the overload resolution chosen by the compiler
Definition: meta/util.hpp:95
Rec * maybeAccessNestedRec()
Definition: gen-node.hpp:740
std::optional< X > retrieveAttribute(string key) const
mismatch tolerant convenience shortcut to peek into the attributes of a nested Record ...
Definition: gen-node.hpp:800
static const Ref NO
symbolic ID ref "_NO_"
Definition: gen-node.hpp:861
void buildMutator(BufferHandle)
attachment point to receive and apply tree-diff changes.
Locator expand() const
Definition: gen-node.hpp:652
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:452
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:351
static const Ref ATTRIBS
symbolic ID ref "_ATTRIBS_"
Definition: gen-node.hpp:865
Offset measures a distance in time.
Definition: timevalue.hpp:358
string recordType() const
peek into the type field of a nested Record<GenNode>
Definition: gen-node.hpp:760
Duration is the internal Lumiera time metric.
Definition: timevalue.hpp:468
Ref(string const &symbolicID)
create an empty ID stand-in.
Definition: gen-node.hpp:847
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:573
Ref(GenNode &oNode)
build reference to a Record, using the original ID
Definition: gen-node.hpp:855
a family of time value like entities and their relationships.
object-like record of data.
Definition: record.hpp:141
static const Ref THIS
symbolic ID ref "_THIS_"
Definition: gen-node.hpp:863
basic constant internal time value.
Definition: timevalue.hpp:133
GenNode const & Access
using const reference data access relevant for handling large subtrees
Definition: gen-node.hpp:126
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:222