/* GEN-NODE.hpp - generic node element for tree like data representation Copyright (C) Lumiera.org 2015, Hermann Vosseler This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /** @file gen-node.hpp ** Generic building block for tree shaped (meta)data structures. ** A representation built from GenNode elements is intended to support ** (limited) introspection of data structures and exchange of mutations ** in the form of \link diff-language.hpp diff messages. \endlink ** ** Despite of the name, GenNode is \em not meant to be an universal ** data representation; rather it is limited to embody a fixed hard ** wired set of data types, able to stand-in for attributes ** and sub scope contents of the lumiera high-level data model. ** ** \par Anatomy of a GenNode ** ** GenNode is a polymorphic value with well defined identity and type. ** Each element is conceived to be »unique within context« -- as defined ** by the immediately visible scope within a tree like structure. ** Beyond this identity metadata, each GenNode carries a DataCap, which ** is an inline container and attachment point for payload data. Simple ** attribute values can be carried alongside, while more complex types ** or entities bound to a reference and registration system (e.g. Placement) ** will be referred by a suitable reference representation (PlacementID). ** The DataCap is what creates the polymorphic nature, where the common ** interface is mostly limited to managemental tasks (copying of values, ** external representation). ** ** To represent object-like structures and for building trees, a special ** kind of data type is placed into the DataCap. This type, Record ** is recursive and has the ability to hold both a a set of attributes ** addressable by-name and an (ordered) collection of elements treated ** as children within the scope of the given record. ** ** \par Requirements ** ** GenNode elements are to be used in the diff detection and implementation. ** This implies some requirements for the (opaque) elements used in diff: ** - they need to support the notion of equality ** - we need to derive a key type for usage in index tables ** - this implies the necessity to support std::less comparisons for tree-maps ** - and the necessity to support hash code generation for unordered (hash)maps ** - moreover, the elements need to be values, able to be copied and handled at will ** - it will be beneficial for these values to support move semantics explicitly ** - in addition, the tree diffing suggests a mechanism to re-gain the fully ** typed context, either based on some kind of embedded type tag, or ** alternatively by visitation and matching ** - finally, the handling of changes prompts us to support installation ** of a specifically typed change handling closure. ** ** \par monadic nature ** ** As suggested by the usage for representation of tree shaped data, we acknowledge ** that GenNode is a Monad. We support the basic operations \em construction ** and \em flatMap. To fit in with this generic processing pattern, the one element ** flavours of GenNode are considered the special case, while the collective flavours ** form the base case -- every GenNode can be iterated. The \em construction requirement ** suggests that GenNode may be created readily, just by wrapping any given and suitable ** element, thereby picking up the element's type. For sake of code organisation and ** dependency management, we solve this requirement with the help of a trait type, ** expecting the actual usage to supply the necessary specialisations on site. ** ** @todo the purpose and goal of the monadic approach is not clear yet (5/2015). ** To begin with, for the task of diff detection and application, it is sufficient ** to get the children as traversable collection ** ** @see diff-index-table-test.cpp ** @see diff-list-generation-test.cpp ** @see DiffDetector ** */ #ifndef LIB_DIFF_GEN_NODE_H #define LIB_DIFF_GEN_NODE_H #include "lib/hash-indexed.hpp" ///< @warning needs to be first, see explanation in lib/hash-standard.hpp #include "lib/error.hpp" #include "lib/variant.hpp" #include "lib/time/timevalue.hpp" #include "lib/diff/record.hpp" #include "lib/idi/entry-id.hpp" //#include "lib/util.hpp" //#include "lib/format-string.hpp" //#include "lib/format-util.hpp" #include "lib/variant.hpp" #include "lib/util.hpp" //#include #include //#include namespace lib { namespace diff{ namespace error = lumiera::error; using std::string; class GenNode; using Rec = Record; using DataValues = meta::Types; class DataCap : public Variant { public: template DataCap(X&& x) : Variant(std::forward(x)) { } ////////////////////////TICKET #963 Forwarding shadows copy operations -- generic solution?? DataCap(DataCap const&) =default; DataCap(DataCap&&) =default; DataCap(DataCap& o) : DataCap((DataCap const&)o) { } DataCap& operator= (DataCap const&) =default; DataCap& operator= (DataCap&&) =default; }; /** generic data element node within a tree */ struct GenNode { class ID : public idi::BareEntryID { friend class GenNode; template ID (X*, string const& symbolicID) : idi::BareEntryID (symbolicID, idi::getTypeHash()) { } public: ID (GenNode const& node) : ID(node.idi) { } // standard copy operations acceptable operator string() const { return "ID(\""+getSym()+"\")"; } }; //------GenNode Data fields--- ID idi; DataCap data; template GenNode(X&& val) : idi(&val, buildChildID()) , data(std::forward(val)) { } template GenNode(string const& symbolicID, X&& val) : idi(&val, symbolicID) , data(std::forward(val)) { } GenNode(string const& symbolicID, const char* text) : GenNode(symbolicID, string(text)) { } GenNode(const char* text) : GenNode(string(text)) { } ////////////////////////TICKET #963 Forwarding shadows copy operations -- generic solution?? GenNode(GenNode const&) =default; GenNode(GenNode&&) =default; GenNode(GenNode& o) : GenNode((GenNode const&)o) { } GenNode& operator= (GenNode const&) =default; GenNode& operator= (GenNode&&) =default; bool isNamed() const { return util::startsWith (idi.getSym(), "_CHILD_"); } friend string name (GenNode const& node) { return node.idi.getSym(); } friend bool operator== (GenNode const& n1, GenNode const& n2) { return n1.idi == n2.idi; } friend bool operator!= (GenNode const& n1, GenNode const& n2) { return n1.idi != n2.idi; } private: template static string buildChildID() { return "_CHILD_" + idi::generateSymbolicID(); } }; /* === Specialisation for handling of attributes in Record === */ template<> inline bool Rec::isAttribute (GenNode const& v) { return false; ////TODO } template<> inline bool Rec::isTypeID (GenNode const& v) { return false; ////TODO } template<> inline string Rec::extractTypeID (GenNode const& v) { return "todo"; ////TODO } template<> inline GenNode Rec::buildTypeAttribute (string const& typeID) { return GenNode("type", typeID); } template<> inline string Rec::extractKey (GenNode const& v) { return v.idi.getSym(); } template<> inline GenNode Rec::extractVal (GenNode const& v) { return GenNode(v); ///TODO } }} // namespace lib::diff #endif /*LIB_DIFF_GEN_NODE_H*/