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 
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<const GenNode, ScopeExplorer>
664  {
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:142
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: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:776
Rec::scopeIter childIter() const
visit children of a nested Record<GenNode>
Definition: gen-node.hpp:203
Typesafe union record.
Definition: variant.hpp:223
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
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:317
Implementation namespace for support and library code.
Lumiera&#39;s internal time value datatype.
Definition: timevalue.hpp:305
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:85
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:619
char Yes_t
helper types to detect the overload resolution chosen by the compiler
Definition: meta/util.hpp:103
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: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:865
Offset measures a distance in time.
Definition: timevalue.hpp:364
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:474
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:579
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:150
static const Ref THIS
symbolic ID ref "_THIS_"
Definition: gen-node.hpp:863
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