2015-03-21 02:00:55 +01:00
|
|
|
/*
|
|
|
|
|
GEN-NODE.hpp - generic node element for tree like data representation
|
|
|
|
|
|
|
|
|
|
Copyright (C) Lumiera.org
|
|
|
|
|
2015, Hermann Vosseler <Ichthyostega@web.de>
|
|
|
|
|
|
|
|
|
|
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.
|
2015-05-02 01:11:39 +02:00
|
|
|
** A representation built from GenNode elements is intended to support
|
2015-06-08 01:58:39 +02:00
|
|
|
** (limited) introspection of data structures and exchange of mutations
|
|
|
|
|
** in the form of \link diff-language.hpp diff messages. \endlink
|
2015-03-21 02:00:55 +01:00
|
|
|
**
|
|
|
|
|
** Despite of the name, GenNode is \em not meant to be an universal
|
|
|
|
|
** data representation; rather it is limited to embody a fixed hard
|
2015-06-08 01:58:39 +02:00
|
|
|
** wired set of data types, able to stand-in for attributes
|
2015-05-02 01:11:39 +02:00
|
|
|
** and sub scope contents of the lumiera high-level data model.
|
2015-03-21 02:00:55 +01:00
|
|
|
**
|
|
|
|
|
** \par Anatomy of a GenNode
|
|
|
|
|
**
|
2015-06-04 19:26:45 +02:00
|
|
|
** GenNode is a polymorphic value with well defined identity and type.
|
2015-03-21 02:00:55 +01:00
|
|
|
** 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,
|
2015-06-08 01:58:39 +02:00
|
|
|
** 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<GenNode>
|
|
|
|
|
** 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.
|
2015-03-21 02:00:55 +01:00
|
|
|
**
|
2015-03-21 19:23:41 +01:00
|
|
|
** \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
|
2015-05-02 01:11:39 +02:00
|
|
|
** - 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
|
2015-03-21 19:23:41 +01:00
|
|
|
** - in addition, the tree diffing suggests a mechanism to re-gain the fully
|
2015-06-04 19:26:45 +02:00
|
|
|
** typed context, either based on some kind of embedded type tag, or
|
|
|
|
|
** alternatively by visitation and matching
|
2015-03-21 19:23:41 +01:00
|
|
|
** - finally, the handling of changes prompts us to support installation
|
|
|
|
|
** of a specifically typed <i>change handling closure</i>.
|
|
|
|
|
**
|
|
|
|
|
** \par monadic nature
|
|
|
|
|
**
|
|
|
|
|
** As suggested by the usage for representation of tree shaped data, we acknowledge
|
|
|
|
|
** that GenNode is a <b>Monad</b>. 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.
|
|
|
|
|
**
|
2015-06-04 19:26:45 +02:00
|
|
|
** @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
|
|
|
|
|
**
|
2015-03-21 02:00:55 +01:00
|
|
|
** @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
|
|
|
|
|
|
|
|
|
|
|
2015-05-02 01:11:39 +02:00
|
|
|
#include "lib/hash-indexed.hpp" ///< @warning needs to be first, see explanation in lib/hash-standard.hpp
|
|
|
|
|
|
2015-03-21 02:00:55 +01:00
|
|
|
#include "lib/error.hpp"
|
2015-05-02 01:11:39 +02:00
|
|
|
#include "lib/variant.hpp"
|
|
|
|
|
#include "lib/time/timevalue.hpp"
|
|
|
|
|
#include "lib/diff/record.hpp"
|
2015-07-03 04:13:16 +02:00
|
|
|
#include "lib/idi/entry-id.hpp"
|
2015-03-21 02:00:55 +01:00
|
|
|
//#include "lib/util.hpp"
|
|
|
|
|
//#include "lib/format-string.hpp"
|
2015-07-03 19:18:49 +02:00
|
|
|
//#include "lib/format-util.hpp"
|
2015-05-02 01:11:39 +02:00
|
|
|
#include "lib/variant.hpp"
|
|
|
|
|
#include "lib/util.hpp"
|
|
|
|
|
|
2015-03-21 02:00:55 +01:00
|
|
|
//#include <vector>
|
2015-05-02 01:11:39 +02:00
|
|
|
#include <string>
|
2015-03-21 02:00:55 +01:00
|
|
|
//#include <map>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace lib {
|
|
|
|
|
namespace diff{
|
|
|
|
|
|
|
|
|
|
namespace error = lumiera::error;
|
|
|
|
|
|
2015-05-02 01:11:39 +02:00
|
|
|
using std::string;
|
|
|
|
|
|
2015-08-16 00:16:30 +02:00
|
|
|
struct GenNode;
|
2015-05-02 01:11:39 +02:00
|
|
|
|
2015-08-17 02:40:57 +02:00
|
|
|
/** Define actual data storage and access types used */
|
|
|
|
|
template<>
|
|
|
|
|
struct RecordSetup<GenNode>
|
|
|
|
|
{
|
|
|
|
|
using Storage = std::vector<GenNode>;
|
|
|
|
|
using ElmIter = typename Storage::const_iterator;
|
|
|
|
|
|
|
|
|
|
/** using const reference data access
|
|
|
|
|
* relevant for handling large subtrees */
|
|
|
|
|
using Access = GenNode const&;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-06-08 01:58:39 +02:00
|
|
|
using Rec = Record<GenNode>;
|
2015-07-04 20:50:18 +02:00
|
|
|
using RecRef = RecordRef<GenNode>;
|
2015-07-04 14:55:36 +02:00
|
|
|
using MakeRec = Rec::Mutator;
|
2015-05-02 01:11:39 +02:00
|
|
|
using DataValues = meta::Types<int
|
|
|
|
|
,int64_t
|
|
|
|
|
,short
|
|
|
|
|
,char
|
|
|
|
|
,bool
|
|
|
|
|
,double
|
|
|
|
|
,string
|
|
|
|
|
,time::Time
|
2015-06-08 01:58:39 +02:00
|
|
|
,time::Offset
|
2015-05-02 01:11:39 +02:00
|
|
|
,time::Duration
|
|
|
|
|
,time::TimeSpan
|
|
|
|
|
,hash::LuidH
|
2015-07-04 20:50:18 +02:00
|
|
|
,RecRef
|
2015-06-08 01:58:39 +02:00
|
|
|
,Rec
|
2015-05-02 01:11:39 +02:00
|
|
|
>;
|
|
|
|
|
|
2015-03-21 02:00:55 +01:00
|
|
|
|
2015-05-02 01:11:39 +02:00
|
|
|
|
|
|
|
|
class DataCap
|
|
|
|
|
: public Variant<DataValues>
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
template<typename X>
|
2015-07-03 18:16:54 +02:00
|
|
|
DataCap(X&& x)
|
2015-05-02 01:11:39 +02:00
|
|
|
: Variant<DataValues>(std::forward<X>(x))
|
|
|
|
|
{ }
|
2015-07-03 04:13:16 +02:00
|
|
|
|
2015-07-03 18:08:28 +02:00
|
|
|
////////////////////////TICKET #963 Forwarding shadows copy operations -- generic solution??
|
2015-07-03 18:16:54 +02:00
|
|
|
DataCap(DataCap const&) =default;
|
|
|
|
|
DataCap(DataCap&&) =default;
|
|
|
|
|
DataCap(DataCap& o)
|
|
|
|
|
: DataCap((DataCap const&)o)
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
DataCap& operator= (DataCap const&) =default;
|
|
|
|
|
DataCap& operator= (DataCap&&) =default;
|
2015-05-02 01:11:39 +02:00
|
|
|
};
|
2015-03-21 02:00:55 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/** generic data element node within a tree */
|
2015-07-03 04:13:16 +02:00
|
|
|
struct GenNode
|
2015-03-21 02:00:55 +01:00
|
|
|
{
|
2015-07-03 04:13:16 +02:00
|
|
|
class ID
|
|
|
|
|
: public idi::BareEntryID
|
|
|
|
|
{
|
2015-08-16 00:16:30 +02:00
|
|
|
friend struct GenNode;
|
2015-07-03 04:13:16 +02:00
|
|
|
|
|
|
|
|
template<typename X>
|
|
|
|
|
ID (X*, string const& symbolicID)
|
|
|
|
|
: idi::BareEntryID (symbolicID,
|
|
|
|
|
idi::getTypeHash<X>())
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
ID (GenNode const& node)
|
|
|
|
|
: ID(node.idi)
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
// standard copy operations acceptable
|
2015-07-03 19:18:49 +02:00
|
|
|
|
|
|
|
|
operator string() const
|
|
|
|
|
{
|
|
|
|
|
return "ID(\""+getSym()+"\")";
|
|
|
|
|
}
|
2015-07-03 04:13:16 +02:00
|
|
|
};
|
|
|
|
|
|
2015-07-03 18:21:46 +02:00
|
|
|
|
|
|
|
|
//------GenNode Data fields---
|
|
|
|
|
|
2015-07-03 04:13:16 +02:00
|
|
|
ID idi;
|
|
|
|
|
DataCap data;
|
|
|
|
|
|
2015-07-03 18:08:28 +02:00
|
|
|
|
2015-07-03 04:13:16 +02:00
|
|
|
template<typename X>
|
2015-07-03 18:16:54 +02:00
|
|
|
GenNode(X&& val)
|
2015-07-03 04:13:16 +02:00
|
|
|
: idi(&val, buildChildID<X>())
|
|
|
|
|
, data(std::forward<X>(val))
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
template<typename X>
|
|
|
|
|
GenNode(string const& symbolicID, X&& val)
|
|
|
|
|
: idi(&val, symbolicID)
|
|
|
|
|
, data(std::forward<X>(val))
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
GenNode(string const& symbolicID, const char* text)
|
|
|
|
|
: GenNode(symbolicID, string(text))
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
GenNode(const char* text)
|
|
|
|
|
: GenNode(string(text))
|
|
|
|
|
{ }
|
|
|
|
|
|
2015-07-03 18:16:54 +02:00
|
|
|
////////////////////////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;
|
|
|
|
|
|
2015-07-03 04:13:16 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
isNamed() const
|
|
|
|
|
{
|
|
|
|
|
return util::startsWith (idi.getSym(), "_CHILD_");
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-04 14:55:36 +02:00
|
|
|
bool
|
2015-07-05 03:17:39 +02:00
|
|
|
contains (GenNode const& elm) const
|
2015-07-04 14:55:36 +02:00
|
|
|
{
|
2015-07-05 03:17:39 +02:00
|
|
|
return contains (elm.idi);
|
2015-07-04 14:55:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
contains (ID const&) const
|
|
|
|
|
{
|
|
|
|
|
UNIMPLEMENTED("containment check by ID");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-07-03 04:13:16 +02:00
|
|
|
friend string
|
|
|
|
|
name (GenNode const& node)
|
|
|
|
|
{
|
|
|
|
|
return node.idi.getSym();
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-03 18:21:46 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-04 20:50:18 +02:00
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
/** @internal for dedicated builder subclasses */
|
|
|
|
|
GenNode (ID&& id, DataCap&& d)
|
|
|
|
|
: idi(std::move(id))
|
|
|
|
|
, data(std::move(d))
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
template<typename X>
|
|
|
|
|
static GenNode::ID
|
|
|
|
|
fabricateRefID (string const& symbolicID)
|
|
|
|
|
{
|
2015-07-08 04:12:10 +02:00
|
|
|
X* typeID(0);
|
2015-07-04 20:50:18 +02:00
|
|
|
return ID(typeID, symbolicID);
|
|
|
|
|
}
|
2015-07-03 18:21:46 +02:00
|
|
|
|
2015-07-03 04:13:16 +02:00
|
|
|
private:
|
|
|
|
|
template<typename X>
|
|
|
|
|
static string
|
|
|
|
|
buildChildID()
|
|
|
|
|
{
|
|
|
|
|
return "_CHILD_" + idi::generateSymbolicID<X>();
|
|
|
|
|
}
|
2015-03-21 02:00:55 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2015-07-04 20:50:18 +02:00
|
|
|
/**
|
|
|
|
|
* Constructor for a specially crafted 'ref GenNode'.
|
|
|
|
|
* The identity record of the generated object will be prepared
|
|
|
|
|
* such as to be identical to a regular GenNode with Record payload.
|
|
|
|
|
* @note slicing in usage is intentional
|
|
|
|
|
*/
|
|
|
|
|
struct Ref
|
|
|
|
|
: GenNode
|
|
|
|
|
{
|
|
|
|
|
/** create an empty ID stand-in.
|
|
|
|
|
* @note the purpose is to create a symbolic reference by name
|
|
|
|
|
*/
|
|
|
|
|
explicit
|
|
|
|
|
Ref(string const& symbolicID)
|
|
|
|
|
: GenNode(fabricateRefID<RecRef> (symbolicID)
|
|
|
|
|
, DataCap(RecRef())) // note: places NIL into the reference part
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
/** build reference to a Record, using the original ID
|
|
|
|
|
* @throw error::Logic when oNode does not hold a Record<GenNode>
|
|
|
|
|
*/
|
|
|
|
|
Ref(GenNode& oNode)
|
|
|
|
|
: GenNode(ID(oNode)
|
|
|
|
|
, DataCap(RecRef(oNode.data.get<Rec>())))
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
static Ref END; ///< symbolic ID ref "_END_"
|
|
|
|
|
static Ref THIS; ///< symbolic ID ref "_THIS_"
|
|
|
|
|
static Ref CHILD; ///< symbolic ID ref "_CHILD_"
|
|
|
|
|
static Ref ATTRIBS; ///< symbolic ID ref "_ATTRIBS_"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2015-03-21 02:00:55 +01:00
|
|
|
|
2015-07-04 03:39:53 +02:00
|
|
|
/* === Specialisation to add fluent GenNode builder API to Record<GenNode> === */
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
inline GenNode&&
|
2015-07-04 15:22:04 +02:00
|
|
|
MakeRec::genNode()
|
2015-07-04 03:39:53 +02:00
|
|
|
{
|
2015-07-04 15:22:04 +02:00
|
|
|
return std::move (GenNode(std::move(record_)));
|
2015-07-04 03:39:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
inline GenNode&&
|
2015-07-04 15:22:04 +02:00
|
|
|
MakeRec::genNode(string const& symbolicID)
|
2015-07-04 03:39:53 +02:00
|
|
|
{
|
2015-07-04 15:22:04 +02:00
|
|
|
return std::move (GenNode(symbolicID, std::move(record_)));
|
2015-07-04 03:39:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-06-06 02:40:18 +02:00
|
|
|
/* === Specialisation for handling of attributes in Record<GenNode> === */
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
inline bool
|
2015-06-08 01:58:39 +02:00
|
|
|
Rec::isAttribute (GenNode const& v)
|
2015-06-06 02:40:18 +02:00
|
|
|
{
|
|
|
|
|
return false; ////TODO
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
inline bool
|
2015-06-08 01:58:39 +02:00
|
|
|
Rec::isTypeID (GenNode const& v)
|
2015-06-06 02:40:18 +02:00
|
|
|
{
|
|
|
|
|
return false; ////TODO
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
inline string
|
2015-06-08 01:58:39 +02:00
|
|
|
Rec::extractTypeID (GenNode const& v)
|
2015-06-06 02:40:18 +02:00
|
|
|
{
|
|
|
|
|
return "todo"; ////TODO
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
inline string
|
2015-06-08 01:58:39 +02:00
|
|
|
Rec::extractKey (GenNode const& v)
|
2015-06-06 02:40:18 +02:00
|
|
|
{
|
2015-07-03 04:13:16 +02:00
|
|
|
return v.idi.getSym();
|
2015-06-06 02:40:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<>
|
2015-08-17 02:40:57 +02:00
|
|
|
inline GenNode const&
|
2015-06-08 01:58:39 +02:00
|
|
|
Rec::extractVal (GenNode const& v)
|
2015-06-06 02:40:18 +02:00
|
|
|
{
|
2015-07-03 04:13:16 +02:00
|
|
|
return GenNode(v); ///TODO
|
2015-06-06 02:40:18 +02:00
|
|
|
}
|
|
|
|
|
|
2015-07-05 03:17:39 +02:00
|
|
|
template<>
|
|
|
|
|
inline string
|
|
|
|
|
Rec::renderAttribute (GenNode const& a)
|
|
|
|
|
{
|
|
|
|
|
return "notyet = todo"; ////TODO
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-21 02:00:55 +01:00
|
|
|
|
|
|
|
|
}} // namespace lib::diff
|
|
|
|
|
#endif /*LIB_DIFF_GEN_NODE_H*/
|