Merge Platform upgrade and Diff-Framework development
This commit is contained in:
commit
24d7f55935
92 changed files with 3551 additions and 695 deletions
|
|
@ -155,6 +155,29 @@ would require a ``deep copy'' of any underlying data structures.
|
||||||
|
|
||||||
Ichthyostega:: 'Sa 07 Jan 2012 21:49:09 CET' ~<prg@ichthyostega.de>~
|
Ichthyostega:: 'Sa 07 Jan 2012 21:49:09 CET' ~<prg@ichthyostega.de>~
|
||||||
|
|
||||||
|
NOTE: Lumiera Forward Iterators can be made to work together with the
|
||||||
|
'range for loop', as introduced with C++11. The preferred solution
|
||||||
|
is to define the necessary free functions `begin` and `end` for ADL.
|
||||||
|
This is best done on a per implementation base. We consider a generic
|
||||||
|
solution not worth the effort
|
||||||
|
|
||||||
|
This is to say, these two concepts can be made to work together well. While,
|
||||||
|
at a conceptual level, they are not really compatible, and build on a
|
||||||
|
different understanding: The standard for-loop assumes ``a container'',
|
||||||
|
while our Forward Iterator Concept deals with ``abstract data sources''.
|
||||||
|
The user needs to understand the fine points of that conceptual difference:
|
||||||
|
|
||||||
|
- if you apply the range-`for` construct on a container, you can iterate
|
||||||
|
as often as you like. Even if the iterators of that container are
|
||||||
|
implemented in compliance with the Lumiera Forward Iterator concept.
|
||||||
|
- but if you apply the range-`for` construct on _a given iterator_,
|
||||||
|
you can do so only once. There is no way to reset that iterator,
|
||||||
|
other than obtaining a new one.
|
||||||
|
|
||||||
|
See `71167be9c9aaa` for the typical bridge implementation
|
||||||
|
|
||||||
|
Ichthyostega:: 'Sa 04 Jul 2015 22:57:51 CEST' ~<prg@ichthyostega.de>~
|
||||||
|
|
||||||
|
|
||||||
//endof_comments:
|
//endof_comments:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,6 @@ namespace lumiera{
|
||||||
namespace query {
|
namespace query {
|
||||||
|
|
||||||
|
|
||||||
using lib::P;
|
|
||||||
using lumiera::Query;
|
using lumiera::Query;
|
||||||
using boost::scoped_ptr;
|
using boost::scoped_ptr;
|
||||||
|
|
||||||
|
|
@ -73,14 +72,14 @@ namespace query {
|
||||||
* is considered \e misconfiguration.
|
* is considered \e misconfiguration.
|
||||||
*/
|
*/
|
||||||
template<class TAR>
|
template<class TAR>
|
||||||
P<TAR> operator() (Query<TAR> const&);
|
lib::P<TAR> operator() (Query<TAR> const&);
|
||||||
|
|
||||||
|
|
||||||
/** search through the registered defaults, never create anything.
|
/** search through the registered defaults, never create anything.
|
||||||
* @return object fulfilling the query, \c empty ptr if not found.
|
* @return object fulfilling the query, \c empty ptr if not found.
|
||||||
*/
|
*/
|
||||||
template<class TAR>
|
template<class TAR>
|
||||||
P<TAR> search (Query<TAR> const&);
|
lib::P<TAR> search (Query<TAR> const&);
|
||||||
|
|
||||||
/** retrieve an object fulfilling the query and register it as default.
|
/** retrieve an object fulfilling the query and register it as default.
|
||||||
* The resolution is delegated to the ConfigQuery system (which may cause
|
* The resolution is delegated to the ConfigQuery system (which may cause
|
||||||
|
|
@ -88,7 +87,7 @@ namespace query {
|
||||||
* @return object fulfilling the query, \c empty ptr if no solution.
|
* @return object fulfilling the query, \c empty ptr if no solution.
|
||||||
*/
|
*/
|
||||||
template<class TAR>
|
template<class TAR>
|
||||||
P<TAR> create (Query<TAR> const&);
|
lib::P<TAR> create (Query<TAR> const&);
|
||||||
|
|
||||||
/** register the given object as default, after ensuring it fulfils the
|
/** register the given object as default, after ensuring it fulfils the
|
||||||
* query. The latter may cause some properties of the object to be set,
|
* query. The latter may cause some properties of the object to be set,
|
||||||
|
|
@ -97,13 +96,13 @@ namespace query {
|
||||||
* @note only a weak ref to the object is stored
|
* @note only a weak ref to the object is stored
|
||||||
*/
|
*/
|
||||||
template<class TAR>
|
template<class TAR>
|
||||||
bool define (P<TAR> const&, Query<TAR> const& =Query<TAR>());
|
bool define (lib::P<TAR> const&, Query<TAR> const& =Query<TAR>());
|
||||||
|
|
||||||
/** remove the defaults registration of the given object, if there was such
|
/** remove the defaults registration of the given object, if there was such
|
||||||
* @return false if nothing has been changed because the object wasn't registered
|
* @return false if nothing has been changed because the object wasn't registered
|
||||||
*/
|
*/
|
||||||
template<class TAR>
|
template<class TAR>
|
||||||
bool forget (P<TAR> const&);
|
bool forget (lib::P<TAR> const&);
|
||||||
|
|
||||||
|
|
||||||
/** @internal for session lifecycle */
|
/** @internal for session lifecycle */
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
/** @file timeline-widget.hpp
|
/** @file timeline-widget.hpp
|
||||||
** This file defines the core component of the Lumiera GUI
|
** This file defines the core component of the Lumiera GUI
|
||||||
**
|
**
|
||||||
|
** @deprecated broken since transition to GTK-3
|
||||||
** @todo needs to be reworked from ground as if 5/2015
|
** @todo needs to be reworked from ground as if 5/2015
|
||||||
** GTK-3 uses different event handling callbacks,
|
** GTK-3 uses different event handling callbacks,
|
||||||
** so the existing implementation is defunct.
|
** so the existing implementation is defunct.
|
||||||
|
|
@ -67,6 +68,7 @@ namespace widget {
|
||||||
* Core timeline display (custom widget).
|
* Core timeline display (custom widget).
|
||||||
* @remarks This widget is a composite of several widgets contained
|
* @remarks This widget is a composite of several widgets contained
|
||||||
* within the timeline namespace.
|
* within the timeline namespace.
|
||||||
|
* @deprecated dysfunctional and broken by switch to GTK-3. Needs to be rewritten
|
||||||
*/
|
*/
|
||||||
class TimelineWidget
|
class TimelineWidget
|
||||||
: public Gtk::Table
|
: public Gtk::Table
|
||||||
|
|
|
||||||
|
|
@ -125,6 +125,7 @@ protected:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The event handler for when the TimelineWidget's state is switched.
|
* The event handler for when the TimelineWidget's state is switched.
|
||||||
|
* @deprecated needs to be rewritten from scratch for GTK-3
|
||||||
*/
|
*/
|
||||||
void on_state_changed (shared_ptr<TimelineState> newState);
|
void on_state_changed (shared_ptr<TimelineState> newState);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -121,13 +121,13 @@ namespace lumiera {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
typedef lib::IterSource<proc::mobject::ModelPort>::iterator ModelPorts;
|
using ModelPorts = lib::IterSource<proc::mobject::ModelPort>::iterator;
|
||||||
typedef lib::IterSource<proc::mobject::OutputDesignation>::iterator Pipes;
|
using Pipes = lib::IterSource<proc::mobject::OutputDesignation>::iterator;
|
||||||
typedef proc::play::POutputManager Output;
|
using Output = proc::play::POutputManager;
|
||||||
typedef proc::mobject::session::PClipMO Clip;
|
using Clip = proc::mobject::session::PClip;
|
||||||
typedef proc::mobject::PFork Fork;
|
using Fork = proc::mobject::PFork;
|
||||||
typedef proc::asset::PTimeline Timeline;
|
using Timeline = proc::asset::PTimeline;
|
||||||
typedef proc::asset::PViewer Viewer;
|
using Viewer = proc::asset::PViewer;
|
||||||
|
|
||||||
|
|
||||||
/* ==== convenience shortcuts for common use cases ==== */
|
/* ==== convenience shortcuts for common use cases ==== */
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ namespace diff{
|
||||||
using Handler = HandlerFun<Interpreter,Val>;
|
using Handler = HandlerFun<Interpreter,Val>;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class I, typename E>
|
template<class I, typename E> ///< alternatively derive value and interpreter from a Handler binding
|
||||||
struct InterpreterScheme<HandlerFun<I,E>>
|
struct InterpreterScheme<HandlerFun<I,E>>
|
||||||
{
|
{
|
||||||
using Val = E;
|
using Val = E;
|
||||||
|
|
@ -266,10 +266,10 @@ namespace diff{
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* generic builder to apply a list diff to a given target sequence.
|
* generic builder to apply a diff description to a given target data structure.
|
||||||
* The usage pattern is as follows
|
* The usage pattern is as follows
|
||||||
* #. construct a DiffApplicator instance, wrapping the target sequence
|
* #. construct a DiffApplicator instance, wrapping the target data
|
||||||
* #. feed the list diff (sequence of diff verbs) to the #consume function
|
* #. feed the diff (sequence of diff verbs) to the #consume function
|
||||||
* #. the wrapped target sequence has been altered, to conform to the given diff
|
* #. the wrapped target sequence has been altered, to conform to the given diff
|
||||||
* @note a suitable DiffApplicationStrategy will be picked, based on the type
|
* @note a suitable DiffApplicationStrategy will be picked, based on the type
|
||||||
* of the concrete target sequence given at construction. (Effectively
|
* of the concrete target sequence given at construction. (Effectively
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
|
|
||||||
#include "lib/error.hpp"
|
#include "lib/error.hpp"
|
||||||
#include "lib/diff/diff-language.hpp"
|
#include "lib/diff/diff-language.hpp"
|
||||||
|
#include "lib/diff/gen-node.hpp"
|
||||||
|
|
||||||
|
|
||||||
namespace lib {
|
namespace lib {
|
||||||
|
|
@ -40,5 +41,14 @@ namespace diff{
|
||||||
|
|
||||||
LUMIERA_ERROR_DEFINE(DIFF_CONFLICT, "Collision in diff application: contents of target not as expected.");
|
LUMIERA_ERROR_DEFINE(DIFF_CONFLICT, "Collision in diff application: contents of target not as expected.");
|
||||||
|
|
||||||
|
/* symbolic marker ID references
|
||||||
|
* used the tree diff language
|
||||||
|
* to mark specific scopes
|
||||||
|
*/
|
||||||
|
Ref Ref::END ("_END_");
|
||||||
|
Ref Ref::THIS ("_THIS_");
|
||||||
|
Ref Ref::CHILD ("_CHILD_");
|
||||||
|
Ref Ref::ATTRIBS("_ATTRIBS_");
|
||||||
|
|
||||||
|
|
||||||
}} // namespace lib::diff
|
}} // namespace lib::diff
|
||||||
|
|
|
||||||
|
|
@ -24,17 +24,17 @@
|
||||||
/** @file gen-node.hpp
|
/** @file gen-node.hpp
|
||||||
** Generic building block for tree shaped (meta)data structures.
|
** Generic building block for tree shaped (meta)data structures.
|
||||||
** A representation built from GenNode elements is intended to support
|
** A representation built from GenNode elements is intended to support
|
||||||
** introspection of data structures and exchange of mutations in the
|
** (limited) introspection of data structures and exchange of mutations
|
||||||
** form of \link diff-language.hpp diff messages. \endlink
|
** in the form of \link diff-language.hpp diff messages. \endlink
|
||||||
**
|
**
|
||||||
** Despite of the name, GenNode is \em not meant to be an universal
|
** Despite of the name, GenNode is \em not meant to be an universal
|
||||||
** data representation; rather it is limited to embody a fixed hard
|
** data representation; rather it is limited to embody a fixed hard
|
||||||
** wired set of data elements, able to stand-in for attributes
|
** wired set of data types, able to stand-in for attributes
|
||||||
** and sub scope contents of the lumiera high-level data model.
|
** and sub scope contents of the lumiera high-level data model.
|
||||||
**
|
**
|
||||||
** \par Anatomy of a GenNode
|
** \par Anatomy of a GenNode
|
||||||
**
|
**
|
||||||
** GenNode is a polymorphic value with well defined identity and type-ID.
|
** GenNode is a polymorphic value with well defined identity and type.
|
||||||
** Each element is conceived to be »unique within context« -- as defined
|
** Each element is conceived to be »unique within context« -- as defined
|
||||||
** by the immediately visible scope within a tree like structure.
|
** by the immediately visible scope within a tree like structure.
|
||||||
** Beyond this identity metadata, each GenNode carries a DataCap, which
|
** Beyond this identity metadata, each GenNode carries a DataCap, which
|
||||||
|
|
@ -44,13 +44,13 @@
|
||||||
** will be referred by a suitable reference representation (PlacementID).
|
** will be referred by a suitable reference representation (PlacementID).
|
||||||
** The DataCap is what creates the polymorphic nature, where the common
|
** The DataCap is what creates the polymorphic nature, where the common
|
||||||
** interface is mostly limited to managemental tasks (copying of values,
|
** interface is mostly limited to managemental tasks (copying of values,
|
||||||
** external representation). Besides, there is are special flavours of
|
** external representation).
|
||||||
** the DataCap to represent \em sub-collections of GenNode elements.
|
**
|
||||||
** Especially, the \ref Record type is a kind of collection suitable
|
** To represent object-like structures and for building trees, a special
|
||||||
** to represent object-like structures, since it both holds several
|
** kind of data type is placed into the DataCap. This type, Record<GenNode>
|
||||||
** \am attributes referable by-name, and a (ordered) collection
|
** is recursive and has the ability to hold both a a set of attributes
|
||||||
** of elements treated as children within the scope of the
|
** addressable by-name and an (ordered) collection of elements treated
|
||||||
** given record.
|
** as children within the scope of the given record.
|
||||||
**
|
**
|
||||||
** \par Requirements
|
** \par Requirements
|
||||||
**
|
**
|
||||||
|
|
@ -63,7 +63,8 @@
|
||||||
** - moreover, the elements need to be values, able to be copied and handled at will
|
** - 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
|
** - 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
|
** - in addition, the tree diffing suggests a mechanism to re-gain the fully
|
||||||
** typed context, based on some kind of embedded type tag
|
** 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
|
** - finally, the handling of changes prompts us to support installation
|
||||||
** of a specifically typed <i>change handling closure</i>.
|
** of a specifically typed <i>change handling closure</i>.
|
||||||
**
|
**
|
||||||
|
|
@ -79,6 +80,10 @@
|
||||||
** dependency management, we solve this requirement with the help of a trait type,
|
** dependency management, we solve this requirement with the help of a trait type,
|
||||||
** expecting the actual usage to supply the necessary specialisations on site.
|
** 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-index-table-test.cpp
|
||||||
** @see diff-list-generation-test.cpp
|
** @see diff-list-generation-test.cpp
|
||||||
** @see DiffDetector
|
** @see DiffDetector
|
||||||
|
|
@ -96,10 +101,10 @@
|
||||||
#include "lib/variant.hpp"
|
#include "lib/variant.hpp"
|
||||||
#include "lib/time/timevalue.hpp"
|
#include "lib/time/timevalue.hpp"
|
||||||
#include "lib/diff/record.hpp"
|
#include "lib/diff/record.hpp"
|
||||||
|
#include "lib/idi/entry-id.hpp"
|
||||||
//#include "lib/util.hpp"
|
//#include "lib/util.hpp"
|
||||||
//#include "lib/format-string.hpp"
|
//#include "lib/format-string.hpp"
|
||||||
|
//#include "lib/format-util.hpp"
|
||||||
#include "lib/format-util.hpp"
|
|
||||||
#include "lib/variant.hpp"
|
#include "lib/variant.hpp"
|
||||||
#include "lib/util.hpp"
|
#include "lib/util.hpp"
|
||||||
|
|
||||||
|
|
@ -115,8 +120,11 @@ namespace diff{
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
|
|
||||||
class GenNode;
|
struct GenNode;
|
||||||
|
|
||||||
|
using Rec = Record<GenNode>;
|
||||||
|
using RecRef = RecordRef<GenNode>;
|
||||||
|
using MakeRec = Rec::Mutator;
|
||||||
using DataValues = meta::Types<int
|
using DataValues = meta::Types<int
|
||||||
,int64_t
|
,int64_t
|
||||||
,short
|
,short
|
||||||
|
|
@ -125,10 +133,12 @@ namespace diff{
|
||||||
,double
|
,double
|
||||||
,string
|
,string
|
||||||
,time::Time
|
,time::Time
|
||||||
|
,time::Offset
|
||||||
,time::Duration
|
,time::Duration
|
||||||
,time::TimeSpan
|
,time::TimeSpan
|
||||||
,hash::LuidH
|
,hash::LuidH
|
||||||
,Record<GenNode>
|
,RecRef
|
||||||
|
,Rec
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -141,17 +151,250 @@ namespace diff{
|
||||||
DataCap(X&& x)
|
DataCap(X&& x)
|
||||||
: Variant<DataValues>(std::forward<X>(x))
|
: Variant<DataValues>(std::forward<X>(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 */
|
/** generic data element node within a tree */
|
||||||
class GenNode
|
struct GenNode
|
||||||
{
|
{
|
||||||
public:
|
class ID
|
||||||
|
: public idi::BareEntryID
|
||||||
|
{
|
||||||
|
friend struct GenNode;
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
operator string() const
|
||||||
|
{
|
||||||
|
return "ID(\""+getSym()+"\")";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//------GenNode Data fields---
|
||||||
|
|
||||||
|
ID idi;
|
||||||
|
DataCap data;
|
||||||
|
|
||||||
|
|
||||||
|
template<typename X>
|
||||||
|
GenNode(X&& val)
|
||||||
|
: 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))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
////////////////////////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_");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
contains (GenNode const& elm) const
|
||||||
|
{
|
||||||
|
return contains (elm.idi);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
contains (ID const&) const
|
||||||
|
{
|
||||||
|
UNIMPLEMENTED("containment check by ID");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
X* typeID(0);
|
||||||
|
return ID(typeID, symbolicID);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<typename X>
|
||||||
|
static string
|
||||||
|
buildChildID()
|
||||||
|
{
|
||||||
|
return "_CHILD_" + idi::generateSymbolicID<X>();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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_"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* === Specialisation to add fluent GenNode builder API to Record<GenNode> === */
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline GenNode&&
|
||||||
|
MakeRec::genNode()
|
||||||
|
{
|
||||||
|
return std::move (GenNode(std::move(record_)));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline GenNode&&
|
||||||
|
MakeRec::genNode(string const& symbolicID)
|
||||||
|
{
|
||||||
|
return std::move (GenNode(symbolicID, std::move(record_)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* === Specialisation for handling of attributes in Record<GenNode> === */
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline string
|
||||||
|
Rec::renderAttribute (GenNode const& a)
|
||||||
|
{
|
||||||
|
return "notyet = todo"; ////TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}} // namespace lib::diff
|
}} // namespace lib::diff
|
||||||
#endif /*LIB_DIFF_GEN_NODE_H*/
|
#endif /*LIB_DIFF_GEN_NODE_H*/
|
||||||
|
|
|
||||||
|
|
@ -32,9 +32,50 @@
|
||||||
** which in turn serve as the standard handle to refer to other elements, entities,
|
** which in turn serve as the standard handle to refer to other elements, entities,
|
||||||
** attributes or references within the "backbone" of the Lumiera GUI.
|
** attributes or references within the "backbone" of the Lumiera GUI.
|
||||||
**
|
**
|
||||||
** @see diff-index-table-test.cpp
|
** \par design decisions
|
||||||
** @see diff-list-generation-test.cpp
|
** The Record type is shaped from its intended use: It serves to symbolically represent
|
||||||
** @see DiffDetector
|
** \em objects in the "external tree description". Here, \em objects means objects for
|
||||||
|
** real, i.e. with types, fields and an enclosed scope. But \em external means that we
|
||||||
|
** do not work on these objects right here, we only represent them, for later referral,
|
||||||
|
** \em symbolically.
|
||||||
|
**
|
||||||
|
** This leads to the following decisions
|
||||||
|
** - the Record entity is itself an object and thus has an inner side, privately.
|
||||||
|
** The entrails of the Record can be reworked and tuned for performance
|
||||||
|
** - yet the Record has an external appearance, which makes it look flat and passive.
|
||||||
|
** This is to say, a Record has no visible functionality.
|
||||||
|
** - the parts or \em realms within this symbolic representation are distinguished
|
||||||
|
** by convention solely
|
||||||
|
**
|
||||||
|
** * metadata is very limited and boils down to magic attributes known by name
|
||||||
|
** * children (scope contents) can be recognised by \em not bearing a name
|
||||||
|
**
|
||||||
|
** Record entities are meant to be immutable. The proper way to alter a Record is
|
||||||
|
** to apply a \link tree-diff.hpp diff \endlink
|
||||||
|
**
|
||||||
|
** \par rationale
|
||||||
|
** The underlying theme of this design is negative, dialectical: we do not want to
|
||||||
|
** build yet another object system. The object model of C++ is deemed adequate.
|
||||||
|
**
|
||||||
|
** @remarks
|
||||||
|
** - the implementation is focused on the intended primary use case,
|
||||||
|
** which is to exchange diff messages drawn against a symbolic representation
|
||||||
|
** of a typed object tree. Especially, we assume that there is only a small
|
||||||
|
** number of attributes (so linear search for access by key is adequate).
|
||||||
|
** - moreover, we assume that the value type allows to somehow to embed
|
||||||
|
** the key of each attribute; the implementation needs an explicit
|
||||||
|
** specialisation of the binding functions for each value type.
|
||||||
|
** - this header defines a specialisation for VAL = std::string --
|
||||||
|
** while the most relevant specialisation for GenNode is provided
|
||||||
|
** alongside with this special, monadic value type.
|
||||||
|
** - an alternative implementation approach would have been to use a
|
||||||
|
** dedicated helper type to represent the collection of attributes.
|
||||||
|
** This type might then be specialised, e.g. to utilise an index table
|
||||||
|
** for key-value lookup. However, in the light of the intended usage
|
||||||
|
** of Record entities as tree nodes within a GenNode monad, such a
|
||||||
|
** more elaborate approach was deemed unnecessary for the time being.
|
||||||
|
**
|
||||||
|
** @see GenericRecordRepresentation_test
|
||||||
**
|
**
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -44,11 +85,19 @@
|
||||||
|
|
||||||
|
|
||||||
#include "lib/error.hpp"
|
#include "lib/error.hpp"
|
||||||
//#include "lib/util.hpp"
|
#include "lib/iter-adapter.hpp"
|
||||||
//#include "lib/format-string.hpp"
|
#include "lib/iter-adapter-stl.hpp"
|
||||||
|
#include "lib/itertools.hpp"
|
||||||
|
#include "lib/util.hpp"
|
||||||
|
|
||||||
|
//#include "lib/format-string.hpp"
|
||||||
|
#include <boost/noncopyable.hpp>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
//#include <vector>
|
|
||||||
//#include <map>
|
|
||||||
|
|
||||||
|
|
||||||
namespace lib {
|
namespace lib {
|
||||||
|
|
@ -57,19 +106,521 @@ namespace diff{
|
||||||
namespace error = lumiera::error;
|
namespace error = lumiera::error;
|
||||||
|
|
||||||
//using util::_Fmt;
|
//using util::_Fmt;
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** object-like record of data */
|
/**
|
||||||
|
* object-like record of data.
|
||||||
|
* For symbolic representation of "objects".
|
||||||
|
* A Record holds both \em attributes (key-value data)
|
||||||
|
* plus a list of \em enclosed children, which are conceived
|
||||||
|
* to be within the "scope" of this Record. Optionally, a \em typeID
|
||||||
|
* (metadata) may be defined. Otherwise, this typeID defaults to \c "NIL".
|
||||||
|
* The representation of attributes depends on the actual value type, which
|
||||||
|
* somehow need the ability to encode the keys within the value data.
|
||||||
|
* By default, a specialisation is given for string, using the \c "key = val"
|
||||||
|
* syntax. Yet the most relevant use case is \c Record<GenNode> -- using the
|
||||||
|
* embedded name-ID of the GenNode elements as key for attributes.
|
||||||
|
*
|
||||||
|
* Record elements are meant to be immutable; they can be created from a
|
||||||
|
* defining collection. However, we provide a #Mutator mechanism to allow
|
||||||
|
* for rebuilding and mutating symbolic data structures based on Records
|
||||||
|
* and GenNode. Essentially, Lumiera's diff framework relies on this.
|
||||||
|
*/
|
||||||
template<typename VAL>
|
template<typename VAL>
|
||||||
class Record
|
class Record
|
||||||
{
|
{
|
||||||
|
using _Vec = std::vector<VAL>;
|
||||||
|
using Attribs = _Vec;
|
||||||
|
using Children = _Vec;
|
||||||
|
using ElmIter = typename _Vec::const_iterator;
|
||||||
|
|
||||||
|
string type_;
|
||||||
|
Attribs attribs_;
|
||||||
|
Children children_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
Record()
|
||||||
|
: type_("NIL")
|
||||||
|
{ }
|
||||||
|
|
||||||
|
template<typename A, typename C>
|
||||||
|
Record(Symbol typeID, A&& att, C&& chi)
|
||||||
|
: type_(typeID)
|
||||||
|
, attribs_(std::forward<A> (att))
|
||||||
|
, children_(std::forward<C> (chi))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
template<typename A, typename C>
|
||||||
|
Record(Symbol typeID, std::initializer_list<A> const&& att
|
||||||
|
, std::initializer_list<C> const&& chi)
|
||||||
|
: type_(typeID)
|
||||||
|
, attribs_(att)
|
||||||
|
, children_(chi)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
template<typename SEQ>
|
||||||
|
explicit
|
||||||
|
Record (SEQ const& con)
|
||||||
|
: type_("NIL")
|
||||||
|
{
|
||||||
|
auto p = std::begin(con);
|
||||||
|
auto e = std::end(con);
|
||||||
|
if (p!=e && isTypeID (*p))
|
||||||
|
type_ = extractTypeID(*(p++));
|
||||||
|
for ( ; p!=e && isAttribute(*p); ++p)
|
||||||
|
attribs_.push_back (*p);
|
||||||
|
for ( ; p!=e; ++p)
|
||||||
|
children_.push_back (*p);
|
||||||
|
}
|
||||||
|
|
||||||
|
Record (std::initializer_list<VAL> const&& ili)
|
||||||
|
: Record(ili)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
// all default copy operations acceptable
|
||||||
|
|
||||||
|
|
||||||
|
/** for diagnostic purpose: include format-util.hpp */
|
||||||
|
operator std::string() const;
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
empty() const
|
||||||
|
{
|
||||||
|
return attribs_.empty()
|
||||||
|
&& children_.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
string
|
||||||
|
getType() const
|
||||||
|
{
|
||||||
|
return type_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
hasAttribute (string key) const
|
||||||
|
{
|
||||||
|
return attribs_.end() != findKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
contains (VAL const& val) const
|
||||||
|
{
|
||||||
|
return util::contains (children_, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
VAL const&
|
||||||
|
get (string key) const
|
||||||
|
{
|
||||||
|
ElmIter found = findKey (key);
|
||||||
|
if (attribs_.end() == found)
|
||||||
|
throw error::Invalid ("Record has no attribute \""+key+"\"");
|
||||||
|
else
|
||||||
|
return *found;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* While otherwise immutable,
|
||||||
|
* a Record object can be remoulded
|
||||||
|
* with the help of a Mutator object
|
||||||
|
* @remarks a Mutator basically wraps a \em copy
|
||||||
|
* of the original object. After performing
|
||||||
|
* the desired changes, the altered copy can either
|
||||||
|
* be sliced out (by conversion), or moved overwriting
|
||||||
|
* an existing other Record instance (implemented as swap)
|
||||||
|
*/
|
||||||
|
class Mutator;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* copy-initialise (or convert) from the given Mutator instance.
|
||||||
|
* @remarks need to code this explicitly, otherwise Record's
|
||||||
|
* build-from sequence templated ctor would kick in.
|
||||||
|
*/
|
||||||
|
Record (Mutator const& mut)
|
||||||
|
: Record((Record const&) mut)
|
||||||
|
{ }
|
||||||
|
Record (Mutator && mut)
|
||||||
|
: Record(std::move ((Record) mut))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
friend class Mutator;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ==== Exposing scope and contents for iteration ====== */
|
||||||
|
|
||||||
|
using iterator = IterAdapter<typename _Vec::const_iterator, const Record*>;
|
||||||
|
using scopeIter = typename iter_stl::_SeqT<const _Vec>::Range;
|
||||||
|
using keyIter = TransformIter<scopeIter, string>;
|
||||||
|
using valIter = TransformIter<scopeIter, VAL>;
|
||||||
|
|
||||||
|
/** default iteration exposes all data within this "object", starting with the attributes */
|
||||||
|
iterator begin () const { return iterator(this, attribs_.begin()); }
|
||||||
|
iterator end () const { return iterator(); }
|
||||||
|
|
||||||
|
scopeIter attribs() const { return iter_stl::eachElm(attribs_); }
|
||||||
|
scopeIter scope() const { return iter_stl::eachElm(children_); }
|
||||||
|
|
||||||
|
keyIter keys() const { return transformIterator(attribs(), extractKey); }
|
||||||
|
valIter vals() const { return transformIterator(attribs(), extractVal); }
|
||||||
|
|
||||||
|
protected: /* ==== API for the IterAdapter ==== */
|
||||||
|
|
||||||
|
/** Implementation of Iteration-logic: pull next element. */
|
||||||
|
template<class ITER>
|
||||||
|
friend void
|
||||||
|
iterNext (const Record* src, ITER& pos)
|
||||||
|
{
|
||||||
|
++pos;
|
||||||
|
checkPoint (src,pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Implementation of Iteration-logic: detect iteration end.
|
||||||
|
* @remarks seamless continuation of the iteration when reaching
|
||||||
|
* the end of the attribute collection. In this implementation,
|
||||||
|
* we use the default constructed \c ITER() to mark iteration end.
|
||||||
|
*/
|
||||||
|
template<class ITER>
|
||||||
|
friend bool
|
||||||
|
checkPoint (const Record* src, ITER& pos)
|
||||||
|
{
|
||||||
|
REQUIRE (src);
|
||||||
|
if ((pos != ITER()) && (pos == src->attribs_.end()) && !src->children_.empty())
|
||||||
|
{
|
||||||
|
pos = src->children_.begin();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (pos != ITER() && (pos != src->children_.end()))
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pos = ITER();
|
||||||
|
return false;
|
||||||
|
} }
|
||||||
|
|
||||||
|
private:
|
||||||
|
/* === abstract attribute handling : needs specialisation === */
|
||||||
|
static bool isAttribute (VAL const& v);
|
||||||
|
static bool isTypeID (VAL const& v);
|
||||||
|
static string extractTypeID (VAL const& v);
|
||||||
|
static VAL buildTypeAttribute (string const& typeID);
|
||||||
|
static string renderAttribute (VAL const& a);
|
||||||
|
static string extractKey (VAL const& v);
|
||||||
|
static VAL extractVal (VAL const& v);
|
||||||
|
|
||||||
|
|
||||||
|
ElmIter
|
||||||
|
findKey (string key) const
|
||||||
|
{
|
||||||
|
return std::find_if (attribs_.begin()
|
||||||
|
,attribs_.end()
|
||||||
|
,[=](VAL const& elm)
|
||||||
|
{
|
||||||
|
return key == extractKey(elm);
|
||||||
|
});
|
||||||
|
} ///////////////////TODO this lambda triggers a GCC-4.7.2 Bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56402
|
||||||
|
|
||||||
|
|
||||||
|
friend bool
|
||||||
|
operator== (Record const& r1, Record const& r2)
|
||||||
|
{
|
||||||
|
return r1.type_ == r2.type_
|
||||||
|
&& r1.attribs_ == r2.attribs_
|
||||||
|
&& r1.children_ == r2.children_;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool
|
||||||
|
operator!= (Record const& r1, Record const& r2)
|
||||||
|
{
|
||||||
|
return ! (r1 == r2);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template<typename VAL>
|
||||||
|
class Record<VAL>::Mutator
|
||||||
|
: boost::noncopyable
|
||||||
|
{
|
||||||
|
using Rec = Record<VAL>;
|
||||||
|
|
||||||
|
Rec record_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Mutator()
|
||||||
|
: record_()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
explicit
|
||||||
|
Mutator (Rec const& startingPoint)
|
||||||
|
: record_(startingPoint)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
explicit
|
||||||
|
Mutator (Rec && startingPoint)
|
||||||
|
: record_(std::move (startingPoint))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
operator Rec&()
|
||||||
|
{
|
||||||
|
return record_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
replace (Rec& existingInstance) noexcept
|
||||||
|
{
|
||||||
|
std::swap (existingInstance, record_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
empty() const
|
||||||
|
{
|
||||||
|
return record_.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* === functions to alter contents === */
|
||||||
|
|
||||||
|
void
|
||||||
|
setType (string const& newTypeID)
|
||||||
|
{
|
||||||
|
set ("type", Rec::buildTypeAttribute (newTypeID));
|
||||||
|
record_.type_ = newTypeID;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mutator&
|
||||||
|
type (string const& typeID)
|
||||||
|
{
|
||||||
|
setType (typeID);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mutator&
|
||||||
|
set (string const& key, VAL const& newValue)
|
||||||
|
{
|
||||||
|
///////////TODO;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mutator&
|
||||||
|
appendChild (VAL const& newChild)
|
||||||
|
{
|
||||||
|
record_.children_.push_back (newChild);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mutator&
|
||||||
|
prependChild (VAL const& newChild)
|
||||||
|
{
|
||||||
|
record_.children_.insert (record_.children_.begin(), newChild);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* === extension point for building specific value types === */
|
||||||
|
/*
|
||||||
|
* the following builder functions are to be specialised
|
||||||
|
* to create a Record holding specific value types,
|
||||||
|
* especially for building a tree like structure
|
||||||
|
* with GenNode holding a Record<GenNode>
|
||||||
|
*/
|
||||||
|
|
||||||
|
VAL&& genNode();
|
||||||
|
VAL&& genNode(string const& symbolicID);
|
||||||
|
|
||||||
|
template<typename X, typename...ARGS>
|
||||||
|
Mutator& attrib (string const& key, X const& initialiser, ARGS&& ...args)
|
||||||
|
{
|
||||||
|
set (key, VAL(initialiser));
|
||||||
|
return attrib (std::forward<ARGS>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename X>
|
||||||
|
Mutator&
|
||||||
|
attrib (string const& key, X const& initialiser)
|
||||||
|
{
|
||||||
|
set (key, VAL(initialiser));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename X, typename...ARGS>
|
||||||
|
Mutator& scope (X const& initialiser, ARGS&& ...args)
|
||||||
|
{
|
||||||
|
appendChild (VAL(initialiser));
|
||||||
|
return scope (std::forward<ARGS>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename X>
|
||||||
|
Mutator& scope (X const& initialiser)
|
||||||
|
{
|
||||||
|
appendChild (VAL(initialiser));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wrapped record reference.
|
||||||
|
* A helper for lib::GenNode and the diff representation.
|
||||||
|
* RecordRef is copyable and assignable, but like a reference
|
||||||
|
* can not be rebound. It can be used to refer to a subtree
|
||||||
|
* within the diff representation, without the need to copy.
|
||||||
|
* @remarks this is almost identical to std::ref, with the
|
||||||
|
* notable difference that it can be default-created
|
||||||
|
* into "bottom" state; this also implies to have
|
||||||
|
* a NULL check on dereferentiation.
|
||||||
|
*/
|
||||||
|
template<typename VAL>
|
||||||
|
class RecordRef
|
||||||
|
{
|
||||||
|
using Target = Record<VAL>;
|
||||||
|
|
||||||
|
Target* record_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** by default create an
|
||||||
|
* invalid ("bottom") reference */
|
||||||
|
RecordRef() noexcept
|
||||||
|
: record_(nullptr)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/** create a reference bound to
|
||||||
|
* the given target; can not be rebound */
|
||||||
|
RecordRef(Target& o) noexcept
|
||||||
|
: record_(&o)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/** prevent moving into black hole */
|
||||||
|
RecordRef(Target&&) = delete;
|
||||||
|
|
||||||
|
// standard copy operations acceptable
|
||||||
|
|
||||||
|
|
||||||
|
explicit
|
||||||
|
operator bool() const
|
||||||
|
{
|
||||||
|
return empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
empty() const
|
||||||
|
{
|
||||||
|
return bool(record_);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** target is accessed by cast
|
||||||
|
* @throws error::Logic on bottom reference
|
||||||
|
*/
|
||||||
|
operator Target&() const
|
||||||
|
{
|
||||||
|
if (!record_)
|
||||||
|
throw error::Logic("attempt to dereference an unbound record reference"
|
||||||
|
,error::LUMIERA_ERROR_BOTTOM_VALUE);
|
||||||
|
return *record_;
|
||||||
|
}
|
||||||
|
|
||||||
|
Target*
|
||||||
|
get() const noexcept
|
||||||
|
{
|
||||||
|
return record_;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* === Specialisations to define the handling of attributes === */
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline string
|
||||||
|
Record<string>::extractKey (string const& v)
|
||||||
|
{
|
||||||
|
size_t pos = v.find('=');
|
||||||
|
if (string::npos == pos)
|
||||||
|
return "";
|
||||||
|
else
|
||||||
|
return v.substr(0,pos); //////////////////////////////TODO should trim here
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline string
|
||||||
|
Record<string>::extractVal (string const& v)
|
||||||
|
{
|
||||||
|
size_t pos = v.find('=');
|
||||||
|
if (string::npos == pos)
|
||||||
|
return v;
|
||||||
|
else
|
||||||
|
return v.substr(pos+1, v.length() - pos); ////////////TODO should trim here
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline bool
|
||||||
|
Record<string>::isAttribute (string const& v)
|
||||||
|
{
|
||||||
|
return string::npos != v.find('=');
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline bool
|
||||||
|
Record<string>::isTypeID (string const& v)
|
||||||
|
{
|
||||||
|
return isAttribute(v)
|
||||||
|
&& "type" == extractKey(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline string
|
||||||
|
Record<string>::extractTypeID (string const& v)
|
||||||
|
{
|
||||||
|
return "todo"; //////////////////////////////////////////TODO do we really need this function?
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline string
|
||||||
|
Record<string>::buildTypeAttribute (string const& typeID)
|
||||||
|
{
|
||||||
|
return "type = "+typeID;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline string
|
||||||
|
Record<string>::renderAttribute (string const& attrib)
|
||||||
|
{
|
||||||
|
return extractKey(attrib) + " = " + extractVal(attrib);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* === Diagnostics === */
|
||||||
|
|
||||||
|
template<typename VAL>
|
||||||
|
Record<VAL>::operator std::string() const
|
||||||
|
{
|
||||||
|
#ifndef LIB_FORMAT_UTIL_H
|
||||||
|
return "Record(...)";
|
||||||
|
#else
|
||||||
|
using util::join;
|
||||||
|
using lib::transformIterator;
|
||||||
|
|
||||||
|
return "Rec("
|
||||||
|
+ join (transformIterator (this->attribs(), renderAttribute))
|
||||||
|
+ "|{"
|
||||||
|
+ join (this->scope())
|
||||||
|
+ "})"
|
||||||
|
;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}} // namespace lib::diff
|
}} // namespace lib::diff
|
||||||
#endif /*LIB_DIFF_GEN_NODE_H*/
|
#endif /*LIB_DIFF_GEN_NODE_H*/
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ namespace diff{
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
template<class PAR>
|
template<class PAR>
|
||||||
class Builder;
|
struct Builder;
|
||||||
|
|
||||||
using ID = Literal;
|
using ID = Literal;
|
||||||
using Attribute = DataCap;
|
using Attribute = DataCap;
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,7 @@
|
||||||
namespace std { // forward declaration to avoid including <iostream>
|
namespace std { // forward declaration to avoid including <iostream>
|
||||||
|
|
||||||
template<typename C>
|
template<typename C>
|
||||||
class char_traits;
|
struct char_traits;
|
||||||
|
|
||||||
template<typename C, class _TRAITS>
|
template<typename C, class _TRAITS>
|
||||||
class basic_ostream;
|
class basic_ostream;
|
||||||
|
|
|
||||||
|
|
@ -38,10 +38,12 @@
|
||||||
#define LIB_FORMAT_UTIL_H
|
#define LIB_FORMAT_UTIL_H
|
||||||
|
|
||||||
#include "lib/meta/trait.hpp"
|
#include "lib/meta/trait.hpp"
|
||||||
|
#include "lib/itertools.hpp"
|
||||||
#include "lib/symbol.hpp"
|
#include "lib/symbol.hpp"
|
||||||
#include "lib/util.hpp"
|
#include "lib/util.hpp"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
|
|
@ -59,6 +61,7 @@ namespace util {
|
||||||
using boost::enable_if;
|
using boost::enable_if;
|
||||||
using lib::meta::can_ToString;
|
using lib::meta::can_ToString;
|
||||||
using lib::meta::can_lexical2string;
|
using lib::meta::can_lexical2string;
|
||||||
|
using lib::meta::can_IterForEach;
|
||||||
using lib::Symbol;
|
using lib::Symbol;
|
||||||
using util::isnil;
|
using util::isnil;
|
||||||
using std::string;
|
using std::string;
|
||||||
|
|
@ -143,5 +146,67 @@ namespace util {
|
||||||
: tyStr(val);
|
: tyStr(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace { // helper to build range iterator on demand
|
||||||
|
template<class CON, typename TOGGLE = void>
|
||||||
|
struct _RangeIter
|
||||||
|
{
|
||||||
|
using StlIter = typename CON::const_iterator;
|
||||||
|
|
||||||
|
lib::RangeIter<StlIter> iter;
|
||||||
|
|
||||||
|
_RangeIter(CON const& collection)
|
||||||
|
: iter(begin(collection), end(collection))
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class IT>
|
||||||
|
struct _RangeIter<IT, typename enable_if< can_IterForEach<IT> >::type>
|
||||||
|
{
|
||||||
|
IT iter;
|
||||||
|
|
||||||
|
_RangeIter(IT&& srcIter)
|
||||||
|
: iter(std::forward<IT>(srcIter))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enumerate a collection's contents, separated by delimiter.
|
||||||
|
* @param coll something that is standard-iterable
|
||||||
|
* @return all contents converted to string and joined into
|
||||||
|
* a single string, with separators interspersed.
|
||||||
|
* @remarks based on the \c boost::join library function,
|
||||||
|
* which in turn is based on
|
||||||
|
* additionally, we use our
|
||||||
|
* \link #str failsafe string conversion \endlink
|
||||||
|
* which in turn invokes custom string conversion,
|
||||||
|
* or lexical_cast as appropriate.
|
||||||
|
*/
|
||||||
|
template<class CON>
|
||||||
|
inline string
|
||||||
|
join (CON&& coll, string const& delim =", ")
|
||||||
|
{
|
||||||
|
using Coll = typename lib::meta::Strip<CON>::Type;
|
||||||
|
using Val = typename Coll::value_type;
|
||||||
|
|
||||||
|
std::function<string(Val const&)> toString = [] (Val const& val) { return str(val); };
|
||||||
|
|
||||||
|
_RangeIter<Coll> range(std::forward<Coll>(coll));
|
||||||
|
auto strings = lib::transformIterator(range.iter, toString);
|
||||||
|
|
||||||
|
if (!strings) return "";
|
||||||
|
|
||||||
|
std::ostringstream buffer;
|
||||||
|
for (string const& elm : strings)
|
||||||
|
buffer << elm << delim;
|
||||||
|
|
||||||
|
// chop off last delimiter
|
||||||
|
size_t len = buffer.str().length();
|
||||||
|
ASSERT (len > delim.length());
|
||||||
|
return buffer.str().substr(0, len - delim.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace util
|
} // namespace util
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -39,13 +39,13 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef ASSET_ENTRY_ID_H
|
#ifndef LIB_IDI_ENTRY_ID_H
|
||||||
#define ASSET_ENTRY_ID_H
|
#define LIB_IDI_ENTRY_ID_H
|
||||||
|
|
||||||
|
|
||||||
#include "proc/asset.hpp"
|
#include "lib/error.hpp"
|
||||||
#include "proc/asset/struct-scheme.hpp"
|
|
||||||
#include "lib/hash-indexed.hpp"
|
#include "lib/hash-indexed.hpp"
|
||||||
|
#include "lib/idi/genfunc.hpp"
|
||||||
#include "lib/util.hpp"
|
#include "lib/util.hpp"
|
||||||
|
|
||||||
#include <boost/functional/hash.hpp>
|
#include <boost/functional/hash.hpp>
|
||||||
|
|
@ -54,18 +54,36 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
namespace proc {
|
namespace lib {
|
||||||
namespace asset {
|
|
||||||
|
/**
|
||||||
|
* Identification Schemes.
|
||||||
|
* Collection of commonly used mechanisms to build identification records,
|
||||||
|
* unique identifiers, registration numbers and hashes. These are used as glue
|
||||||
|
* and thin abstraction to link various subsystems or to allow interoperation
|
||||||
|
* of registration facilities
|
||||||
|
*/
|
||||||
|
namespace idi {
|
||||||
|
|
||||||
|
namespace error = lumiera::error;
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::ostream;
|
using std::ostream;
|
||||||
|
|
||||||
|
using lib::idi::generateSymbolicID;
|
||||||
|
using lib::idi::getTypeHash;
|
||||||
|
using lib::idi::typeSymbol;
|
||||||
|
using lib::hash::LuidH;
|
||||||
|
using lib::HashVal;
|
||||||
|
|
||||||
|
namespace {
|
||||||
namespace idi {
|
/** lousy old tinkerer's trick:
|
||||||
|
* hash values with poor distribution can be improved
|
||||||
using lib::hash::LuidH;
|
* by spreading the input with something close to the golden ratio.
|
||||||
using lib::HashVal;
|
* Additionally, the scaling factor (for hashing) should be prime.
|
||||||
|
* 2^32 * (√5-1)/2 = 2654435769.49723
|
||||||
|
*/
|
||||||
|
const size_t KNUTH_MAGIC = 2654435761;
|
||||||
|
|
||||||
|
|
||||||
/** build up a hash value, packaged as LUID.
|
/** build up a hash value, packaged as LUID.
|
||||||
|
|
@ -82,16 +100,22 @@ namespace asset {
|
||||||
* conjunction with LUID. How to create a LuidH instance, if not generating
|
* conjunction with LUID. How to create a LuidH instance, if not generating
|
||||||
* a new random value. How to make EntryID and asset::Ident interchangeable, /////////TICKET #739
|
* a new random value. How to make EntryID and asset::Ident interchangeable, /////////TICKET #739
|
||||||
* which would require both to yield the same hash values....
|
* which would require both to yield the same hash values....
|
||||||
* @warning there is a weakness in boost::hash for strings of running numbers, causing
|
* @warning there is a weakness in boost::hash for strings of running numbers,
|
||||||
* collisions already for a small set with less than 100000 entries.
|
* causing collisions already for a small set with less than 100000 entries.
|
||||||
* To ameliorate the problem, we hash the symbol twice /////////TICKET #865
|
* To ameliorate the problem, we hash in the trailing digits, and
|
||||||
|
* spread them by the #KNUTH_MAGIC /////////TICKET #865
|
||||||
* @warning this code isn't portable and breaks if sizeof(size_t) < sizeof(void*)
|
* @warning this code isn't portable and breaks if sizeof(size_t) < sizeof(void*)
|
||||||
|
* @see HashGenerator_test#verify_Knuth_workaround
|
||||||
*/
|
*/
|
||||||
inline LuidH
|
inline LuidH
|
||||||
buildHash (string const& sym, HashVal seed =0)
|
buildHash (string const& sym, HashVal seed =0)
|
||||||
{
|
{
|
||||||
|
size_t l = sym.length();
|
||||||
|
if (l > 1) boost::hash_combine(seed, KNUTH_MAGIC * sym[l-1]);
|
||||||
|
if (l > 2) boost::hash_combine(seed, KNUTH_MAGIC * sym[l-2]);
|
||||||
|
if (l > 3) boost::hash_combine(seed, KNUTH_MAGIC * sym[l-3]); ////////////////////////TICKET #865
|
||||||
|
|
||||||
boost::hash_combine(seed, sym);
|
boost::hash_combine(seed, sym);
|
||||||
boost::hash_combine(seed, sym); ////////////////////////TICKET #865
|
|
||||||
lumiera_uid tmpLUID;
|
lumiera_uid tmpLUID;
|
||||||
lumiera_uid_set_ptr (&tmpLUID, reinterpret_cast<void*> (seed));
|
lumiera_uid_set_ptr (&tmpLUID, reinterpret_cast<void*> (seed));
|
||||||
return reinterpret_cast<LuidH&> (tmpLUID);
|
return reinterpret_cast<LuidH&> (tmpLUID);
|
||||||
|
|
@ -111,7 +135,6 @@ namespace asset {
|
||||||
class BareEntryID
|
class BareEntryID
|
||||||
: public boost::equality_comparable<BareEntryID>
|
: public boost::equality_comparable<BareEntryID>
|
||||||
{
|
{
|
||||||
typedef lib::hash::LuidH LuidH;
|
|
||||||
|
|
||||||
string symbol_;
|
string symbol_;
|
||||||
LuidH hash_;
|
LuidH hash_;
|
||||||
|
|
@ -123,9 +146,9 @@ namespace asset {
|
||||||
* encoded into a hash seed. Thus even the same symbolicID
|
* encoded into a hash seed. Thus even the same symbolicID
|
||||||
* generates differing hash-IDs for different type parameters
|
* generates differing hash-IDs for different type parameters
|
||||||
*/
|
*/
|
||||||
BareEntryID (string const& symbolID, idi::HashVal seed =0)
|
BareEntryID (string const& symbolID, HashVal seed =0)
|
||||||
: symbol_(util::sanitise(symbolID))
|
: symbol_(symbolID)
|
||||||
, hash_(idi::buildHash (symbol_, seed))
|
, hash_(buildHash (symbol_, seed))
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -160,7 +183,7 @@ namespace asset {
|
||||||
|
|
||||||
|
|
||||||
template<typename TAR>
|
template<typename TAR>
|
||||||
EntryID<TAR> recast() const;
|
EntryID<TAR> const& recast() const;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -193,7 +216,7 @@ namespace asset {
|
||||||
|
|
||||||
/** case-1: auto generated symbolic ID */
|
/** case-1: auto generated symbolic ID */
|
||||||
EntryID()
|
EntryID()
|
||||||
: BareEntryID (idi::generateSymbolID<TY>(), getTypeHash())
|
: BareEntryID (generateSymbolicID<TY>(), getTypeHash<TY>())
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
/** case-2: explicitly specify a symbolic ID to use.
|
/** case-2: explicitly specify a symbolic ID to use.
|
||||||
|
|
@ -202,31 +225,10 @@ namespace asset {
|
||||||
*/
|
*/
|
||||||
explicit
|
explicit
|
||||||
EntryID (string const& symbolID)
|
EntryID (string const& symbolID)
|
||||||
: BareEntryID (symbolID, getTypeHash())
|
: BareEntryID (util::sanitise(symbolID), getTypeHash<TY>())
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
|
||||||
/** generate an Asset identification tuple
|
|
||||||
* based on this EntryID's symbolic ID and type information.
|
|
||||||
* The remaining fields are filled in with hardwired defaults.
|
|
||||||
* @note there is a twist, as this asset identity tuple generates
|
|
||||||
* a different hash as the EntryID. It would be desirable
|
|
||||||
* to make those two addressing systems interchangeable. /////////////TICKET #739
|
|
||||||
*/
|
|
||||||
Asset::Ident
|
|
||||||
getIdent() const
|
|
||||||
{
|
|
||||||
Category cat (STRUCT, idi::StructTraits<TY>::catFolder());
|
|
||||||
return Asset::Ident (this->getSym(), cat);
|
|
||||||
}
|
|
||||||
|
|
||||||
static idi::HashVal
|
|
||||||
getTypeHash()
|
|
||||||
{
|
|
||||||
return hash_value (Category (STRUCT, idi::StructTraits<TY>::catFolder()));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** @return true if the upcast would yield exactly the same
|
/** @return true if the upcast would yield exactly the same
|
||||||
* tuple (symbol,type) as was used on original definition
|
* tuple (symbol,type) as was used on original definition
|
||||||
* of an ID, based on the given BareEntryID. Implemented
|
* of an ID, based on the given BareEntryID. Implemented
|
||||||
|
|
@ -235,23 +237,23 @@ namespace asset {
|
||||||
static bool
|
static bool
|
||||||
canRecast (BareEntryID const& bID)
|
canRecast (BareEntryID const& bID)
|
||||||
{
|
{
|
||||||
return bID.getHash() == idi::buildHash (bID.getSym(), getTypeHash());
|
return bID.getHash() == buildHash (bID.getSym(), getTypeHash<TY>());
|
||||||
}
|
}
|
||||||
|
|
||||||
static EntryID
|
static EntryID const&
|
||||||
recast (BareEntryID const& bID)
|
recast (BareEntryID const& bID)
|
||||||
{
|
{
|
||||||
if (!canRecast(bID))
|
if (!canRecast(bID))
|
||||||
throw error::Logic ("unable to recast EntryID: desired type "
|
throw error::Logic ("unable to recast EntryID: desired type "
|
||||||
"doesn't match original definition"
|
"doesn't match original definition"
|
||||||
, error::LUMIERA_ERROR_WRONG_TYPE);
|
, error::LUMIERA_ERROR_WRONG_TYPE);
|
||||||
return EntryID (bID.getSym());
|
return static_cast<EntryID const&> (bID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
operator string () const
|
operator string () const
|
||||||
{
|
{
|
||||||
return "ID<"+idi::StructTraits<TY>::idSymbol()+">-"+EntryID::getSym();
|
return "ID<"+typeSymbol<TY>()+">-"+EntryID::getSym();
|
||||||
}
|
}
|
||||||
|
|
||||||
friend ostream& operator<< (ostream& os, EntryID const& id) { return os << string(id); }
|
friend ostream& operator<< (ostream& os, EntryID const& id) { return os << string(id); }
|
||||||
|
|
@ -280,12 +282,13 @@ namespace asset {
|
||||||
* Exception if it doesn't match the stored hash.
|
* Exception if it doesn't match the stored hash.
|
||||||
*/
|
*/
|
||||||
template<typename TAR>
|
template<typename TAR>
|
||||||
EntryID<TAR> BareEntryID::recast() const
|
EntryID<TAR> const&
|
||||||
|
BareEntryID::recast() const
|
||||||
{
|
{
|
||||||
return EntryID<TAR>::recast(*this);
|
return EntryID<TAR>::recast(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}} // namespace proc::asset
|
}} // namespace lib::idi
|
||||||
#endif
|
#endif /*LIB_IDI_ENTRY_ID_H*/
|
||||||
76
src/lib/idi/genfunc.cpp
Normal file
76
src/lib/idi/genfunc.cpp
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
GenFunc - generic identification functions (raw)
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
* *****************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#include "lib/idi/genfunc.hpp"
|
||||||
|
#include "lib/format-string.hpp"
|
||||||
|
#include "lib/util.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <boost/functional/hash.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
using util::_Fmt;
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
|
||||||
|
namespace lib {
|
||||||
|
namespace test{ // see test-helper.cpp
|
||||||
|
std::string demangleCxx (lib::Literal rawName);
|
||||||
|
}
|
||||||
|
namespace idi {
|
||||||
|
|
||||||
|
|
||||||
|
namespace format { // generic entry points / integration helpers...
|
||||||
|
|
||||||
|
using lib::test::demangleCxx;
|
||||||
|
|
||||||
|
string
|
||||||
|
demangled_innermost_component (const char* rawName)
|
||||||
|
{
|
||||||
|
string typeStr = demangleCxx (rawName);
|
||||||
|
size_t pos = typeStr.rfind("::");
|
||||||
|
if (pos != string::npos)
|
||||||
|
typeStr = typeStr.substr(pos+2);
|
||||||
|
return typeStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
string
|
||||||
|
demangled_sanitised_name (const char* rawName)
|
||||||
|
{
|
||||||
|
return util::sanitise (test::demangleCxx (rawName));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
string
|
||||||
|
instance_formatter (string const& prefix, long instanceNr)
|
||||||
|
{
|
||||||
|
return _Fmt("%s.%03d")
|
||||||
|
% prefix % instanceNr;
|
||||||
|
}
|
||||||
|
|
||||||
|
} //(End)integration helpers...
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}} // namespace lib::test
|
||||||
139
src/lib/idi/genfunc.hpp
Normal file
139
src/lib/idi/genfunc.hpp
Normal file
|
|
@ -0,0 +1,139 @@
|
||||||
|
/*
|
||||||
|
GENFUNC.hpp - generic identification functions
|
||||||
|
|
||||||
|
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 genfunc.hpp
|
||||||
|
** Generic function to build identification schemes.
|
||||||
|
** These template functions are meant as common extension point.
|
||||||
|
** The purpose is to streamline and disentangle the various identification schemes
|
||||||
|
** in use at various places within Lumiera. We strive to cover all the common basic
|
||||||
|
** usage situations through these functions
|
||||||
|
** - build a symbolic ID
|
||||||
|
** - build a classification record
|
||||||
|
** - create a readable yet unique ID
|
||||||
|
** - render an ID in human readable form
|
||||||
|
** - derive a hash function
|
||||||
|
**
|
||||||
|
** @see EntryID
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef LIB_IDI_GENFUNC_H
|
||||||
|
#define LIB_IDI_GENFUNC_H
|
||||||
|
|
||||||
|
#include "lib/hash-value.h"
|
||||||
|
#include "lib/symbol.hpp"
|
||||||
|
#include "lib/typed-counter.hpp"
|
||||||
|
//#include "lib/hash-standard.hpp"
|
||||||
|
|
||||||
|
#include <typeinfo>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
namespace lib {
|
||||||
|
namespace idi {
|
||||||
|
|
||||||
|
using lib::HashVal;
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
namespace format { // integration helpers...
|
||||||
|
string demangled_innermost_component (const char* rawName);
|
||||||
|
string demangled_sanitised_name (const char* rawName);
|
||||||
|
|
||||||
|
string instance_formatter (string const& prefix, long instanceNr);
|
||||||
|
|
||||||
|
} //(End)integration helpers...
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Short readable type identifier, not necessarily unique or complete.
|
||||||
|
* @return the innermost component of the demangled C++ type name.
|
||||||
|
* Usually, this is the bare name without any namespaces.
|
||||||
|
*/
|
||||||
|
template<typename TY>
|
||||||
|
inline string
|
||||||
|
typeSymbol()
|
||||||
|
{
|
||||||
|
return format::demangled_innermost_component (typeid(TY).name());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Complete unique type identifier
|
||||||
|
* @return complete demangled C++ type name, additionally
|
||||||
|
* passed through our ID sanitiser function, i.e.
|
||||||
|
* one word, no whitespace, only minimal punctuation
|
||||||
|
*/
|
||||||
|
template<typename TY>
|
||||||
|
inline string
|
||||||
|
typeFullID()
|
||||||
|
{
|
||||||
|
return format::demangled_sanitised_name (typeid(TY).name());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TY>
|
||||||
|
inline string
|
||||||
|
categoryFolder()
|
||||||
|
{
|
||||||
|
return typeSymbol<TY>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TY>
|
||||||
|
inline string
|
||||||
|
namePrefix()
|
||||||
|
{
|
||||||
|
return typeSymbol<TY>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** build a per-type unique identifier.
|
||||||
|
* @return a type based prefix, followed by an instance number
|
||||||
|
* @note we use the short prefix without namespace, not necessarily unique
|
||||||
|
* @todo consequently the generated IDs might clash for two distinct types,
|
||||||
|
* which generate the same \c namePrefix(). Is this a problem?
|
||||||
|
* @warning this operation is not exactly cheap; it acquires a lock
|
||||||
|
* for the counter and, after increasing and dropping the lock,
|
||||||
|
* it builds and uses a boost::format instance.
|
||||||
|
*/
|
||||||
|
template<class TY>
|
||||||
|
inline string
|
||||||
|
generateSymbolicID()
|
||||||
|
{
|
||||||
|
static TypedCounter instanceCounter;
|
||||||
|
return format::instance_formatter (namePrefix<TY>(), instanceCounter.inc<TY>());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return a boost hash value, based on the full (mangled) C++ type name
|
||||||
|
*/
|
||||||
|
template<typename TY>
|
||||||
|
inline HashVal
|
||||||
|
getTypeHash()
|
||||||
|
{
|
||||||
|
Literal rawTypeName (typeid(TY).name());
|
||||||
|
return hash_value (rawTypeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}} // namespace lib::idi
|
||||||
|
#endif /*LIB_IDI_GENFUNC_H*/
|
||||||
334
src/lib/iter-adapter-ptr-deref.hpp
Normal file
334
src/lib/iter-adapter-ptr-deref.hpp
Normal file
|
|
@ -0,0 +1,334 @@
|
||||||
|
/*
|
||||||
|
ITER-ADAPTER-PTR-DEREF.hpp - wrapping iterator to dereference pointers automatically
|
||||||
|
|
||||||
|
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 iter-adapter-ptr-deref.hpp
|
||||||
|
** Extension adapter for Lumiera Forward Iterators to dereference
|
||||||
|
** any pointer values automatically. Sometimes, the iteration of some
|
||||||
|
** container naturally just yields pointers to contained values. But,
|
||||||
|
** from a viewpoint of interface design, we'd prefer the iterator to
|
||||||
|
** expose direct references (NULL values can be excluded). This helper
|
||||||
|
** template does precisely this: it wraps up any other entity conforming
|
||||||
|
** to the »Lumiera Forward Iterator« concept and, on access, automatically
|
||||||
|
** dereferences the exposed pointer.
|
||||||
|
**
|
||||||
|
** In addition, the reversed operation is also supported through another
|
||||||
|
** helper template: to take the address of any value exposed by the given
|
||||||
|
** underlying iterator
|
||||||
|
**
|
||||||
|
** @see iter-adapter-test.cpp
|
||||||
|
** @see iter-adapter.hpp basic iterator adapters
|
||||||
|
** @see itertools.hpp
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef LIB_ITER_ADAPTER_PTR_DEREF_H
|
||||||
|
#define LIB_ITER_ADAPTER_PTR_DEREF_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "lib/iter-adapter.hpp"
|
||||||
|
|
||||||
|
#include <boost/type_traits/remove_const.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace lib {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
/** helper to remove pointer,
|
||||||
|
* while retaining const */
|
||||||
|
template<typename T>
|
||||||
|
struct RemovePtr { typedef T Type; };
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct RemovePtr<T*> { typedef T Type; };
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct RemovePtr<const T*> { typedef const T Type; };
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct RemovePtr<T* const> { typedef const T Type; };
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct RemovePtr<const T* const> { typedef const T Type; };
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wrapper for an existing Iterator type,
|
||||||
|
* automatically dereferencing the output of the former.
|
||||||
|
* For this to work, the "source" iterator is expected
|
||||||
|
* to be declared on \em pointers rather than on values.
|
||||||
|
* @note bool checkable if and only if source is...
|
||||||
|
*/
|
||||||
|
template<class IT>
|
||||||
|
class PtrDerefIter
|
||||||
|
: public lib::BoolCheckable<PtrDerefIter<IT> >
|
||||||
|
{
|
||||||
|
IT i_; ///< nested source iterator
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef typename IT::value_type pointer;
|
||||||
|
typedef typename RemovePtr<pointer>::Type value_type;
|
||||||
|
typedef value_type& reference;
|
||||||
|
|
||||||
|
// for use with STL algorithms
|
||||||
|
typedef void difference_type;
|
||||||
|
typedef std::forward_iterator_tag iterator_category;
|
||||||
|
|
||||||
|
|
||||||
|
// the purpose of the following typedefs is to ease building a correct "const iterator"
|
||||||
|
|
||||||
|
typedef typename boost::remove_const<value_type>::type ValueTypeBase; // value_type without const
|
||||||
|
|
||||||
|
typedef typename IterType<IT>::template SimilarIter< ValueTypeBase* * >::Type WrappedIterType;
|
||||||
|
typedef typename IterType<IT>::template SimilarIter<const ValueTypeBase* * >::Type WrappedConstIterType;
|
||||||
|
|
||||||
|
typedef PtrDerefIter<WrappedIterType> IterType;
|
||||||
|
typedef PtrDerefIter<WrappedConstIterType> ConstIterType;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** PtrDerefIter is always created
|
||||||
|
* by wrapping an existing iterator.
|
||||||
|
*/
|
||||||
|
explicit
|
||||||
|
PtrDerefIter (IT srcIter)
|
||||||
|
: i_(srcIter)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
|
||||||
|
/** allow copy initialisation also when
|
||||||
|
* the wrapped iterator is based on some variation of a pointer.
|
||||||
|
* Especially, this includes initialisation of the "const variant"
|
||||||
|
* from the "normal variant" of PtrDerefIter. Actually, we need to convert
|
||||||
|
* in this case by brute force, because indeed (const TY *)* is not assignable
|
||||||
|
* from (TY *)* -- just we know that our intention is to dereference both levels
|
||||||
|
* of pointers, and then the resulting conversion is correct.
|
||||||
|
* @note in case IT == WrappedIterType, this is just a redefinition of the
|
||||||
|
* default copy ctor. In all other cases, this is an <i>additional
|
||||||
|
* ctor besides the default copy ctor</i> */
|
||||||
|
PtrDerefIter (PtrDerefIter<WrappedIterType> const& oIter)
|
||||||
|
: i_(reinterpret_cast<IT const&> (oIter.getBase()))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
PtrDerefIter&
|
||||||
|
operator= (PtrDerefIter<WrappedIterType> const& ref)
|
||||||
|
{
|
||||||
|
i_ = reinterpret_cast<IT const&> (ref.getBase());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** explicit builder to allow creating a const variant from the basic srcIter type.
|
||||||
|
* Again, the reason necessitating this "backdoor" is that we want to swallow one level
|
||||||
|
* of indirection. Generally speaking `const T **` is not the same as `T * const *`,
|
||||||
|
* but in our specific case the API ensures that a `PtrDerefIter<WrappedConstIterType>`
|
||||||
|
* only exposes const elements.
|
||||||
|
*/
|
||||||
|
static PtrDerefIter
|
||||||
|
build_by_cast (WrappedIterType const& srcIter)
|
||||||
|
{
|
||||||
|
return PtrDerefIter (reinterpret_cast<IT const&> (srcIter));
|
||||||
|
}
|
||||||
|
|
||||||
|
static PtrDerefIter
|
||||||
|
nil()
|
||||||
|
{
|
||||||
|
return PtrDerefIter (IT());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* === lumiera forward iterator concept === */
|
||||||
|
|
||||||
|
reference
|
||||||
|
operator*() const
|
||||||
|
{
|
||||||
|
return *(*i_);
|
||||||
|
}
|
||||||
|
|
||||||
|
pointer
|
||||||
|
operator->() const
|
||||||
|
{
|
||||||
|
return *i_;
|
||||||
|
}
|
||||||
|
|
||||||
|
PtrDerefIter&
|
||||||
|
operator++()
|
||||||
|
{
|
||||||
|
++i_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
isValid () const
|
||||||
|
{
|
||||||
|
return bool(i_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
empty () const
|
||||||
|
{
|
||||||
|
return !isValid();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** access the wrapped implementation iterator */
|
||||||
|
IT const&
|
||||||
|
getBase() const
|
||||||
|
{
|
||||||
|
return i_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Supporting equality comparisons...
|
||||||
|
template<class I1, class I2>
|
||||||
|
bool operator== (PtrDerefIter<I1> const& il, PtrDerefIter<I2> const& ir) { return il.getBase() == ir.getBase(); }
|
||||||
|
|
||||||
|
template<class I1, class I2>
|
||||||
|
bool operator!= (PtrDerefIter<I1> const& il, PtrDerefIter<I2> const& ir) { return !(il == ir); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wrapper for an existing Iterator type to expose the address of each value yielded.
|
||||||
|
* Typically this can be used to build visitation sequences based on values living
|
||||||
|
* within a stable data structure (e.g. unmodifiable STL vector)
|
||||||
|
* @warning use of this wrapper might lead to taking the address of temporaries.
|
||||||
|
* The continued existence of the exposed storage locations must be guaranteed.
|
||||||
|
* @note bool checkable if and only if source is...
|
||||||
|
*/
|
||||||
|
template<class IT>
|
||||||
|
class AddressExposingIter
|
||||||
|
: public lib::BoolCheckable<AddressExposingIter<IT> >
|
||||||
|
{
|
||||||
|
typedef typename IT::pointer _Ptr;
|
||||||
|
|
||||||
|
IT i_; ///< nested source iterator
|
||||||
|
|
||||||
|
mutable _Ptr currPtr_;
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
takeAddress()
|
||||||
|
{
|
||||||
|
if (i_.isValid())
|
||||||
|
currPtr_ = & (*i_);
|
||||||
|
else
|
||||||
|
currPtr_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef typename IT::pointer const* pointer;
|
||||||
|
typedef typename IT::pointer const& reference;
|
||||||
|
typedef typename IT::pointer const value_type;
|
||||||
|
|
||||||
|
|
||||||
|
/** AddressExposingIter is always created
|
||||||
|
* by wrapping an existing iterator.
|
||||||
|
*/
|
||||||
|
explicit
|
||||||
|
AddressExposingIter (IT srcIter)
|
||||||
|
: i_(srcIter)
|
||||||
|
{
|
||||||
|
takeAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* === lumiera forward iterator concept === */
|
||||||
|
|
||||||
|
/** @return address of the source iteraor's current result
|
||||||
|
* @warning exposing a reference to an internal pointer for sake of compatibility.
|
||||||
|
* Clients must not store that reference, but rather use it to initialise
|
||||||
|
* a copy. The internal pointer exposed here will be changed on increment.
|
||||||
|
*/
|
||||||
|
reference
|
||||||
|
operator*() const
|
||||||
|
{
|
||||||
|
return currPtr_;
|
||||||
|
}
|
||||||
|
|
||||||
|
_Ptr
|
||||||
|
operator->() const
|
||||||
|
{
|
||||||
|
return currPtr_;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddressExposingIter&
|
||||||
|
operator++()
|
||||||
|
{
|
||||||
|
++i_;
|
||||||
|
takeAddress();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
isValid () const
|
||||||
|
{
|
||||||
|
return bool(i_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
empty () const
|
||||||
|
{
|
||||||
|
return !isValid();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** access the wrapped implementation iterator */
|
||||||
|
IT const&
|
||||||
|
getBase() const
|
||||||
|
{
|
||||||
|
return i_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Supporting equality comparisons...
|
||||||
|
template<class I1, class I2>
|
||||||
|
bool operator== (AddressExposingIter<I1> const& il, AddressExposingIter<I2> const& ir) { return il.getBase() == ir.getBase(); }
|
||||||
|
|
||||||
|
template<class I1, class I2>
|
||||||
|
bool operator!= (AddressExposingIter<I1> const& il, AddressExposingIter<I2> const& ir) { return !(il == ir); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}// namespace lib
|
||||||
|
#endif /*LIB_ITER_ADAPTER_PTR_DEREF_H*/
|
||||||
|
|
@ -42,7 +42,7 @@
|
||||||
|
|
||||||
|
|
||||||
#include "lib/iter-adapter.hpp"
|
#include "lib/iter-adapter.hpp"
|
||||||
|
#include "lib/iter-adapter-ptr-deref.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,9 @@
|
||||||
** element right into the iterator instance.
|
** element right into the iterator instance.
|
||||||
** - the RangeIter allows just to expose a range of elements defined
|
** - the RangeIter allows just to expose a range of elements defined
|
||||||
** by a STL-like pair of "start" and "end" iterators
|
** by a STL-like pair of "start" and "end" iterators
|
||||||
|
**
|
||||||
|
** Some more specific use cases are provided in the extension header
|
||||||
|
** iter-adapter-ptr-deref.hpp
|
||||||
** - often, objects are managed internally by pointers, while allowing
|
** - often, objects are managed internally by pointers, while allowing
|
||||||
** the clients to use direct references; to support this usage scenario,
|
** the clients to use direct references; to support this usage scenario,
|
||||||
** PtrDerefIter wraps an existing iterator, while dereferencing any value
|
** PtrDerefIter wraps an existing iterator, while dereferencing any value
|
||||||
|
|
@ -99,14 +102,12 @@
|
||||||
#include "lib/bool-checkable.hpp"
|
#include "lib/bool-checkable.hpp"
|
||||||
#include "lib/iter-type-binding.hpp"
|
#include "lib/iter-type-binding.hpp"
|
||||||
|
|
||||||
#include <boost/type_traits/remove_const.hpp>
|
|
||||||
|
|
||||||
|
|
||||||
namespace lib {
|
namespace lib {
|
||||||
|
|
||||||
|
|
||||||
namespace { // internal helpers
|
namespace { // internal helpers
|
||||||
void
|
inline void
|
||||||
_throwIterExhausted()
|
_throwIterExhausted()
|
||||||
{
|
{
|
||||||
throw lumiera::error::Invalid ("Can't iterate further",
|
throw lumiera::error::Invalid ("Can't iterate further",
|
||||||
|
|
@ -114,6 +115,12 @@ namespace lib {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** use a given Lumiera Forward Iterator in standard "range for loops" */
|
||||||
|
#define ENABLE_USE_IN_STD_RANGE_FOR_LOOPS(ITER) \
|
||||||
|
friend ITER begin (ITER const& it){ return it; } \
|
||||||
|
friend ITER&& begin (ITER&& it) { return static_cast<ITER&&> (it); } \
|
||||||
|
friend ITER end (ITER const&) { return ITER(); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -244,6 +251,9 @@ namespace lib {
|
||||||
_throwIterExhausted();
|
_throwIterExhausted();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ENABLE_USE_IN_STD_RANGE_FOR_LOOPS (IterAdapter);
|
||||||
|
|
||||||
/// comparison is allowed to access impl iterator
|
/// comparison is allowed to access impl iterator
|
||||||
template<class P1, class P2, class CX>
|
template<class P1, class P2, class CX>
|
||||||
friend bool operator== (IterAdapter<P1,CX> const&, IterAdapter<P2,CX> const&);
|
friend bool operator== (IterAdapter<P1,CX> const&, IterAdapter<P2,CX> const&);
|
||||||
|
|
@ -357,6 +367,9 @@ namespace lib {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ENABLE_USE_IN_STD_RANGE_FOR_LOOPS (IterStateWrapper);
|
||||||
|
|
||||||
/// comparison is allowed to access state implementation core
|
/// comparison is allowed to access state implementation core
|
||||||
template<class T1, class T2, class STX>
|
template<class T1, class T2, class STX>
|
||||||
friend bool operator== (IterStateWrapper<T1,STX> const&, IterStateWrapper<T2,STX> const&);
|
friend bool operator== (IterStateWrapper<T1,STX> const&, IterStateWrapper<T2,STX> const&);
|
||||||
|
|
@ -469,6 +482,9 @@ namespace lib {
|
||||||
const IT& getEnd() const { return e_; }
|
const IT& getEnd() const { return e_; }
|
||||||
|
|
||||||
|
|
||||||
|
ENABLE_USE_IN_STD_RANGE_FOR_LOOPS (RangeIter);
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -492,28 +508,6 @@ namespace lib {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
/** helper to remove pointer,
|
|
||||||
* while retaining const */
|
|
||||||
template<typename T>
|
|
||||||
struct RemovePtr { typedef T Type; };
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct RemovePtr<T*> { typedef T Type; };
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct RemovePtr<const T*> { typedef const T Type; };
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct RemovePtr<T* const> { typedef const T Type; };
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct RemovePtr<const T* const> { typedef const T Type; };
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper for type rewritings:
|
* Helper for type rewritings:
|
||||||
* get the element type for an iterator like entity
|
* get the element type for an iterator like entity
|
||||||
|
|
@ -548,260 +542,6 @@ namespace lib {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* wrapper for an existing Iterator type,
|
|
||||||
* automatically dereferencing the output of the former.
|
|
||||||
* For this to work, the "source" iterator is expected
|
|
||||||
* to be declared on \em pointers rather than on values.
|
|
||||||
* @note bool checkable if and only if source is...
|
|
||||||
*/
|
|
||||||
template<class IT>
|
|
||||||
class PtrDerefIter
|
|
||||||
: public lib::BoolCheckable<PtrDerefIter<IT> >
|
|
||||||
{
|
|
||||||
IT i_; ///< nested source iterator
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
typedef typename IT::value_type pointer;
|
|
||||||
typedef typename RemovePtr<pointer>::Type value_type;
|
|
||||||
typedef value_type& reference;
|
|
||||||
|
|
||||||
// for use with STL algorithms
|
|
||||||
typedef void difference_type;
|
|
||||||
typedef std::forward_iterator_tag iterator_category;
|
|
||||||
|
|
||||||
|
|
||||||
// the purpose of the following typedefs is to ease building a correct "const iterator"
|
|
||||||
|
|
||||||
typedef typename boost::remove_const<value_type>::type ValueTypeBase; // value_type without const
|
|
||||||
|
|
||||||
typedef typename IterType<IT>::template SimilarIter< ValueTypeBase* * >::Type WrappedIterType;
|
|
||||||
typedef typename IterType<IT>::template SimilarIter<const ValueTypeBase* * >::Type WrappedConstIterType;
|
|
||||||
|
|
||||||
typedef PtrDerefIter<WrappedIterType> IterType;
|
|
||||||
typedef PtrDerefIter<WrappedConstIterType> ConstIterType;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** PtrDerefIter is always created
|
|
||||||
* by wrapping an existing iterator.
|
|
||||||
*/
|
|
||||||
explicit
|
|
||||||
PtrDerefIter (IT srcIter)
|
|
||||||
: i_(srcIter)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
|
|
||||||
/** allow copy initialisation also when
|
|
||||||
* the wrapped iterator is based on some variation of a pointer.
|
|
||||||
* Especially, this includes initialisation of the "const variant"
|
|
||||||
* from the "normal variant" of PtrDerefIter. Actually, we need to convert
|
|
||||||
* in this case by brute force, because indeed (const TY *)* is not assignable
|
|
||||||
* from (TY *)* -- just we know that our intention is to dereference both levels
|
|
||||||
* of pointers, and then the resulting conversion is correct.
|
|
||||||
* @note in case IT == WrappedIterType, this is just a redefinition of the
|
|
||||||
* default copy ctor. In all other cases, this is an <i>additional
|
|
||||||
* ctor besides the default copy ctor</i> */
|
|
||||||
PtrDerefIter (PtrDerefIter<WrappedIterType> const& oIter)
|
|
||||||
: i_(reinterpret_cast<IT const&> (oIter.getBase()))
|
|
||||||
{ }
|
|
||||||
|
|
||||||
PtrDerefIter&
|
|
||||||
operator= (PtrDerefIter<WrappedIterType> const& ref)
|
|
||||||
{
|
|
||||||
i_ = reinterpret_cast<IT const&> (ref.getBase());
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** explicit builder to allow creating a const variant from the basic srcIter type.
|
|
||||||
* Again, the reason necessitating this "backdoor" is that we want to swallow one level
|
|
||||||
* of indirection. Generally speaking `const T **` is not the same as `T * const *`,
|
|
||||||
* but in our specific case the API ensures that a `PtrDerefIter<WrappedConstIterType>`
|
|
||||||
* only exposes const elements.
|
|
||||||
*/
|
|
||||||
static PtrDerefIter
|
|
||||||
build_by_cast (WrappedIterType const& srcIter)
|
|
||||||
{
|
|
||||||
return PtrDerefIter (reinterpret_cast<IT const&> (srcIter));
|
|
||||||
}
|
|
||||||
|
|
||||||
static PtrDerefIter
|
|
||||||
nil()
|
|
||||||
{
|
|
||||||
return PtrDerefIter (IT());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* === lumiera forward iterator concept === */
|
|
||||||
|
|
||||||
reference
|
|
||||||
operator*() const
|
|
||||||
{
|
|
||||||
return *(*i_);
|
|
||||||
}
|
|
||||||
|
|
||||||
pointer
|
|
||||||
operator->() const
|
|
||||||
{
|
|
||||||
return *i_;
|
|
||||||
}
|
|
||||||
|
|
||||||
PtrDerefIter&
|
|
||||||
operator++()
|
|
||||||
{
|
|
||||||
++i_;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
isValid () const
|
|
||||||
{
|
|
||||||
return bool(i_);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
empty () const
|
|
||||||
{
|
|
||||||
return !isValid();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** access the wrapped implementation iterator */
|
|
||||||
IT const&
|
|
||||||
getBase() const
|
|
||||||
{
|
|
||||||
return i_;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/// Supporting equality comparisons...
|
|
||||||
template<class I1, class I2>
|
|
||||||
bool operator== (PtrDerefIter<I1> const& il, PtrDerefIter<I2> const& ir) { return il.getBase() == ir.getBase(); }
|
|
||||||
|
|
||||||
template<class I1, class I2>
|
|
||||||
bool operator!= (PtrDerefIter<I1> const& il, PtrDerefIter<I2> const& ir) { return !(il == ir); }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* wrapper for an existing Iterator type to expose the address of each value yielded.
|
|
||||||
* Typically this can be used to build visitation sequences based on values living
|
|
||||||
* within a stable data structure (e.g. unmodifiable STL vector)
|
|
||||||
* @warning use of this wrapper might lead to taking the address of temporaries.
|
|
||||||
* The continued existence of the exposed storage locations must be guaranteed.
|
|
||||||
* @note bool checkable if and only if source is...
|
|
||||||
*/
|
|
||||||
template<class IT>
|
|
||||||
class AddressExposingIter
|
|
||||||
: public lib::BoolCheckable<AddressExposingIter<IT> >
|
|
||||||
{
|
|
||||||
typedef typename IT::pointer _Ptr;
|
|
||||||
|
|
||||||
IT i_; ///< nested source iterator
|
|
||||||
|
|
||||||
mutable _Ptr currPtr_;
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
takeAddress()
|
|
||||||
{
|
|
||||||
if (i_.isValid())
|
|
||||||
currPtr_ = & (*i_);
|
|
||||||
else
|
|
||||||
currPtr_ = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
typedef typename IT::pointer const* pointer;
|
|
||||||
typedef typename IT::pointer const& reference;
|
|
||||||
typedef typename IT::pointer const value_type;
|
|
||||||
|
|
||||||
|
|
||||||
/** AddressExposingIter is always created
|
|
||||||
* by wrapping an existing iterator.
|
|
||||||
*/
|
|
||||||
explicit
|
|
||||||
AddressExposingIter (IT srcIter)
|
|
||||||
: i_(srcIter)
|
|
||||||
{
|
|
||||||
takeAddress();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* === lumiera forward iterator concept === */
|
|
||||||
|
|
||||||
/** @return address of the source iteraor's current result
|
|
||||||
* @warning exposing a reference to an internal pointer for sake of compatibility.
|
|
||||||
* Clients must not store that reference, but rather use it to initialise
|
|
||||||
* a copy. The internal pointer exposed here will be changed on increment.
|
|
||||||
*/
|
|
||||||
reference
|
|
||||||
operator*() const
|
|
||||||
{
|
|
||||||
return currPtr_;
|
|
||||||
}
|
|
||||||
|
|
||||||
_Ptr
|
|
||||||
operator->() const
|
|
||||||
{
|
|
||||||
return currPtr_;
|
|
||||||
}
|
|
||||||
|
|
||||||
AddressExposingIter&
|
|
||||||
operator++()
|
|
||||||
{
|
|
||||||
++i_;
|
|
||||||
takeAddress();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
isValid () const
|
|
||||||
{
|
|
||||||
return bool(i_);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
empty () const
|
|
||||||
{
|
|
||||||
return !isValid();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** access the wrapped implementation iterator */
|
|
||||||
IT const&
|
|
||||||
getBase() const
|
|
||||||
{
|
|
||||||
return i_;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/// Supporting equality comparisons...
|
|
||||||
template<class I1, class I2>
|
|
||||||
bool operator== (AddressExposingIter<I1> const& il, AddressExposingIter<I2> const& ir) { return il.getBase() == ir.getBase(); }
|
|
||||||
|
|
||||||
template<class I1, class I2>
|
|
||||||
bool operator!= (AddressExposingIter<I1> const& il, AddressExposingIter<I2> const& ir) { return !(il == ir); }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** wrapper to declare exposed values const */
|
/** wrapper to declare exposed values const */
|
||||||
template<class IT>
|
template<class IT>
|
||||||
class ConstIter
|
class ConstIter
|
||||||
|
|
@ -874,5 +614,5 @@ namespace lib {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace lib
|
}// namespace lib
|
||||||
#endif
|
#endif /*LIB_ITER_ADAPTER_H*/
|
||||||
|
|
|
||||||
|
|
@ -281,8 +281,8 @@ namespace lib {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
mutable bool isOK_;
|
|
||||||
mutable bool cached_;
|
mutable bool cached_;
|
||||||
|
mutable bool isOK_;
|
||||||
|
|
||||||
bool
|
bool
|
||||||
currVal_isOK () const ///< @return (maybe cached) result of filter predicate
|
currVal_isOK () const ///< @return (maybe cached) result of filter predicate
|
||||||
|
|
@ -304,7 +304,8 @@ namespace lib {
|
||||||
FilterCore (IT const& source, PRED prediDef)
|
FilterCore (IT const& source, PRED prediDef)
|
||||||
: Raw(source)
|
: Raw(source)
|
||||||
, predicate_(prediDef) // induces a signature check
|
, predicate_(prediDef) // induces a signature check
|
||||||
, cached_(false)
|
, cached_(false) // not yet cached
|
||||||
|
, isOK_() // some value
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -331,6 +332,8 @@ namespace lib {
|
||||||
FilterIter (IT const& src, PRED filterPredicate)
|
FilterIter (IT const& src, PRED filterPredicate)
|
||||||
: _Impl(_Filter(src,filterPredicate))
|
: _Impl(_Filter(src,filterPredicate))
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
ENABLE_USE_IN_STD_RANGE_FOR_LOOPS (FilterIter)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -471,6 +474,8 @@ namespace lib {
|
||||||
TransformIter (IT const& src, FUN trafoFunc)
|
TransformIter (IT const& src, FUN trafoFunc)
|
||||||
: _IteratorImpl(_Trafo(src,trafoFunc))
|
: _IteratorImpl(_Trafo(src,trafoFunc))
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
ENABLE_USE_IN_STD_RANGE_FOR_LOOPS (TransformIter)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,16 +34,16 @@
|
||||||
** a virtual function (which requires a VTable): Even if for everyone else any
|
** a virtual function (which requires a VTable): Even if for everyone else any
|
||||||
** knowledge regarding the exact implementation type has been discarded ("erased"),
|
** knowledge regarding the exact implementation type has been discarded ("erased"),
|
||||||
** the function pointers in the VTable still implicitly hold onto that precise
|
** the function pointers in the VTable still implicitly hold onto that precise
|
||||||
** implementation type, since they were setup during construction, where the
|
** implementation type, since they were set up during construction, where the
|
||||||
** type was still available. Such a scheme of dealing with "opaque" copy operations
|
** type was still available. Such a scheme of dealing with "opaque" copy operations
|
||||||
** is known as <b>virtual copy</b> -- it can be dangerous and tricky to get right
|
** is known as <b>virtual copy</b> -- it can be dangerous and tricky to get right
|
||||||
** and is preferably used only in flat class hierarchies.
|
** and is preferably used only in flat class hierarchies.
|
||||||
**
|
**
|
||||||
** This helper template simplifies the construction of such a scheme.
|
** This helper template simplifies the construction of such a scheme.
|
||||||
** - a base interface defines the available virtual copy operations
|
** - a base interface defines the available virtual copy operations
|
||||||
** - a set of CRTP-style templates covers all the case of
|
** - a set of CRTP-style templates covers all the cases of
|
||||||
** - full copy support
|
** - full copy support
|
||||||
** - copy construction but not assignment
|
** - copy construction but no assignment
|
||||||
** - only move construction allowed
|
** - only move construction allowed
|
||||||
** - noncopyable type
|
** - noncopyable type
|
||||||
** - we use type traits and a policy template to pick the correct implementation
|
** - we use type traits and a policy template to pick the correct implementation
|
||||||
|
|
@ -144,6 +144,8 @@ namespace meta{
|
||||||
: public BASE
|
: public BASE
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
virtual ~VirtualCopySupportInterface() { }
|
||||||
|
|
||||||
virtual void copyInto (void* targetStorage) const =0;
|
virtual void copyInto (void* targetStorage) const =0;
|
||||||
virtual void moveInto (void* targetStorage) =0;
|
virtual void moveInto (void* targetStorage) =0;
|
||||||
virtual void copyInto (IFA& target) const =0;
|
virtual void copyInto (IFA& target) const =0;
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@
|
||||||
|
|
||||||
|
|
||||||
#include "include/logging.h"
|
#include "include/logging.h"
|
||||||
#include "lib/iter-adapter.hpp"
|
#include "lib/iter-adapter-ptr-deref.hpp"
|
||||||
#include "lib/error.hpp"
|
#include "lib/error.hpp"
|
||||||
#include "lib/util.hpp"
|
#include "lib/util.hpp"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,8 @@ namespace lib {
|
||||||
and should be usable both with \c std::tr1 and
|
and should be usable both with \c std::tr1 and
|
||||||
\c <boost/functional/hash.hpp> . It is implemented
|
\c <boost/functional/hash.hpp> . It is implemented
|
||||||
similar as the boost::hash specialisation for std::string */
|
similar as the boost::hash specialisation for std::string */
|
||||||
size_t hash_value (Literal sym)
|
size_t
|
||||||
|
hash_value (Literal sym)
|
||||||
{
|
{
|
||||||
size_t hash=0;
|
size_t hash=0;
|
||||||
if (sym)
|
if (sym)
|
||||||
|
|
|
||||||
|
|
@ -48,9 +48,6 @@ namespace lib {
|
||||||
namespace time {
|
namespace time {
|
||||||
|
|
||||||
|
|
||||||
TCode::~TCode() { } // emit VTable here....
|
|
||||||
|
|
||||||
|
|
||||||
namespace format { /* ================= Timecode implementation details ======== */
|
namespace format { /* ================= Timecode implementation details ======== */
|
||||||
|
|
||||||
LUMIERA_ERROR_DEFINE (INVALID_TIMECODE, "timecode format error, illegal value encountered");
|
LUMIERA_ERROR_DEFINE (INVALID_TIMECODE, "timecode format error, illegal value encountered");
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ namespace time {
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~TCode();
|
virtual ~TCode() { }
|
||||||
|
|
||||||
operator string() const { return show(); }
|
operator string() const { return show(); }
|
||||||
string describe() const { return string(tcID()); }
|
string describe() const { return string(tcID()); }
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
** setup allows to bridge between metaprogramming and (runtime) dispatcher tables.
|
** setup allows to bridge between metaprogramming and (runtime) dispatcher tables.
|
||||||
**
|
**
|
||||||
** Each such series of type-id-slots is associated to a distinct usage context.
|
** Each such series of type-id-slots is associated to a distinct usage context.
|
||||||
** Those usage contexts are discerned by the template parameter \c XY. Each of
|
** Those usage contexts are discerned by the template parameter \c CX. Each of
|
||||||
** these usage contexts uses a separate numbering scheme on his own, i.e. every
|
** these usage contexts uses a separate numbering scheme on his own, i.e. every
|
||||||
** new type encountered at runtime gets the next higher ID number (slot).
|
** new type encountered at runtime gets the next higher ID number (slot).
|
||||||
** @warning the actual ID numbers depend on the sequence of first encountering
|
** @warning the actual ID numbers depend on the sequence of first encountering
|
||||||
|
|
|
||||||
|
|
@ -142,6 +142,20 @@ namespace util {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** check if string starts with a given prefix */
|
||||||
|
inline bool
|
||||||
|
startsWith (string const& str, string const& prefix)
|
||||||
|
{
|
||||||
|
return 0 == str.rfind(prefix, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
startsWith (string const& str, const char* prefix)
|
||||||
|
{
|
||||||
|
return 0 == str.rfind(prefix, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** shortcut for containment test on a map */
|
/** shortcut for containment test on a map */
|
||||||
template <typename MAP>
|
template <typename MAP>
|
||||||
inline bool
|
inline bool
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,14 @@
|
||||||
** concrete type does not support assignment or copy construction, the respective access
|
** concrete type does not support assignment or copy construction, the respective access
|
||||||
** function is replaced by an implementation raising a runtime error.
|
** function is replaced by an implementation raising a runtime error.
|
||||||
**
|
**
|
||||||
|
** @note we use a Visitor interface generated through metaprogramming.
|
||||||
|
** This may generate a lot of warnings "-Woverloaded-virtual",
|
||||||
|
** since one \c handle(TX) function may shadow other \c handle(..) functions
|
||||||
|
** from the inherited (generated) Visitor interface. These warnings are besides
|
||||||
|
** the point, since not the \em client uses these functions, but the Variant does,
|
||||||
|
** after upcasting to the interface. Make sure you define your specialisations with
|
||||||
|
** the override modifier; when done so, it is safe to disable this warning here.
|
||||||
|
**
|
||||||
** @see Veriant_test
|
** @see Veriant_test
|
||||||
** @see lib::diff::GenNode
|
** @see lib::diff::GenNode
|
||||||
** @see virtual-copy-support.hpp
|
** @see virtual-copy-support.hpp
|
||||||
|
|
@ -111,6 +119,12 @@ namespace lib {
|
||||||
using Type = X;
|
using Type = X;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename X, typename TYPES>
|
||||||
|
struct CanBuildFrom<const X, Node<X, TYPES>>
|
||||||
|
{
|
||||||
|
using Type = X;
|
||||||
|
};
|
||||||
|
|
||||||
template<typename X, typename T,typename TYPES>
|
template<typename X, typename T,typename TYPES>
|
||||||
struct CanBuildFrom<X, Node<T, TYPES>>
|
struct CanBuildFrom<X, Node<T, TYPES>>
|
||||||
{
|
{
|
||||||
|
|
@ -136,12 +150,11 @@ namespace lib {
|
||||||
= meta::InstantiateForEach<typename TYPES::List, ValueAcceptInterface>;
|
= meta::InstantiateForEach<typename TYPES::List, ValueAcceptInterface>;
|
||||||
|
|
||||||
|
|
||||||
/////TODO: - is it possible directly to forward the constructor invocation to the object within the buffer? Beware of unverifiable generic solutions!
|
|
||||||
|
|
||||||
}//(End) implementation helpers
|
}//(End) implementation helpers
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Typesafe union record.
|
* Typesafe union record.
|
||||||
* A Variant element may carry an embedded value of any of the predefined types.
|
* A Variant element may carry an embedded value of any of the predefined types.
|
||||||
|
|
@ -154,6 +167,10 @@ namespace lib {
|
||||||
* in question, but type mismatch will provoke an exception at runtime.
|
* in question, but type mismatch will provoke an exception at runtime.
|
||||||
* Generic access is possible using a visitor.
|
* Generic access is possible using a visitor.
|
||||||
* @warning not threadsafe
|
* @warning not threadsafe
|
||||||
|
* @todo we need to define all copy operations explicitly, due to the
|
||||||
|
* templated one-arg ctor to wrap the actual values.
|
||||||
|
* There might be a generic solution for that ////////////////////////TICKET #963 Forwarding shadows copy operations -- generic solution??
|
||||||
|
* But -- Beware of unverifiable generic solutions!
|
||||||
*/
|
*/
|
||||||
template<typename TYPES>
|
template<typename TYPES>
|
||||||
class Variant
|
class Variant
|
||||||
|
|
@ -395,6 +412,12 @@ namespace lib {
|
||||||
return buff<X>().access();
|
return buff<X>().access();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename X>
|
||||||
|
X const&
|
||||||
|
get() const
|
||||||
|
{
|
||||||
|
return unConst(this)->template get<X>();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
accept (Visitor& visitor)
|
accept (Visitor& visitor)
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,6 @@ namespace asset {
|
||||||
using std::static_pointer_cast;
|
using std::static_pointer_cast;
|
||||||
|
|
||||||
using lib::HashVal;
|
using lib::HashVal;
|
||||||
using lib::P;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -119,8 +118,8 @@ namespace asset {
|
||||||
class Asset;
|
class Asset;
|
||||||
class AssetManager;
|
class AssetManager;
|
||||||
typedef const ID<Asset>& IDA;
|
typedef const ID<Asset>& IDA;
|
||||||
typedef P<Asset> PAsset;
|
typedef lib::P<Asset> PAsset;
|
||||||
typedef P<const Asset> PcAsset;
|
typedef lib::P<const Asset> PcAsset;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,15 +44,14 @@ using std::string;
|
||||||
namespace proc {
|
namespace proc {
|
||||||
namespace asset {
|
namespace asset {
|
||||||
|
|
||||||
using lib::P;
|
|
||||||
using lib::Symbol;
|
using lib::Symbol;
|
||||||
using lib::Literal;
|
using lib::Literal;
|
||||||
|
|
||||||
class Proc;
|
class Proc;
|
||||||
class ProcPatt;
|
class ProcPatt;
|
||||||
|
|
||||||
typedef P<const asset::Proc> PProc;
|
using PProc = lib::P<const asset::Proc>;
|
||||||
typedef P<const asset::ProcPatt> PProcPatt;
|
using PProcPatt = lib::P<const asset::ProcPatt>;
|
||||||
|
|
||||||
|
|
||||||
static Symbol CURRENT = "current";
|
static Symbol CURRENT = "current";
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ namespace asset {
|
||||||
mediaref.ident.version );
|
mediaref.ident.version );
|
||||||
}
|
}
|
||||||
|
|
||||||
Media::PClipMO
|
Media::PClip
|
||||||
createClipMO (const Clip& thisClipAsset, const Media& mediaChannel)
|
createClipMO (const Clip& thisClipAsset, const Media& mediaChannel)
|
||||||
{
|
{
|
||||||
return mobject::MObject::create (thisClipAsset,mediaChannel);
|
return mobject::MObject::create (thisClipAsset,mediaChannel);
|
||||||
|
|
@ -64,9 +64,9 @@ namespace asset {
|
||||||
mediaref.getLength())
|
mediaref.getLength())
|
||||||
, source_ (mediaref)
|
, source_ (mediaref)
|
||||||
, clipMO_ (createClipMO (*this, source_))
|
, clipMO_ (createClipMO (*this, source_))
|
||||||
{
|
{
|
||||||
this->defineDependency (mediaref);
|
this->defineDependency (mediaref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Specialisation of the asset::Media interface method,
|
/** Specialisation of the asset::Media interface method,
|
||||||
|
|
@ -76,7 +76,7 @@ namespace asset {
|
||||||
* Placements or no placement at all (meaning it need not
|
* Placements or no placement at all (meaning it need not
|
||||||
* be placed within the session)
|
* be placed within the session)
|
||||||
*/
|
*/
|
||||||
Media::PClipMO
|
Media::PClip
|
||||||
Clip::createClip () const
|
Clip::createClip () const
|
||||||
{
|
{
|
||||||
return clipMO_;
|
return clipMO_;
|
||||||
|
|
@ -87,7 +87,7 @@ namespace asset {
|
||||||
/** return this wrapped into a shared ptr,
|
/** return this wrapped into a shared ptr,
|
||||||
* because it's already the desired asset::Clip
|
* because it's already the desired asset::Clip
|
||||||
*/
|
*/
|
||||||
Media::PClip
|
Media::PClipAsset
|
||||||
Clip::getClipAsset ()
|
Clip::getClipAsset ()
|
||||||
{
|
{
|
||||||
return AssetManager::wrap (*this);
|
return AssetManager::wrap (*this);
|
||||||
|
|
|
||||||
|
|
@ -42,21 +42,21 @@ namespace asset {
|
||||||
const Media& source_;
|
const Media& source_;
|
||||||
|
|
||||||
/** the corresponding (dependent) clip-MO */
|
/** the corresponding (dependent) clip-MO */
|
||||||
PClipMO clipMO_;
|
PClip clipMO_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual PClipMO createClip () const;
|
virtual PClip createClip () const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Clip (Media& mediaref);
|
Clip (Media& mediaref);
|
||||||
friend class MediaFactory;
|
friend class MediaFactory;
|
||||||
|
|
||||||
virtual PClip getClipAsset ();
|
virtual PClipAsset getClipAsset ();
|
||||||
virtual PMedia checkCompound () const;
|
virtual PMedia checkCompound () const;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef P<const asset::Clip> PClipAsset;
|
typedef lib::P<const asset::Clip> PClipAsset;
|
||||||
|
|
||||||
const string CLIP_SUBFOLDER = "clips"; // TODO: handling of hard-wired constants....
|
const string CLIP_SUBFOLDER = "clips"; // TODO: handling of hard-wired constants....
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ namespace asset {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template<class KIND>
|
template<class KIND>
|
||||||
P<KIND>
|
lib::P<KIND>
|
||||||
get (ID<KIND> hash) const
|
get (ID<KIND> hash) const
|
||||||
{
|
{
|
||||||
return dynamic_pointer_cast<KIND,Asset> (find (hash));
|
return dynamic_pointer_cast<KIND,Asset> (find (hash));
|
||||||
|
|
@ -115,7 +115,7 @@ namespace asset {
|
||||||
|
|
||||||
template<class KIND>
|
template<class KIND>
|
||||||
void
|
void
|
||||||
put (ID<KIND> hash, P<KIND>& ptr)
|
put (ID<KIND> hash, lib::P<KIND>& ptr)
|
||||||
{
|
{
|
||||||
table[hash] = static_pointer_cast (ptr);
|
table[hash] = static_pointer_cast (ptr);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ namespace asset {
|
||||||
{};
|
{};
|
||||||
|
|
||||||
|
|
||||||
typedef P<Inventory> PInv;
|
typedef lib::P<Inventory> PInv;
|
||||||
|
|
||||||
|
|
||||||
}} // namespace proc::asset
|
}} // namespace proc::asset
|
||||||
|
|
|
||||||
|
|
@ -75,11 +75,11 @@ namespace asset {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Media::PClipMO
|
Media::PClip
|
||||||
Media::createClip ()
|
Media::createClip ()
|
||||||
{
|
{
|
||||||
PClip clipAsset (getClipAsset());
|
PClipAsset clipAsset (getClipAsset());
|
||||||
PClipMO clipMO = clipAsset->createClip();
|
PClip clipMO = clipAsset->createClip();
|
||||||
|
|
||||||
ENSURE (clipMO->isValid());
|
ENSURE (clipMO->isValid());
|
||||||
return clipMO;
|
return clipMO;
|
||||||
|
|
@ -90,7 +90,7 @@ namespace asset {
|
||||||
* or to get the right reference to some already existing asset::Clip,
|
* or to get the right reference to some already existing asset::Clip,
|
||||||
* especially when this media is part of a compound (multichannel) media.
|
* especially when this media is part of a compound (multichannel) media.
|
||||||
*/
|
*/
|
||||||
Media::PClip
|
Media::PClipAsset
|
||||||
Media::getClipAsset ()
|
Media::getClipAsset ()
|
||||||
{
|
{
|
||||||
if (PMedia parent = this->checkCompound())
|
if (PMedia parent = this->checkCompound())
|
||||||
|
|
@ -228,7 +228,7 @@ namespace asset {
|
||||||
* @throw Invalid if the given media asset is not top-level,
|
* @throw Invalid if the given media asset is not top-level,
|
||||||
* but rather part or a multichannel (compound) media
|
* but rather part or a multichannel (compound) media
|
||||||
*/
|
*/
|
||||||
P<Clip>
|
lib::P<Clip>
|
||||||
MediaFactory::operator() (Media& mediaref)
|
MediaFactory::operator() (Media& mediaref)
|
||||||
{
|
{
|
||||||
if (mediaref.checkCompound())
|
if (mediaref.checkCompound())
|
||||||
|
|
|
||||||
|
|
@ -75,10 +75,10 @@ namespace asset {
|
||||||
const Duration len_;
|
const Duration len_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef P<Media> PMedia;
|
using PMedia = lib::P<Media>;
|
||||||
typedef P<proc::asset::Clip> PClip;
|
using PClipAsset = lib::P<proc::asset::Clip>;
|
||||||
typedef P<proc::asset::ProcPatt> PProcPatt;
|
using PProcPatt = lib::P<proc::asset::ProcPatt>;
|
||||||
typedef proc::mobject::session::PClipMO PClipMO;
|
using PClip = mobject::Placement<mobject::session::Clip>;
|
||||||
|
|
||||||
|
|
||||||
static MediaFactory create;
|
static MediaFactory create;
|
||||||
|
|
@ -103,7 +103,7 @@ namespace asset {
|
||||||
* it can be regenerated from the corresponding asset::Clip
|
* it can be regenerated from the corresponding asset::Clip
|
||||||
* @return a Placement smart ptr owning the new Clip MObject
|
* @return a Placement smart ptr owning the new Clip MObject
|
||||||
*/
|
*/
|
||||||
PClipMO createClip ();
|
PClip createClip ();
|
||||||
|
|
||||||
/** @return the overall length of the media represented by this asset */
|
/** @return the overall length of the media represented by this asset */
|
||||||
virtual Duration getLength () const;
|
virtual Duration getLength () const;
|
||||||
|
|
@ -116,7 +116,7 @@ namespace asset {
|
||||||
|
|
||||||
/** get or create the correct asset::Clip
|
/** get or create the correct asset::Clip
|
||||||
* corresponding to this media */
|
* corresponding to this media */
|
||||||
virtual PClip getClipAsset ();
|
virtual PClipAsset getClipAsset ();
|
||||||
|
|
||||||
/** predicate to decide if this asset::Media
|
/** predicate to decide if this asset::Media
|
||||||
* is part of a compound (multichannel) media.
|
* is part of a compound (multichannel) media.
|
||||||
|
|
@ -144,7 +144,7 @@ namespace asset {
|
||||||
: boost::noncopyable
|
: boost::noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef P<Media> PType;
|
typedef lib::P<Media> PType;
|
||||||
|
|
||||||
PType operator() (Asset::Ident& key, const string& file="");
|
PType operator() (Asset::Ident& key, const string& file="");
|
||||||
PType operator() (const string& file, const Category& cat);
|
PType operator() (const string& file, const Category& cat);
|
||||||
|
|
@ -154,7 +154,7 @@ namespace asset {
|
||||||
PType operator() (const char* file, const Category& cat);
|
PType operator() (const char* file, const Category& cat);
|
||||||
PType operator() (const char* file, asset::Kind);
|
PType operator() (const char* file, asset::Kind);
|
||||||
|
|
||||||
P<Clip>
|
lib::P<Clip>
|
||||||
operator() (Media& mediaref);
|
operator() (Media& mediaref);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
#include "proc/asset/meta.hpp"
|
#include "proc/asset/meta.hpp"
|
||||||
#include "lib/util.hpp"
|
#include "lib/util.hpp"
|
||||||
|
|
||||||
|
using lib::idi::EntryID;
|
||||||
|
|
||||||
namespace proc {
|
namespace proc {
|
||||||
namespace asset {
|
namespace asset {
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@
|
||||||
#define ASSET_META_H
|
#define ASSET_META_H
|
||||||
|
|
||||||
#include "proc/asset.hpp"
|
#include "proc/asset.hpp"
|
||||||
#include "proc/asset/entry-id.hpp"
|
#include "lib/idi/entry-id.hpp"
|
||||||
|
|
||||||
#include <boost/noncopyable.hpp>
|
#include <boost/noncopyable.hpp>
|
||||||
|
|
||||||
|
|
@ -139,7 +139,7 @@ namespace asset {
|
||||||
inline ID<Meta>::ID(HashVal id) : ID<Asset> (id) {};
|
inline ID<Meta>::ID(HashVal id) : ID<Asset> (id) {};
|
||||||
inline ID<Meta>::ID(const Meta& meta) : ID<Asset> (meta.getID()) {};
|
inline ID<Meta>::ID(const Meta& meta) : ID<Asset> (meta.getID()) {};
|
||||||
|
|
||||||
typedef P<Meta> PMeta;
|
typedef lib::P<Meta> PMeta;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -150,13 +150,13 @@ namespace asset {
|
||||||
: boost::noncopyable
|
: boost::noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef P<asset::Meta> PType;
|
typedef lib::P<asset::Meta> PType;
|
||||||
|
|
||||||
template<class MA>
|
template<class MA>
|
||||||
meta::Builder<MA> operator() (EntryID<MA> elementIdentity);
|
meta::Builder<MA> operator() (lib::idi::EntryID<MA> elementIdentity);
|
||||||
|
|
||||||
template<class MA>
|
template<class MA>
|
||||||
meta::Builder<MA> operator() (meta::Descriptor const& prototype, EntryID<MA> elementIdentity);
|
meta::Builder<MA> operator() (meta::Descriptor const& prototype, lib::idi::EntryID<MA> elementIdentity);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
|
|
||||||
#include "proc/asset/meta/time-grid.hpp"
|
#include "proc/asset/meta/time-grid.hpp"
|
||||||
#include "proc/asset/entry-id.hpp"
|
#include "proc/asset/struct-scheme.hpp"
|
||||||
#include "proc/assetmanager.hpp"
|
#include "proc/assetmanager.hpp"
|
||||||
#include "lib/time/quantiser.hpp"
|
#include "lib/time/quantiser.hpp"
|
||||||
#include "lib/time/timevalue.hpp"
|
#include "lib/time/timevalue.hpp"
|
||||||
|
|
@ -36,7 +36,6 @@
|
||||||
using util::_Fmt;
|
using util::_Fmt;
|
||||||
using util::cStr;
|
using util::cStr;
|
||||||
using util::isnil;
|
using util::isnil;
|
||||||
using boost::str;
|
|
||||||
using std::string;
|
using std::string;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -49,8 +48,8 @@ namespace meta {
|
||||||
|
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
TimeGrid::TimeGrid (EntryID<TimeGrid> const& nameID)
|
TimeGrid::TimeGrid (GridID const& nameID)
|
||||||
: Meta (nameID.getIdent())
|
: Meta (idi::getAssetIdent (nameID))
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -108,12 +107,12 @@ namespace meta {
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SimpleTimeGrid (Time start, Duration frameDuration, EntryID<TimeGrid> const& name)
|
SimpleTimeGrid (Time start, Duration frameDuration, GridID const& name)
|
||||||
: TimeGrid (name)
|
: TimeGrid (name)
|
||||||
, FixedFrameQuantiser(frameDuration,start)
|
, FixedFrameQuantiser(frameDuration,start)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
SimpleTimeGrid (Time start, FrameRate frames_per_second, EntryID<TimeGrid> const& name)
|
SimpleTimeGrid (Time start, FrameRate frames_per_second, GridID const& name)
|
||||||
: TimeGrid (name)
|
: TimeGrid (name)
|
||||||
, FixedFrameQuantiser(frames_per_second,start)
|
, FixedFrameQuantiser(frames_per_second,start)
|
||||||
{ }
|
{ }
|
||||||
|
|
@ -136,7 +135,7 @@ namespace meta {
|
||||||
* Later on the intention is that in such cases, instead of creating a new grid
|
* Later on the intention is that in such cases, instead of creating a new grid
|
||||||
* we'll silently return the already registered existing and equivalent grid.
|
* we'll silently return the already registered existing and equivalent grid.
|
||||||
*/
|
*/
|
||||||
P<TimeGrid>
|
lib::P<TimeGrid>
|
||||||
Builder<TimeGrid>::commit()
|
Builder<TimeGrid>::commit()
|
||||||
{
|
{
|
||||||
if (predecessor_)
|
if (predecessor_)
|
||||||
|
|
@ -149,7 +148,7 @@ namespace meta {
|
||||||
_Fmt gridIdFormat("grid(%f_%d)");
|
_Fmt gridIdFormat("grid(%f_%d)");
|
||||||
id_ = string(gridIdFormat % fps_ % _raw(origin_));
|
id_ = string(gridIdFormat % fps_ % _raw(origin_));
|
||||||
}
|
}
|
||||||
EntryID<TimeGrid> nameID (id_);
|
GridID nameID (id_);
|
||||||
|
|
||||||
return publishWrapped (*new SimpleTimeGrid(origin_, fps_, nameID));
|
return publishWrapped (*new SimpleTimeGrid(origin_, fps_, nameID));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@
|
||||||
#define ASSET_META_TIME_GRID_H
|
#define ASSET_META_TIME_GRID_H
|
||||||
|
|
||||||
#include "proc/asset/meta.hpp"
|
#include "proc/asset/meta.hpp"
|
||||||
|
#include "lib/idi/entry-id.hpp"
|
||||||
#include "lib/time/grid.hpp"
|
#include "lib/time/grid.hpp"
|
||||||
#include "lib/time/timevalue.hpp"
|
#include "lib/time/timevalue.hpp"
|
||||||
#include "lib/symbol.hpp"
|
#include "lib/symbol.hpp"
|
||||||
|
|
@ -67,7 +68,8 @@ namespace meta {
|
||||||
|
|
||||||
|
|
||||||
class TimeGrid;
|
class TimeGrid;
|
||||||
typedef P<TimeGrid> PGrid;
|
using PGrid = lib::P<TimeGrid>;
|
||||||
|
using GridID = lib::idi::EntryID<TimeGrid>;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -91,7 +93,7 @@ namespace meta {
|
||||||
static PGrid build (Symbol gridID, FrameRate frames_per_second, Time origin);
|
static PGrid build (Symbol gridID, FrameRate frames_per_second, Time origin);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
TimeGrid (EntryID<TimeGrid> const&);
|
TimeGrid (GridID const&);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -111,7 +113,7 @@ namespace meta {
|
||||||
* the origin of this (local) grid.
|
* the origin of this (local) grid.
|
||||||
* @todo currently not supported (as of 12/2010)
|
* @todo currently not supported (as of 12/2010)
|
||||||
*/
|
*/
|
||||||
P<TimeGrid> predecessor_;
|
lib::P<TimeGrid> predecessor_;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* initialise to blank (zero).
|
* initialise to blank (zero).
|
||||||
|
|
@ -128,7 +130,7 @@ namespace meta {
|
||||||
/** create a time grid
|
/** create a time grid
|
||||||
* based on settings within this builder
|
* based on settings within this builder
|
||||||
*/
|
*/
|
||||||
P<TimeGrid> commit();
|
lib::P<TimeGrid> commit();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ namespace asset {
|
||||||
using std::string;
|
using std::string;
|
||||||
|
|
||||||
class Pipe;
|
class Pipe;
|
||||||
typedef P<Pipe> PPipe;
|
typedef lib::P<Pipe> PPipe;
|
||||||
|
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ namespace asset {
|
||||||
class Proc;
|
class Proc;
|
||||||
class ProcFactory;
|
class ProcFactory;
|
||||||
|
|
||||||
typedef P<const Proc> PProc;
|
typedef lib::P<const Proc> PProc;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -121,7 +121,7 @@ namespace asset {
|
||||||
: boost::noncopyable
|
: boost::noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef P<asset::Proc> PType;
|
typedef lib::P<asset::Proc> PType;
|
||||||
|
|
||||||
PType operator() (Asset::Ident& key); ////////////TODO define actual operation
|
PType operator() (Asset::Ident& key); ////////////TODO define actual operation
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ namespace asset {
|
||||||
* some ProcPatt as a template for creating more
|
* some ProcPatt as a template for creating more
|
||||||
* specialised patterns.
|
* specialised patterns.
|
||||||
*/
|
*/
|
||||||
P<ProcPatt>
|
lib::P<ProcPatt>
|
||||||
ProcPatt::newCopy (string newID) const
|
ProcPatt::newCopy (string newID) const
|
||||||
{
|
{
|
||||||
TODO ("implement the Pattern-ID within the propDescriptor!");
|
TODO ("implement the Pattern-ID within the propDescriptor!");
|
||||||
|
|
|
||||||
|
|
@ -39,9 +39,9 @@ namespace asset {
|
||||||
|
|
||||||
class Proc;
|
class Proc;
|
||||||
class ProcPatt;
|
class ProcPatt;
|
||||||
class BuildInstruct;
|
struct BuildInstruct;
|
||||||
typedef P<const asset::Proc> PProc;
|
typedef lib::P<const asset::Proc> PProc;
|
||||||
typedef P<const asset::ProcPatt> PProcPatt;
|
typedef lib::P<const asset::ProcPatt> PProcPatt;
|
||||||
|
|
||||||
typedef vector<BuildInstruct> InstructionSequence;
|
typedef vector<BuildInstruct> InstructionSequence;
|
||||||
|
|
||||||
|
|
@ -64,7 +64,7 @@ namespace asset {
|
||||||
friend class StructFactoryImpl;
|
friend class StructFactoryImpl;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
P<ProcPatt> newCopy (string newID) const;
|
lib::P<ProcPatt> newCopy (string newID) const;
|
||||||
|
|
||||||
ProcPatt& attach (Symbol where, PProc& node);
|
ProcPatt& attach (Symbol where, PProc& node);
|
||||||
ProcPatt& operator+= (PProcPatt& toReuse);
|
ProcPatt& operator+= (PProcPatt& toReuse);
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ namespace asset {
|
||||||
|
|
||||||
|
|
||||||
class Sequence;
|
class Sequence;
|
||||||
typedef P<Sequence> PSequence;
|
typedef lib::P<Sequence> PSequence;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -103,7 +103,6 @@ namespace asset {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
typedef P<Sequence> PSequence;
|
|
||||||
|
|
||||||
///////////////////////////TODO currently just fleshing the API
|
///////////////////////////TODO currently just fleshing the API
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,7 @@ namespace asset {
|
||||||
using proc::mobject::session::Scope;
|
using proc::mobject::session::Scope;
|
||||||
using proc::mobject::session::match_specificFork;
|
using proc::mobject::session::match_specificFork;
|
||||||
using proc::mobject::session::RBinding;
|
using proc::mobject::session::RBinding;
|
||||||
|
using proc::mobject::session::ForkID;
|
||||||
using proc::mobject::session::RFork;
|
using proc::mobject::session::RFork;
|
||||||
using proc::mobject::session::Fork;
|
using proc::mobject::session::Fork;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,8 @@
|
||||||
|
|
||||||
|
|
||||||
#include "lib/symbol.hpp"
|
#include "lib/symbol.hpp"
|
||||||
|
#include "proc/asset.hpp"
|
||||||
|
#include "lib/idi/entry-id.hpp"
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
|
|
@ -45,11 +47,9 @@
|
||||||
using boost::format;
|
using boost::format;
|
||||||
|
|
||||||
|
|
||||||
namespace lumiera {
|
|
||||||
class StreamType;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace proc {
|
namespace proc {
|
||||||
|
struct StreamType;
|
||||||
|
|
||||||
namespace mobject {
|
namespace mobject {
|
||||||
namespace session {
|
namespace session {
|
||||||
|
|
||||||
|
|
@ -105,7 +105,7 @@ namespace asset{
|
||||||
static Symbol catFolder() { return "pipes";}
|
static Symbol catFolder() { return "pipes";}
|
||||||
static Symbol idSymbol() { return "pipe"; }
|
static Symbol idSymbol() { return "pipe"; }
|
||||||
};
|
};
|
||||||
template<> struct StructTraits<lumiera::StreamType>
|
template<> struct StructTraits<proc::StreamType>
|
||||||
{
|
{
|
||||||
static Symbol namePrefix() { return "type"; }
|
static Symbol namePrefix() { return "type"; }
|
||||||
static Symbol catFolder() { return "stream-types";}
|
static Symbol catFolder() { return "stream-types";}
|
||||||
|
|
@ -147,18 +147,22 @@ namespace asset{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** generate an Asset identification tuple
|
||||||
template<class STRU>
|
* based on this EntryID's symbolic ID and type information.
|
||||||
inline string
|
* The remaining fields are filled in with hardwired defaults.
|
||||||
generateSymbolID()
|
* @note there is a twist, as this asset identity tuple generates
|
||||||
|
* a different hash as the EntryID. It would be desirable
|
||||||
|
* to make those two addressing systems interchangeable. /////////////TICKET #739
|
||||||
|
*/
|
||||||
|
template<typename TY>
|
||||||
|
inline Asset::Ident
|
||||||
|
getAssetIdent (lib::idi::EntryID<TY> const& entryID)
|
||||||
{
|
{
|
||||||
static uint i=0;
|
Category cat (STRUCT, idi::StructTraits<TY>::catFolder());
|
||||||
static format namePattern ("%s.%03d");
|
return Asset::Ident (entryID.getSym(), cat);
|
||||||
////////////////////////////////////////////////////////////////////////////////TICKET #166 : needs to be pushed down into a *.cpp
|
|
||||||
|
|
||||||
return str(namePattern % StructTraits<STRU>::namePrefix() % (++i) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}}} // namespace asset::idi
|
}}} // namespace asset::idi
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ namespace asset {
|
||||||
* asset is a code smell ////////////////////////////TICKET #691
|
* asset is a code smell ////////////////////////////TICKET #691
|
||||||
*/
|
*/
|
||||||
template<class STRU>
|
template<class STRU>
|
||||||
P<STRU>
|
lib::P<STRU>
|
||||||
StructFactory::newInstance (Symbol nameID)
|
StructFactory::newInstance (Symbol nameID)
|
||||||
{
|
{
|
||||||
Query<STRU> desired_name (isnil(nameID)? "" : "id("+nameID+")");
|
Query<STRU> desired_name (isnil(nameID)? "" : "id("+nameID+")");
|
||||||
|
|
@ -103,10 +103,10 @@ namespace asset {
|
||||||
* created as a side effect of calling the concrete Struct subclass ctor.
|
* created as a side effect of calling the concrete Struct subclass ctor.
|
||||||
*/
|
*/
|
||||||
template<class STRU>
|
template<class STRU>
|
||||||
P<STRU>
|
lib::P<STRU>
|
||||||
StructFactory::operator() (Query<STRU> const& capabilities)
|
StructFactory::operator() (Query<STRU> const& capabilities)
|
||||||
{
|
{
|
||||||
P<STRU> res;
|
lib::P<STRU> res;
|
||||||
QueryHandler<STRU>& typeHandler = ConfigResolver::instance();
|
QueryHandler<STRU>& typeHandler = ConfigResolver::instance();
|
||||||
typeHandler.resolve (res, capabilities);
|
typeHandler.resolve (res, capabilities);
|
||||||
|
|
||||||
|
|
@ -131,7 +131,7 @@ namespace asset {
|
||||||
* re-invoking the ConfigRules....
|
* re-invoking the ConfigRules....
|
||||||
*/
|
*/
|
||||||
template<class STRU>
|
template<class STRU>
|
||||||
P<STRU>
|
lib::P<STRU>
|
||||||
StructFactory::made4fake (Query<STRU> const& query)
|
StructFactory::made4fake (Query<STRU> const& query)
|
||||||
{
|
{
|
||||||
STRU* pS = impl_->fabricate(query);
|
STRU* pS = impl_->fabricate(query);
|
||||||
|
|
@ -149,7 +149,7 @@ namespace asset {
|
||||||
* @see ProcPatt
|
* @see ProcPatt
|
||||||
* @see DefaultsManager
|
* @see DefaultsManager
|
||||||
*/
|
*/
|
||||||
P<Pipe>
|
lib::P<Pipe>
|
||||||
StructFactory::newPipe (string pipeID, string streamID)
|
StructFactory::newPipe (string pipeID, string streamID)
|
||||||
{
|
{
|
||||||
normaliseID (pipeID);
|
normaliseID (pipeID);
|
||||||
|
|
@ -178,18 +178,19 @@ namespace asset {
|
||||||
|
|
||||||
namespace proc {
|
namespace proc {
|
||||||
namespace asset {
|
namespace asset {
|
||||||
|
using PPipe = lib::P<Pipe>;
|
||||||
|
|
||||||
template P<Pipe> StructFactory::operator() (Query<Pipe> const&);
|
template PPipe StructFactory::operator() (Query<Pipe> const&);
|
||||||
template PProcPatt StructFactory::operator() (Query<const ProcPatt> const&);
|
template PProcPatt StructFactory::operator() (Query<const ProcPatt> const&);
|
||||||
template PTimeline StructFactory::operator() (Query<Timeline> const&);
|
template PTimeline StructFactory::operator() (Query<Timeline> const&);
|
||||||
template PSequence StructFactory::operator() (Query<Sequence>const&);
|
template PSequence StructFactory::operator() (Query<Sequence>const&);
|
||||||
|
|
||||||
template P<Pipe> StructFactory::newInstance (Symbol);
|
template PPipe StructFactory::newInstance (Symbol);
|
||||||
template PProcPatt StructFactory::newInstance (Symbol);
|
template PProcPatt StructFactory::newInstance (Symbol);
|
||||||
template PTimeline StructFactory::newInstance (Symbol);
|
template PTimeline StructFactory::newInstance (Symbol);
|
||||||
template PSequence StructFactory::newInstance (Symbol);
|
template PSequence StructFactory::newInstance (Symbol);
|
||||||
|
|
||||||
template P<Pipe> StructFactory::made4fake (Query<Pipe> const&);
|
template PPipe StructFactory::made4fake (Query<Pipe> const&);
|
||||||
template PProcPatt StructFactory::made4fake (Query<const ProcPatt> const&);
|
template PProcPatt StructFactory::made4fake (Query<const ProcPatt> const&);
|
||||||
template PTimeline StructFactory::made4fake (Query<Timeline> const&);
|
template PTimeline StructFactory::made4fake (Query<Timeline> const&);
|
||||||
template PSequence StructFactory::made4fake (Query<Sequence>const&);
|
template PSequence StructFactory::made4fake (Query<Sequence>const&);
|
||||||
|
|
|
||||||
|
|
@ -151,17 +151,17 @@ namespace asset {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template<class STRU>
|
template<class STRU>
|
||||||
P<STRU> operator() (Query<STRU> const& query);
|
lib::P<STRU> operator() (Query<STRU> const& query);
|
||||||
|
|
||||||
// P<Timeline> operator() (MORef<Binding>); ///////////TODO doesn't this create circular includes?? Any better idea how to refer to an existing binding?
|
// lib::P<Timeline> operator() (MORef<Binding>); ///////////TODO doesn't this create circular includes?? Any better idea how to refer to an existing binding?
|
||||||
|
|
||||||
template<class STRU>
|
template<class STRU>
|
||||||
P<STRU> newInstance (Symbol nameID ="");
|
lib::P<STRU> newInstance (Symbol nameID ="");
|
||||||
|
|
||||||
template<class STRU>
|
template<class STRU>
|
||||||
P<STRU> made4fake (Query<STRU> const& query); ///< @warning to be removed in Alpha when using a real resolution engine /////TICKET #710
|
lib::P<STRU> made4fake (Query<STRU> const& query); ///< @warning to be removed in Alpha when using a real resolution engine /////TICKET #710
|
||||||
|
|
||||||
P<Pipe> newPipe (string pipeID, string streamID);
|
lib::P<Pipe> newPipe (string pipeID, string streamID);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ namespace asset {
|
||||||
|
|
||||||
|
|
||||||
class Timeline;
|
class Timeline;
|
||||||
typedef P<Timeline> PTimeline;
|
typedef lib::P<Timeline> PTimeline;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ namespace asset {
|
||||||
|
|
||||||
|
|
||||||
class Viewer;
|
class Viewer;
|
||||||
typedef P<Viewer> PViewer;
|
typedef lib::P<Viewer> PViewer;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,7 @@ namespace asset {
|
||||||
|
|
||||||
DB::Lock guard(®istry);
|
DB::Lock guard(®istry);
|
||||||
//////////////////////////////////////////////////////////TICKET #840 handle duplicate Registrations
|
//////////////////////////////////////////////////////////TICKET #840 handle duplicate Registrations
|
||||||
P<KIND> smart_ptr (obj, &destroy);
|
lib::P<KIND> smart_ptr (obj, &destroy);
|
||||||
|
|
||||||
registry.put (asset_id, smart_ptr);
|
registry.put (asset_id, smart_ptr);
|
||||||
return asset_id;
|
return asset_id;
|
||||||
|
|
@ -129,10 +129,10 @@ namespace asset {
|
||||||
* of the stored object differs and can't be casted.
|
* of the stored object differs and can't be casted.
|
||||||
*/
|
*/
|
||||||
template<class KIND>
|
template<class KIND>
|
||||||
P<KIND>
|
lib::P<KIND>
|
||||||
AssetManager::getAsset (const ID<KIND>& id)
|
AssetManager::getAsset (const ID<KIND>& id)
|
||||||
{
|
{
|
||||||
if (P<KIND> obj = registry.get (id))
|
if (lib::P<KIND> obj = registry.get (id))
|
||||||
return obj;
|
return obj;
|
||||||
else
|
else
|
||||||
if (known (id)) // provide Ident tuple of existing Asset
|
if (known (id)) // provide Ident tuple of existing Asset
|
||||||
|
|
@ -148,7 +148,7 @@ namespace asset {
|
||||||
* is explicitly given by type KIND.
|
* is explicitly given by type KIND.
|
||||||
*/
|
*/
|
||||||
template<class KIND>
|
template<class KIND>
|
||||||
P<KIND>
|
lib::P<KIND>
|
||||||
AssetManager::wrap (const KIND& asset)
|
AssetManager::wrap (const KIND& asset)
|
||||||
{
|
{
|
||||||
ENSURE (instance().known(asset.id),
|
ENSURE (instance().known(asset.id),
|
||||||
|
|
@ -250,6 +250,7 @@ namespace asset {
|
||||||
|
|
||||||
namespace proc {
|
namespace proc {
|
||||||
namespace asset {
|
namespace asset {
|
||||||
|
using lib::P;
|
||||||
|
|
||||||
template ID<Asset> AssetManager::reg (Asset* obj, const Asset::Ident& idi);
|
template ID<Asset> AssetManager::reg (Asset* obj, const Asset::Ident& idi);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -81,11 +81,11 @@ namespace asset {
|
||||||
|
|
||||||
/** retrieve the registered smart-ptr for any asset */
|
/** retrieve the registered smart-ptr for any asset */
|
||||||
template<class KIND>
|
template<class KIND>
|
||||||
static P<KIND> wrap (const KIND& asset);
|
static lib::P<KIND> wrap (const KIND& asset);
|
||||||
|
|
||||||
/** find and return corresponding object */
|
/** find and return corresponding object */
|
||||||
template<class KIND>
|
template<class KIND>
|
||||||
P<KIND> getAsset (const ID<KIND>& id);
|
lib::P<KIND> getAsset (const ID<KIND>& id);
|
||||||
|
|
||||||
|
|
||||||
/** @return true if the given id is registered in the internal asset DB */
|
/** @return true if the given id is registered in the internal asset DB */
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ namespace query {
|
||||||
using proc::asset::PSequence;
|
using proc::asset::PSequence;
|
||||||
|
|
||||||
using proc::mobject::session::Fork;
|
using proc::mobject::session::Fork;
|
||||||
using proc::mobject::session::PFork;
|
using PFork = lib::P<Fork>;
|
||||||
|
|
||||||
template PPipe DefsManager::operator() (Query<Pipe> const&);
|
template PPipe DefsManager::operator() (Query<Pipe> const&);
|
||||||
template PProcPatt DefsManager::operator() (Query<const ProcPatt> const&);
|
template PProcPatt DefsManager::operator() (Query<const ProcPatt> const&);
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,6 @@
|
||||||
#include "lib/meta/function-closure.hpp"
|
#include "lib/meta/function-closure.hpp"
|
||||||
#include "proc/control/command-signature.hpp"
|
#include "proc/control/command-signature.hpp"
|
||||||
#include "lib/functor-util.hpp"
|
#include "lib/functor-util.hpp"
|
||||||
#include "lib/format-util.hpp"
|
|
||||||
#include "lib/util.hpp"
|
#include "lib/util.hpp"
|
||||||
|
|
||||||
#include <boost/operators.hpp>
|
#include <boost/operators.hpp>
|
||||||
|
|
@ -181,19 +180,8 @@ namespace control {
|
||||||
return undo_ && capture_ && isCaptured_;
|
return undo_ && capture_ && isCaptured_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** for diagnostics: include format-util.hpp */
|
||||||
operator std::string() const
|
operator std::string() const;
|
||||||
{
|
|
||||||
if (!undo_ || !capture_)
|
|
||||||
return "·noUNDO·";
|
|
||||||
|
|
||||||
if (!isCaptured_)
|
|
||||||
return "<mem:missing>";
|
|
||||||
|
|
||||||
return "<"
|
|
||||||
+ util::str(memento_, "mem: ", "·memento·")
|
|
||||||
+ ">";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Supporting equality comparisons...
|
/// Supporting equality comparisons...
|
||||||
|
|
@ -212,6 +200,24 @@ namespace control {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename SIG, typename MEM>
|
||||||
|
MementoTie<SIG,MEM>::operator std::string() const
|
||||||
|
{
|
||||||
|
if (!undo_ || !capture_)
|
||||||
|
return "·noUNDO·";
|
||||||
|
|
||||||
|
if (!isCaptured_)
|
||||||
|
return "<mem:missing>";
|
||||||
|
|
||||||
|
return "<"
|
||||||
|
#ifdef LIB_FORMAT_UTIL_H
|
||||||
|
+ util::str(memento_, "mem: ", "·memento·")
|
||||||
|
#else
|
||||||
|
+ std::string("memento")
|
||||||
|
#endif
|
||||||
|
+ ">";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}} // namespace proc::control
|
}} // namespace proc::control
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,6 @@
|
||||||
namespace proc {
|
namespace proc {
|
||||||
namespace control {
|
namespace control {
|
||||||
|
|
||||||
// using lib::P;
|
|
||||||
|
|
||||||
// using std::string;
|
// using std::string;
|
||||||
// using boost::format;
|
// using boost::format;
|
||||||
|
|
|
||||||
|
|
@ -181,8 +181,6 @@ namespace engine{
|
||||||
/* ===== Quality-of-Service ===== */
|
/* ===== Quality-of-Service ===== */
|
||||||
|
|
||||||
|
|
||||||
EngineService::Quality::~Quality() { } // emit vtables here...
|
|
||||||
|
|
||||||
enum CalcType {
|
enum CalcType {
|
||||||
PLAYBACK,
|
PLAYBACK,
|
||||||
RENDER,
|
RENDER,
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ namespace engine{
|
||||||
class Quality
|
class Quality
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~Quality(); ///< this is an Interface
|
virtual ~Quality() { }; ///< this is an Interface
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,6 @@ namespace mobject {
|
||||||
|
|
||||||
namespace builder {
|
namespace builder {
|
||||||
|
|
||||||
using lib::P;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Policy invoking an catch-all function for processing
|
* Policy invoking an catch-all function for processing
|
||||||
|
|
@ -146,10 +145,10 @@ namespace mobject {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class TAR>
|
template<class TAR>
|
||||||
P<TAR>
|
lib::P<TAR>
|
||||||
getPtr ()
|
getPtr ()
|
||||||
{
|
{
|
||||||
P<TAR>* pP = currentWrapper_.get<P<TAR>*>();
|
lib::P<TAR>* pP = currentWrapper_.get<lib::P<TAR>*>();
|
||||||
ENSURE (pP, "wrong target type when invoking %s", __PRETTY_FUNCTION__);
|
ENSURE (pP, "wrong target type when invoking %s", __PRETTY_FUNCTION__);
|
||||||
return *pP;
|
return *pP;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ namespace builder {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/** @internal record to describe a model port */
|
/** @internal record to describe a model port */
|
||||||
struct ModelPortDescriptor;
|
class ModelPortDescriptor;
|
||||||
|
|
||||||
|
|
||||||
static void shutdown ();
|
static void shutdown ();
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,6 @@ namespace proc {
|
||||||
namespace mobject {
|
namespace mobject {
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using lib::P;
|
|
||||||
|
|
||||||
//NOBUG_DECLARE_FLAG (mobjectmem);
|
//NOBUG_DECLARE_FLAG (mobjectmem);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,8 +65,8 @@
|
||||||
|
|
||||||
namespace proc {
|
namespace proc {
|
||||||
namespace asset {
|
namespace asset {
|
||||||
class Timeline; typedef P<Timeline> PTimeline;
|
class Timeline; typedef lib::P<Timeline> PTimeline;
|
||||||
class Sequence; typedef P<Sequence> PSequence;
|
class Sequence; typedef lib::P<Sequence> PSequence;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace mobject {
|
namespace mobject {
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ namespace proc {
|
||||||
namespace asset {
|
namespace asset {
|
||||||
class Sequence;
|
class Sequence;
|
||||||
|
|
||||||
typedef P<Sequence> PSequence;
|
typedef lib::P<Sequence> PSequence;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ namespace proc {
|
||||||
namespace asset {
|
namespace asset {
|
||||||
|
|
||||||
class Pipe;
|
class Pipe;
|
||||||
typedef P<Pipe> PPipe;
|
typedef lib::P<Pipe> PPipe;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
#include "proc/mobject/session/abstractmo.hpp"
|
#include "proc/mobject/session/abstractmo.hpp"
|
||||||
#include "lib/time/timevalue.hpp"
|
#include "lib/time/timevalue.hpp"
|
||||||
|
#include "lib/p.hpp"
|
||||||
|
|
||||||
|
|
||||||
namespace proc {
|
namespace proc {
|
||||||
|
|
@ -40,8 +41,12 @@ namespace session {
|
||||||
using asset::Media;
|
using asset::Media;
|
||||||
using lib::time::TimeVar;
|
using lib::time::TimeVar;
|
||||||
|
|
||||||
typedef P<Media> PMedia;
|
class Clip;
|
||||||
typedef P<asset::Clip> PClipAsset;
|
|
||||||
|
using PMedia = lib::P<Media>;
|
||||||
|
using PClipAsset = lib::P<asset::Clip>;
|
||||||
|
|
||||||
|
using PClip = Placement<Clip>;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -103,7 +108,6 @@ namespace session {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef Placement<Clip> PClipMO;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
#define MOBJECT_SESSION_FORK_H
|
#define MOBJECT_SESSION_FORK_H
|
||||||
|
|
||||||
#include "proc/mobject/session/meta.hpp"
|
#include "proc/mobject/session/meta.hpp"
|
||||||
#include "proc/asset/entry-id.hpp"
|
#include "lib/idi/entry-id.hpp"
|
||||||
#include "lib/time/timevalue.hpp"
|
#include "lib/time/timevalue.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -34,25 +34,13 @@ namespace proc {
|
||||||
namespace mobject {
|
namespace mobject {
|
||||||
namespace session { //////////////////////////////////////////////////////TICKET #637
|
namespace session { //////////////////////////////////////////////////////TICKET #637
|
||||||
|
|
||||||
using lib::P;
|
|
||||||
using lib::time::Time;
|
using lib::time::Time;
|
||||||
|
|
||||||
class Fork;
|
class Fork;
|
||||||
|
|
||||||
typedef P<Fork> PFork;
|
using ForkID = lib::idi::EntryID<Fork>;
|
||||||
|
|
||||||
}}
|
|
||||||
|
|
||||||
namespace asset { //////////////////////////////////////////////////////TICKET #637
|
|
||||||
|
|
||||||
typedef EntryID<mobject::session::Fork> ForkID;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
namespace mobject {
|
|
||||||
namespace session {
|
|
||||||
|
|
||||||
using asset::ForkID;
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////TICKET #646
|
//////////////////////////////////////////////////////TICKET #646
|
||||||
|
|
|
||||||
|
|
@ -40,8 +40,8 @@ namespace session {
|
||||||
using asset::Media;
|
using asset::Media;
|
||||||
using lib::time::TimeVar;
|
using lib::time::TimeVar;
|
||||||
|
|
||||||
typedef P<Media> PMedia;
|
typedef lib::P<Media> PMedia;
|
||||||
typedef P<asset::Clip> PClipAsset;
|
typedef lib::P<asset::Clip> PClipAsset;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -84,8 +84,6 @@ namespace session {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef Placement<Clip> PClipMO;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}}} // namespace proc::mobject::session
|
}}} // namespace proc::mobject::session
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
#define PROC_MOBJECT_SESSION_MOBJECTFACTORY_H
|
#define PROC_MOBJECT_SESSION_MOBJECTFACTORY_H
|
||||||
|
|
||||||
#include "proc/mobject/mobject.hpp"
|
#include "proc/mobject/mobject.hpp"
|
||||||
#include "proc/asset/entry-id.hpp"
|
#include "lib/idi/entry-id.hpp"
|
||||||
#include "lib/symbol.hpp"
|
#include "lib/symbol.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -42,7 +42,7 @@ namespace asset {
|
||||||
class Effect;
|
class Effect;
|
||||||
class Sequence;
|
class Sequence;
|
||||||
|
|
||||||
typedef P<Sequence> PSequence;
|
typedef lib::P<Sequence> PSequence;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -70,7 +70,7 @@ namespace session {
|
||||||
Placement<Root> operator() (lumiera::query::DefsManager&);
|
Placement<Root> operator() (lumiera::query::DefsManager&);
|
||||||
Placement<Clip> operator() (asset::Clip const&, asset::Media const&);
|
Placement<Clip> operator() (asset::Clip const&, asset::Media const&);
|
||||||
Placement<Clip> operator() (asset::Clip const&, vector<asset::Media const*>);
|
Placement<Clip> operator() (asset::Clip const&, vector<asset::Media const*>);
|
||||||
Placement<Fork> operator() (asset::EntryID<Fork> const&);
|
Placement<Fork> operator() (lib::idi::EntryID<Fork> const&);
|
||||||
Placement<Effect> operator() (asset::Effect const&);
|
Placement<Effect> operator() (asset::Effect const&);
|
||||||
Placement<Label> operator() (lib::Symbol);
|
Placement<Label> operator() (lib::Symbol);
|
||||||
Placement<Binding>operator() (asset::PSequence const&);
|
Placement<Binding>operator() (asset::PSequence const&);
|
||||||
|
|
|
||||||
|
|
@ -175,7 +175,7 @@ namespace session {
|
||||||
{
|
{
|
||||||
typedef typename WrapReturn<TY>::Wrapper Ret;
|
typedef typename WrapReturn<TY>::Wrapper Ret;
|
||||||
|
|
||||||
public:
|
|
||||||
/** (dummy) implementation of the QueryHandler interface */
|
/** (dummy) implementation of the QueryHandler interface */
|
||||||
virtual bool
|
virtual bool
|
||||||
resolve (Ret& solution, Query<TY> const& q)
|
resolve (Ret& solution, Query<TY> const& q)
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@
|
||||||
|
|
||||||
#include "lib/symbol.hpp"
|
#include "lib/symbol.hpp"
|
||||||
//#include "common/query.hpp"
|
//#include "common/query.hpp"
|
||||||
#include "proc/asset/entry-id.hpp"
|
#include "lib/idi/entry-id.hpp"
|
||||||
|
|
||||||
#include <boost/noncopyable.hpp>
|
#include <boost/noncopyable.hpp>
|
||||||
|
|
||||||
|
|
@ -46,6 +46,7 @@ namespace proc {
|
||||||
using lib::Symbol;
|
using lib::Symbol;
|
||||||
|
|
||||||
// "yes mummy, we all know this code is not finished yet..."
|
// "yes mummy, we all know this code is not finished yet..."
|
||||||
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wuninitialized"
|
#pragma GCC diagnostic ignored "-Wuninitialized"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -74,7 +75,7 @@ namespace proc {
|
||||||
class ImplFacade;
|
class ImplFacade;
|
||||||
class ImplConstraint;
|
class ImplConstraint;
|
||||||
|
|
||||||
typedef asset::EntryID<StreamType> ID;
|
typedef lib::idi::EntryID<StreamType> ID;
|
||||||
|
|
||||||
|
|
||||||
Prototype const& prototype;
|
Prototype const& prototype;
|
||||||
|
|
@ -192,4 +193,10 @@ namespace proc {
|
||||||
|
|
||||||
|
|
||||||
} // namespace proc
|
} // namespace proc
|
||||||
#endif
|
|
||||||
|
|
||||||
|
namespace lumiera {
|
||||||
|
using proc::StreamType;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /*PROC_STREAMTYPE_H*/
|
||||||
|
|
|
||||||
|
|
@ -187,6 +187,8 @@ out: ^he says: hey Joe!
|
||||||
out: ^the truth: 0
|
out: ^the truth: 0
|
||||||
out: ^just a number: 1.234.*e\+56
|
out: ^just a number: 1.234.*e\+56
|
||||||
out: ^12345X
|
out: ^12345X
|
||||||
|
out: 0.+1.1.+2.2.+3.3.+4.4.+5.5.+6.6.+7.7.+8.8.+\-\-\+\-\-9.9
|
||||||
|
out-lit: Nr.01(0.0), Nr.02(2.2), Nr.03(4.4), Nr.04(6.6), Nr.05(8.8), Nr.06(11.0), Nr.07(13.2), Nr.08(15.4), Nr.09(17.6), Nr.10(19.8)
|
||||||
return: 0
|
return: 0
|
||||||
END
|
END
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,14 +34,14 @@ END
|
||||||
|
|
||||||
|
|
||||||
TEST "plain entry-ID" EntryID_test <<END
|
TEST "plain entry-ID" EntryID_test <<END
|
||||||
out: ID<..proc.asset.+Dummy.>-..proc.asset.+Dummy.\.001
|
out-lit: ID<Dummy>-Dummy.001
|
||||||
out: ID<..proc.asset.+Dummy.>-strange
|
out-lit: ID<Dummy>-strange
|
||||||
out: ID<..proc.asset.+Dummy.>-..proc.asset.+Dummy.\.002
|
out-lit: ID<Dummy>-Dummy.002
|
||||||
out: ID<fork>-fork\.001
|
out-lit: ID<Fork>-Fork.001
|
||||||
out: ID<fork>-fork\.002
|
out-lit: ID<Fork>-Fork.002
|
||||||
out: ID<fork>-special
|
out-lit: ID<Fork>-special
|
||||||
out: sizeof\( ..proc.asset.+EntryID.+mobject.+session.+Fork.+ \) =
|
out: sizeof\( ..lib.idi.EntryID.+mobject.+session.+Fork.+ \) =
|
||||||
out: sizeof\( ..proc.asset.+BareEntryID. \) =
|
out: sizeof\( ..lib.idi.+BareEntryID. \) =
|
||||||
return: 0
|
return: 0
|
||||||
END
|
END
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ namespace test_format {
|
||||||
class StreamTypeBasics_test : public Test
|
class StreamTypeBasics_test : public Test
|
||||||
{
|
{
|
||||||
virtual void
|
virtual void
|
||||||
run (Arg arg)
|
run (Arg)
|
||||||
{
|
{
|
||||||
ImplType iType = buildImplType ();
|
ImplType iType = buildImplType ();
|
||||||
basicImplTypeProperties (iType);
|
basicImplTypeProperties (iType);
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ namespace asset {
|
||||||
|
|
||||||
template<class CHI, class PAR>
|
template<class CHI, class PAR>
|
||||||
inline bool
|
inline bool
|
||||||
dependencyCheck (P<CHI> child, P<PAR> parent)
|
dependencyCheck (lib::P<CHI> child, lib::P<PAR> parent)
|
||||||
{
|
{
|
||||||
return (child == parent)
|
return (child == parent)
|
||||||
|| (0 < child->getParents().size()
|
|| (0 < child->getParents().size()
|
||||||
|
|
|
||||||
|
|
@ -153,8 +153,8 @@ namespace test {
|
||||||
|
|
||||||
void dependProcPatt(string pID)
|
void dependProcPatt(string pID)
|
||||||
{
|
{
|
||||||
typedef P<Pipe> PPipe; /////TODO: transition to P<>
|
typedef lib::P<Pipe> PPipe; /////TODO: transition to P<>
|
||||||
typedef P<const ProcPatt> PProcPatt;
|
typedef lib::P<const ProcPatt> PProcPatt;
|
||||||
|
|
||||||
PPipe thePipe = Pipe::query ("pipe("+pID+")");
|
PPipe thePipe = Pipe::query ("pipe("+pID+")");
|
||||||
CHECK (thePipe);
|
CHECK (thePipe);
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ namespace test {
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////TICKET #589
|
////////////////////////////////////TICKET #589
|
||||||
typedef P<Media> PM; /////TODO: transition to P<>
|
typedef lib::P<Media> PM; /////TODO: transition to P<>
|
||||||
|
|
||||||
/** @test Creating and automatically registering Asset instances.
|
/** @test Creating and automatically registering Asset instances.
|
||||||
* Re-Retrieving the newly created objects from AssetManager.
|
* Re-Retrieving the newly created objects from AssetManager.
|
||||||
|
|
|
||||||
|
|
@ -198,8 +198,8 @@ namespace test {
|
||||||
Depend4Test<backend::test::MediaAccessMock> within_this_scope;
|
Depend4Test<backend::test::MediaAccessMock> within_this_scope;
|
||||||
|
|
||||||
// -----Media and Clip--------------------------------
|
// -----Media and Clip--------------------------------
|
||||||
typedef P<Media> PM;
|
typedef lib::P<Media> PM;
|
||||||
typedef P<Clip> PC;
|
typedef lib::P<Clip> PC;
|
||||||
PM mm = asset::Media::create("test-1", VIDEO);
|
PM mm = asset::Media::create("test-1", VIDEO);
|
||||||
PC cc = mm->createClip()->findClipAsset();
|
PC cc = mm->createClip()->findClipAsset();
|
||||||
CHECK (dependencyCheck (cc,mm));
|
CHECK (dependencyCheck (cc,mm));
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,8 @@
|
||||||
#include "lib/test/run.hpp"
|
#include "lib/test/run.hpp"
|
||||||
#include "lib/test/test-helper.hpp"
|
#include "lib/test/test-helper.hpp"
|
||||||
|
|
||||||
#include "proc/asset/entry-id.hpp"
|
#include "lib/idi/entry-id.hpp"
|
||||||
|
#include "proc/asset/struct-scheme.hpp"
|
||||||
#include "proc/mobject/session/clip.hpp"
|
#include "proc/mobject/session/clip.hpp"
|
||||||
#include "proc/mobject/session/fork.hpp"
|
#include "proc/mobject/session/fork.hpp"
|
||||||
#include "lib/meta/trait-special.hpp"
|
#include "lib/meta/trait-special.hpp"
|
||||||
|
|
@ -47,9 +48,9 @@ using std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace proc {
|
namespace lib {
|
||||||
namespace asset{
|
namespace idi {
|
||||||
namespace test {
|
namespace test{
|
||||||
|
|
||||||
using lumiera::error::LUMIERA_ERROR_WRONG_TYPE;
|
using lumiera::error::LUMIERA_ERROR_WRONG_TYPE;
|
||||||
|
|
||||||
|
|
@ -57,11 +58,11 @@ namespace test {
|
||||||
|
|
||||||
struct Dummy { };
|
struct Dummy { };
|
||||||
|
|
||||||
typedef EntryID<Dummy> DummyID;
|
|
||||||
typedef EntryID<mobject::session::Fork> ForkID;
|
|
||||||
typedef EntryID<mobject::session::Clip> ClipID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using DummyID = EntryID<Dummy>;
|
||||||
|
using ForkID = EntryID<proc::mobject::session::Fork>;
|
||||||
|
using ClipID = EntryID<proc::mobject::session::Clip>;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -132,14 +133,19 @@ namespace test {
|
||||||
void
|
void
|
||||||
checkBasicProperties ()
|
checkBasicProperties ()
|
||||||
{
|
{
|
||||||
|
using proc::asset::Asset;
|
||||||
|
using proc::asset::STRUCT;
|
||||||
|
using proc::asset::Category;
|
||||||
|
using proc::asset::idi::getAssetIdent;
|
||||||
|
|
||||||
ForkID tID(" test ⚡ ☠ ☭ ⚡ track ");
|
ForkID tID(" test ⚡ ☠ ☭ ⚡ track ");
|
||||||
CHECK (tID.getIdent() == Asset::Ident("test_track", Category(STRUCT,"forks"), "lumi", 0));
|
CHECK (getAssetIdent(tID) == Asset::Ident("test_track", Category(STRUCT,"forks"), "lumi", 0));
|
||||||
|
|
||||||
CHECK (tID.getHash() == ForkID("☢ test ☢ track ☢").getHash());
|
CHECK (tID.getHash() == ForkID("☢ test ☢ track ☢").getHash());
|
||||||
|
|
||||||
CHECK (tID.getSym() == tID.getIdent().name);
|
CHECK (tID.getSym() == getAssetIdent(tID).name);
|
||||||
CHECK (ForkID().getIdent().category == Category (STRUCT,"forks"));
|
CHECK (getAssetIdent(ForkID()).category == Category (STRUCT,"forks"));
|
||||||
CHECK (ClipID().getIdent().category == Category (STRUCT,"clips"));
|
CHECK (getAssetIdent(ClipID()).category == Category (STRUCT,"clips"));
|
||||||
|
|
||||||
ClipID cID2,cID3;
|
ClipID cID2,cID3;
|
||||||
CHECK (cID2.getSym() < cID3.getSym());
|
CHECK (cID2.getSym() < cID3.getSym());
|
||||||
|
|
@ -153,7 +159,7 @@ namespace test {
|
||||||
tID = arbitrary;
|
tID = arbitrary;
|
||||||
CHECK (tID.getHash() == arbitrary.getHash());
|
CHECK (tID.getHash() == arbitrary.getHash());
|
||||||
CHECK (tID.getSym() == arbitrary.getSym());
|
CHECK (tID.getSym() == arbitrary.getSym());
|
||||||
CHECK (tID.getIdent()== arbitrary.getIdent());
|
CHECK (getAssetIdent(tID)== getAssetIdent(arbitrary));
|
||||||
}
|
}
|
||||||
|
|
||||||
cout << showSizeof<ForkID>() << endl;
|
cout << showSizeof<ForkID>() << endl;
|
||||||
|
|
@ -199,49 +205,49 @@ namespace test {
|
||||||
void
|
void
|
||||||
checkErasure ()
|
checkErasure ()
|
||||||
{
|
{
|
||||||
ForkID tID("suspicious");
|
ForkID fID("suspicious");
|
||||||
ClipID cID("suspicious");
|
ClipID cID("suspicious");
|
||||||
|
|
||||||
CHECK (tID.getHash() != cID.getHash());
|
CHECK (fID.getHash() != cID.getHash());
|
||||||
CHECK (tID.getSym() == cID.getSym());
|
CHECK (fID.getSym() == cID.getSym());
|
||||||
|
|
||||||
BareEntryID bIDt (tID);
|
BareEntryID bIDf (fID);
|
||||||
BareEntryID bIDc (cID);
|
BareEntryID bIDc (cID);
|
||||||
|
|
||||||
CHECK (bIDt != bIDc);
|
CHECK (bIDf != bIDc);
|
||||||
CHECK (bIDt.getHash() != bIDc.getHash());
|
CHECK (bIDf.getHash() != bIDc.getHash());
|
||||||
CHECK (bIDt.getSym() == bIDc.getSym());
|
CHECK (bIDf.getSym() == bIDc.getSym());
|
||||||
CHECK ("suspicious" == bIDc.getSym());
|
CHECK ("suspicious" == bIDc.getSym());
|
||||||
|
|
||||||
using mobject::session::Fork;
|
using proc::mobject::session::Fork;
|
||||||
using mobject::session::Clip;
|
using proc::mobject::session::Clip;
|
||||||
ForkID tIDnew = bIDt.recast<Fork>();
|
ForkID tIDnew = bIDf.recast<Fork>();
|
||||||
ClipID cIDnew = bIDc.recast<Clip>();
|
ClipID cIDnew = bIDc.recast<Clip>();
|
||||||
CHECK (tIDnew == tID);
|
CHECK (tIDnew == fID);
|
||||||
CHECK (cIDnew == cID);
|
CHECK (cIDnew == cID);
|
||||||
|
|
||||||
VERIFY_ERROR (WRONG_TYPE, bIDt.recast<Clip>());
|
VERIFY_ERROR (WRONG_TYPE, bIDf.recast<Clip>());
|
||||||
VERIFY_ERROR (WRONG_TYPE, bIDc.recast<Fork>());
|
VERIFY_ERROR (WRONG_TYPE, bIDc.recast<Fork>());
|
||||||
VERIFY_ERROR (WRONG_TYPE, bIDc.recast<Dummy>());
|
VERIFY_ERROR (WRONG_TYPE, bIDc.recast<Dummy>());
|
||||||
VERIFY_ERROR (WRONG_TYPE, bIDt.recast<Dummy>());
|
VERIFY_ERROR (WRONG_TYPE, bIDf.recast<Dummy>());
|
||||||
|
|
||||||
CHECK (tID == ForkID::recast (bIDt)); // equivalent static API on typed subclass
|
CHECK (fID == ForkID::recast (bIDf)); // equivalent static API on typed subclass
|
||||||
VERIFY_ERROR (WRONG_TYPE, ForkID::recast(bIDc));
|
VERIFY_ERROR (WRONG_TYPE, ForkID::recast(bIDc));
|
||||||
VERIFY_ERROR (WRONG_TYPE, ClipID::recast(bIDt));
|
VERIFY_ERROR (WRONG_TYPE, ClipID::recast(bIDf));
|
||||||
VERIFY_ERROR (WRONG_TYPE, DummyID::recast(bIDc));
|
VERIFY_ERROR (WRONG_TYPE, DummyID::recast(bIDc));
|
||||||
VERIFY_ERROR (WRONG_TYPE, DummyID::recast(bIDt));
|
VERIFY_ERROR (WRONG_TYPE, DummyID::recast(bIDf));
|
||||||
|
|
||||||
// mixed equality comparisons (based on the hash)
|
// mixed equality comparisons (based on the hash)
|
||||||
BareEntryID bIDt_copy (bIDt);
|
BareEntryID bIDt_copy (bIDf);
|
||||||
CHECK (bIDt == bIDt_copy);
|
CHECK (bIDf == bIDt_copy);
|
||||||
CHECK (!isSameObject (bIDt, bIDt_copy));
|
CHECK (!isSameObject (bIDf, bIDt_copy));
|
||||||
|
|
||||||
CHECK (tID != bIDc);
|
CHECK (fID != bIDc);
|
||||||
CHECK (cID != bIDt_copy);
|
CHECK (cID != bIDt_copy);
|
||||||
CHECK (tID == bIDt_copy);
|
CHECK (fID == bIDt_copy);
|
||||||
|
|
||||||
CHECK (bIDt == ForkID ("suspicious"));
|
CHECK (bIDf == ForkID ("suspicious"));
|
||||||
CHECK (bIDt != ClipID ("suspicious"));
|
CHECK (bIDf != ClipID ("suspicious"));
|
||||||
CHECK (bIDc == ClipID ("suspicious"));
|
CHECK (bIDc == ClipID ("suspicious"));
|
||||||
CHECK (ForkID ("suspicious") != ClipID ("suspicious"));
|
CHECK (ForkID ("suspicious") != ClipID ("suspicious"));
|
||||||
}
|
}
|
||||||
|
|
@ -252,20 +258,25 @@ namespace test {
|
||||||
typedef std::unordered_map<DummyID, string, DummyID::UseEmbeddedHash> Hashtable;
|
typedef std::unordered_map<DummyID, string, DummyID::UseEmbeddedHash> Hashtable;
|
||||||
|
|
||||||
/** @test build a hashtable, using EntryID as key,
|
/** @test build a hashtable, using EntryID as key,
|
||||||
* thereby using the embedded hash-ID */
|
* thereby using the embedded hash-ID
|
||||||
|
* @note there is a known weakness of the boost::hash
|
||||||
|
* when used on IDs with a running number suffix. /////TICKET #587
|
||||||
|
* We use a trick to spread the numbers better.
|
||||||
|
* @see HashGenerator_test#verify_Knuth_workaround
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
buildHashtable ()
|
buildHashtable ()
|
||||||
{
|
{
|
||||||
Hashtable tab;
|
Hashtable tab;
|
||||||
|
|
||||||
for (uint i=0; i<10000; ++i) //////////////////TICKET #865 hash collisions for 100000 entries
|
for (uint i=0; i<100000; ++i)
|
||||||
{
|
{
|
||||||
DummyID dummy;
|
DummyID dummy;
|
||||||
tab[dummy] = string(dummy);
|
tab[dummy] = string(dummy);
|
||||||
}
|
}
|
||||||
|
|
||||||
CHECK (and_all (tab, verifyEntry));
|
CHECK (and_all (tab, verifyEntry));
|
||||||
CHECK (10000 == tab.size());
|
CHECK (100000 == tab.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -287,7 +298,7 @@ namespace test {
|
||||||
|
|
||||||
|
|
||||||
/** Register this test class... */
|
/** Register this test class... */
|
||||||
LAUNCHER (EntryID_test, "unit asset");
|
LAUNCHER (EntryID_test, "unit common");
|
||||||
|
|
||||||
|
|
||||||
}}} // namespace proc::asset::test
|
}}} // namespace lib::idi::test
|
||||||
|
|
|
||||||
|
|
@ -54,8 +54,8 @@ namespace test {
|
||||||
*/
|
*/
|
||||||
class MakeClip_test : public Test
|
class MakeClip_test : public Test
|
||||||
{
|
{
|
||||||
typedef P<asset::Media> PM;
|
typedef lib::P<asset::Media> PM;
|
||||||
typedef asset::Media::PClipMO PC;
|
typedef asset::Media::PClip PC;
|
||||||
|
|
||||||
virtual void run (Arg)
|
virtual void run (Arg)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,6 @@ namespace test {
|
||||||
using namespace lib::time;
|
using namespace lib::time;
|
||||||
|
|
||||||
typedef Builder<TimeGrid> GridBuilder;
|
typedef Builder<TimeGrid> GridBuilder;
|
||||||
typedef EntryID<TimeGrid> GridID;
|
|
||||||
|
|
||||||
namespace { // Test definitions...
|
namespace { // Test definitions...
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ namespace test {
|
||||||
* within AssetManager by the Asset base class ctor
|
* within AssetManager by the Asset base class ctor
|
||||||
*/
|
*/
|
||||||
template<class A>
|
template<class A>
|
||||||
P<TestAsset<A> >
|
lib::P<TestAsset<A> >
|
||||||
TestAsset<A>::ptrFromThis ()
|
TestAsset<A>::ptrFromThis ()
|
||||||
{
|
{
|
||||||
return static_pointer_cast<TestAsset<A>,Asset>
|
return static_pointer_cast<TestAsset<A>,Asset>
|
||||||
|
|
@ -111,8 +111,8 @@ namespace test {
|
||||||
template TestAsset<Asset>::TestAsset (PAsset& pRef);
|
template TestAsset<Asset>::TestAsset (PAsset& pRef);
|
||||||
template TestAsset<Unknown>::TestAsset (PAsset& pRef);
|
template TestAsset<Unknown>::TestAsset (PAsset& pRef);
|
||||||
|
|
||||||
template P<TestAsset<Asset> > TestAsset<Asset>::ptrFromThis ();
|
template lib::P<TestAsset<Asset> > TestAsset<Asset>::ptrFromThis ();
|
||||||
template P<TestAsset<Unknown> > TestAsset<Unknown>::ptrFromThis ();
|
template lib::P<TestAsset<Unknown> > TestAsset<Unknown>::ptrFromThis ();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ namespace test {
|
||||||
static void deleter (TestAsset<A>* aa) { delete aa; }
|
static void deleter (TestAsset<A>* aa) { delete aa; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef P<TestAsset<A> > PA;
|
typedef lib::P<TestAsset<A> > PA;
|
||||||
|
|
||||||
static PA create () { return (new TestAsset<A> )->ptrFromThis(); }
|
static PA create () { return (new TestAsset<A> )->ptrFromThis(); }
|
||||||
static PA create (PAsset& pRef) { return (new TestAsset<A> (pRef))->ptrFromThis(); }
|
static PA create (PAsset& pRef) { return (new TestAsset<A> (pRef))->ptrFromThis(); }
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
#include "lib/test/test-helper.hpp"
|
#include "lib/test/test-helper.hpp"
|
||||||
|
|
||||||
#include "proc/asset/typed-id.hpp"
|
#include "proc/asset/typed-id.hpp"
|
||||||
#include "proc/asset/entry-id.hpp"
|
#include "lib/idi/entry-id.hpp"
|
||||||
#include "lib/p.hpp"
|
#include "lib/p.hpp"
|
||||||
#include "proc/assetmanager.hpp"
|
#include "proc/assetmanager.hpp"
|
||||||
#include "proc/asset/inventory.hpp"
|
#include "proc/asset/inventory.hpp"
|
||||||
|
|
@ -84,14 +84,14 @@ namespace query {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace proc {
|
namespace lib {
|
||||||
namespace asset{
|
namespace idi {
|
||||||
namespace test {
|
namespace test{
|
||||||
|
|
||||||
using mobject::session::test::DummyEntity;
|
using proc::mobject::session::test::DummyEntity;
|
||||||
using mobject::session::test::PDum;
|
using proc::mobject::session::test::PDum;
|
||||||
|
|
||||||
typedef EntryID<DummyEntity> DummyID;
|
using DummyID = EntryID<DummyEntity>;
|
||||||
|
|
||||||
namespace { // Test definitions...
|
namespace { // Test definitions...
|
||||||
|
|
||||||
|
|
@ -244,4 +244,4 @@ namespace test {
|
||||||
LAUNCHER (TypedID_test, "unit asset");
|
LAUNCHER (TypedID_test, "unit asset");
|
||||||
|
|
||||||
|
|
||||||
}}} // namespace proc::asset::test
|
}}} // namespace lib::idi::test
|
||||||
|
|
|
||||||
|
|
@ -161,6 +161,7 @@ namespace test {
|
||||||
CHECK (mp1);
|
CHECK (mp1);
|
||||||
CHECK (mp2);
|
CHECK (mp2);
|
||||||
CHECK (mp1x);
|
CHECK (mp1x);
|
||||||
|
CHECK (mp2x);
|
||||||
CHECK (!mpNull); // bool check verifies setup and connected state
|
CHECK (!mpNull); // bool check verifies setup and connected state
|
||||||
|
|
||||||
CHECK ( ModelPort::exists (pipeA)); // this is the same check, but invoked just with an pipe-ID
|
CHECK ( ModelPort::exists (pipeA)); // this is the same check, but invoked just with an pipe-ID
|
||||||
|
|
|
||||||
|
|
@ -25,14 +25,25 @@
|
||||||
#include "lib/test/test-helper.hpp"
|
#include "lib/test/test-helper.hpp"
|
||||||
#include "lib/diff/gen-node.hpp"
|
#include "lib/diff/gen-node.hpp"
|
||||||
#include "lib/diff/record.hpp"
|
#include "lib/diff/record.hpp"
|
||||||
|
#include "lib/time/timevalue.hpp"
|
||||||
|
#include "lib/util.hpp"
|
||||||
|
|
||||||
//#include <utility>
|
//#include <utility>
|
||||||
//#include <string>
|
//#include <string>
|
||||||
//#include <vector>
|
//#include <vector>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
using util::isnil;
|
||||||
|
using util::contains;
|
||||||
|
using util::isSameObject;
|
||||||
|
using lib::hash::LuidH;
|
||||||
|
using lib::time::FSecs;
|
||||||
|
using lib::time::Time;
|
||||||
|
using lib::time::TimeSpan;
|
||||||
//using std::string;
|
//using std::string;
|
||||||
//using std::vector;
|
//using std::vector;
|
||||||
//using std::swap;
|
//using std::swap;
|
||||||
|
using std::fabs;
|
||||||
|
|
||||||
|
|
||||||
namespace lib {
|
namespace lib {
|
||||||
|
|
@ -40,6 +51,8 @@ namespace diff{
|
||||||
namespace test{
|
namespace test{
|
||||||
|
|
||||||
// using lumiera::error::LUMIERA_ERROR_LOGIC;
|
// using lumiera::error::LUMIERA_ERROR_LOGIC;
|
||||||
|
using error::LUMIERA_ERROR_WRONG_TYPE;
|
||||||
|
using error::LUMIERA_ERROR_BOTTOM_VALUE;
|
||||||
|
|
||||||
namespace {//Test fixture....
|
namespace {//Test fixture....
|
||||||
|
|
||||||
|
|
@ -58,6 +71,18 @@ namespace test{
|
||||||
/*****************************************************************************//**
|
/*****************************************************************************//**
|
||||||
* @test Verify properties of a special collection type shaped for
|
* @test Verify properties of a special collection type shaped for
|
||||||
* external representation of object-like data.
|
* external representation of object-like data.
|
||||||
|
* - GenNode elements can be created "right away", picking up
|
||||||
|
* the given type, assumed that the payload is one of the
|
||||||
|
* supported basic types.
|
||||||
|
* - optionally, GenNode elements can be named
|
||||||
|
* - unnamed elements get a marker ID plus unique number extension
|
||||||
|
* - object-like elements can be represented by using a diff:Record<GenNode>
|
||||||
|
* as payload. Obviously, the resulting data structure type is recursive.
|
||||||
|
* - a shortcut is provided to simplify defining empty baseline objects
|
||||||
|
* - there is a special notation to create "id references", which can
|
||||||
|
* can be used to stand-in for an "object" (Record). This shortcut
|
||||||
|
* notation is relevant for the tree diff language -- used within
|
||||||
|
* Lumiera as "External Tree Description" of object networks.
|
||||||
*
|
*
|
||||||
* @see IndexTable
|
* @see IndexTable
|
||||||
* @see DiffListApplication_test
|
* @see DiffListApplication_test
|
||||||
|
|
@ -69,9 +94,9 @@ namespace test{
|
||||||
run (Arg)
|
run (Arg)
|
||||||
{
|
{
|
||||||
simpleUsage();
|
simpleUsage();
|
||||||
verifySnapshot();
|
objectShortcut();
|
||||||
|
symbolReference();
|
||||||
sequenceIteration();
|
sequenceIteration();
|
||||||
duplicateDetection();
|
|
||||||
copy_and_move();
|
copy_and_move();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -79,30 +104,168 @@ namespace test{
|
||||||
void
|
void
|
||||||
simpleUsage()
|
simpleUsage()
|
||||||
{
|
{
|
||||||
|
// can build from the supported value types
|
||||||
|
GenNode n1(42);
|
||||||
|
CHECK (42 == n1.data.get<int>());
|
||||||
|
CHECK (!n1.isNamed());
|
||||||
|
CHECK (contains (n1.idi.getSym(), "_CHILD_"));
|
||||||
|
CHECK (contains (name(n1), "_CHILD_"));
|
||||||
|
|
||||||
|
// can optionally be named
|
||||||
|
GenNode n2("π", 3.14159265358979323846264338328);
|
||||||
|
CHECK (fabs (3.14159265 - n2.data.get<double>()) < 1e-5 );
|
||||||
|
CHECK (n2.isNamed());
|
||||||
|
CHECK ("π" == n2.idi.getSym());
|
||||||
|
CHECK ("π" == name(n2));
|
||||||
|
|
||||||
|
// is a copyable value
|
||||||
|
GenNode n11(n1);
|
||||||
|
CHECK (n1 == n11);
|
||||||
|
CHECK (42 == n11.data.get<int>());
|
||||||
|
|
||||||
|
// is assignable with compatible payload value
|
||||||
|
n11.data = 24;
|
||||||
|
CHECK (n1 != n11);
|
||||||
|
CHECK (24 == n11.data.get<int>());
|
||||||
|
CHECK (42 == n1.data.get<int>());
|
||||||
|
|
||||||
|
// is assignable within the same kind of value
|
||||||
|
n1 = n11;
|
||||||
|
CHECK (n1 == n11);
|
||||||
|
|
||||||
|
// but assignment may not alter payload type
|
||||||
|
VERIFY_ERROR (WRONG_TYPE, n1 = n2 );
|
||||||
|
|
||||||
|
// can build recursive data structures
|
||||||
|
GenNode n3(Rec({GenNode("type", "spam"), GenNode("ham", "eggs")}));
|
||||||
|
CHECK ("spam" == n3.data.get<Rec>().getType());
|
||||||
|
CHECK ("eggs" == n3.data.get<Rec>().get("ham").data.get<string>());
|
||||||
|
CHECK ("ham" == n3.data.get<Rec>().get("ham").idi.getSym());
|
||||||
|
CHECK (n3.data.get<Rec>().get("ham").isNamed());
|
||||||
|
CHECK (!n3.isNamed());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
verifySnapshot()
|
objectShortcut()
|
||||||
{
|
{
|
||||||
|
auto o0 = MakeRec().genNode();
|
||||||
|
auto o1 = MakeRec().genNode("νόμος");
|
||||||
|
auto o2 = MakeRec().type("spam").genNode();
|
||||||
|
auto o3 = MakeRec().attrib("Ψ", int64_t(42), "π", 3.14159265358979323846264338328).genNode("λόγος");
|
||||||
|
|
||||||
|
CHECK (!o0.isNamed());
|
||||||
|
CHECK (isnil(o0.data.get<Rec>()));
|
||||||
|
CHECK ("NIL" == o0.data.get<Rec>().getType());
|
||||||
|
|
||||||
|
CHECK (o1.isNamed());
|
||||||
|
CHECK ("νόμος" == o1.idi.getSym());
|
||||||
|
CHECK (isnil(o1.data.get<Rec>()));
|
||||||
|
|
||||||
|
CHECK (!o2.isNamed());
|
||||||
|
CHECK ("spam" == o0.data.get<Rec>().getType());
|
||||||
|
CHECK (isnil(o2.data.get<Rec>()));
|
||||||
|
|
||||||
|
CHECK (o3.isNamed());
|
||||||
|
CHECK ("λόγος" == o3.idi.getSym());
|
||||||
|
CHECK ("NIL" == o3.data.get<Rec>().getType());
|
||||||
|
CHECK (GenNode("Ψ", int64_t(42)) == o3.data.get<Rec>().get("Ψ"));
|
||||||
|
CHECK (42L == o3.data.get<Rec>().get("Ψ").data.get<int64_t>());
|
||||||
|
CHECK (1e-7 > fabs (3.14159265 - o3.data.get<Rec>().get("π").data.get<double>()));
|
||||||
|
|
||||||
|
LuidH luid;
|
||||||
|
//Demonstration: object builder is based on the mutator mechanism for Records...
|
||||||
|
auto o4 = Rec::Mutator(o2.data.get<Rec>()) // ...use GenNode o2 as starting point
|
||||||
|
.appendChild(GenNode("τ", Time(1,2,3,4))) // a named node with Time value
|
||||||
|
.scope('*' // a char node
|
||||||
|
,"★" // a string node
|
||||||
|
,luid // a hash value (LUID)
|
||||||
|
,TimeSpan(Time::ZERO, FSecs(23,25)) // a time span
|
||||||
|
,MakeRec().type("ham").scope("eggs").genNode()) // a spam object
|
||||||
|
.genNode("baked beans"); // ---> finish into named node
|
||||||
|
|
||||||
|
CHECK (o4.isNamed());
|
||||||
|
CHECK ("baked beans" == o4.idi.getSym());
|
||||||
|
CHECK ("spam" == o4.data.get<Rec>().getType()); // this was "inherited" from o2
|
||||||
|
|
||||||
|
auto scope = o4.data.get<Rec>().scope();
|
||||||
|
CHECK (!isnil(scope));
|
||||||
|
CHECK (GenNode("τ", Time(1,2,3,4)) == *scope);
|
||||||
|
++scope;
|
||||||
|
CHECK (GenNode(char('*')) == *scope);
|
||||||
|
++scope;
|
||||||
|
CHECK ("★" == scope->data.get<string>());
|
||||||
|
++scope;
|
||||||
|
CHECK (luid == scope->data.get<LuidH>());
|
||||||
|
++scope;
|
||||||
|
CHECK (Time(920,0) == scope->data.get<TimeSpan>().end());
|
||||||
|
++scope;
|
||||||
|
auto spam = *scope;
|
||||||
|
CHECK (!++scope);
|
||||||
|
CHECK ("ham" == spam.data.get<Rec>().getType());
|
||||||
|
CHECK (spam.contains (GenNode("eggs")));
|
||||||
|
|
||||||
|
// but while o4 was based on o2,
|
||||||
|
// adding all the additional contents didn't mutate o2
|
||||||
|
CHECK (isnil(o2.data.get<Rec>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
symbolReference()
|
||||||
|
{
|
||||||
|
GenNode ham = MakeRec().type("spam").attrib("τ", Time(23,42)).genNode("egg bacon sausage and spam");
|
||||||
|
|
||||||
|
GenNode::ID hamID(ham);
|
||||||
|
CHECK (hamID == ham.idi);
|
||||||
|
CHECK (hamID.getSym() == ham.idi.getSym());
|
||||||
|
CHECK (hamID.getHash() == ham.idi.getHash());
|
||||||
|
CHECK (contains (string(hamID), "spam")); // Lovely spam!
|
||||||
|
|
||||||
|
Ref ref1("egg bacon sausage and spam");
|
||||||
|
Ref ref2(ham);
|
||||||
|
|
||||||
|
CHECK (ref1.idi == ham.idi);
|
||||||
|
CHECK (ref2.idi == ham.idi);
|
||||||
|
|
||||||
|
// can stand-in for the original Record...
|
||||||
|
CHECK (isSameObject (ham, ref2.data.get<Rec>()));
|
||||||
|
VERIFY_ERROR (BOTTOM_VALUE, ref1.data.get<Rec>());
|
||||||
|
|
||||||
|
RecRef rr1 = ref1.data.get<RecRef>();
|
||||||
|
RecRef rr2 = ref2.data.get<RecRef>();
|
||||||
|
|
||||||
|
CHECK ( isnil(rr1));
|
||||||
|
CHECK (!isnil(rr2));
|
||||||
|
Rec& ham_ref = rr2;
|
||||||
|
CHECK (isSameObject(ham, ham_ref));
|
||||||
|
CHECK (isSameObject(&ham, rr2.get()));
|
||||||
|
|
||||||
|
// pre-defined special ref-tokens
|
||||||
|
CHECK ("_END_" == name(Ref::END));
|
||||||
|
CHECK ("_THIS_" == name(Ref::THIS));
|
||||||
|
CHECK ("_CHILD_" == name(Ref::CHILD));
|
||||||
|
CHECK ("_ATTRIBS_" == name(Ref::ATTRIBS));
|
||||||
|
|
||||||
|
CHECK (isnil (Ref::END.data.get<RecRef>()));
|
||||||
|
CHECK (isnil (Ref::THIS.data.get<RecRef>()));
|
||||||
|
CHECK (isnil (Ref::CHILD.data.get<RecRef>()));
|
||||||
|
CHECK (isnil (Ref::ATTRIBS.data.get<RecRef>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
sequenceIteration()
|
sequenceIteration()
|
||||||
{
|
{
|
||||||
}
|
UNIMPLEMENTED ("wtf");
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
duplicateDetection()
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
copy_and_move()
|
copy_and_move()
|
||||||
{
|
{
|
||||||
|
UNIMPLEMENTED ("need to check that?");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,15 +23,23 @@
|
||||||
|
|
||||||
#include "lib/test/run.hpp"
|
#include "lib/test/run.hpp"
|
||||||
#include "lib/test/test-helper.hpp"
|
#include "lib/test/test-helper.hpp"
|
||||||
|
#include "lib/format-util.hpp"
|
||||||
#include "lib/diff/record.hpp"
|
#include "lib/diff/record.hpp"
|
||||||
|
#include "lib/itertools.hpp"
|
||||||
|
#include "lib/util.hpp" //////TODO necessary?
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
//#include <utility>
|
//#include <utility>
|
||||||
//#include <string>
|
#include <string>
|
||||||
//#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
//using std::string;
|
using std::string;
|
||||||
//using std::vector;
|
using util::isSameObject;
|
||||||
|
using util::isnil;
|
||||||
|
using std::vector;
|
||||||
//using std::swap;
|
//using std::swap;
|
||||||
|
using std::cout;
|
||||||
|
using std::endl;
|
||||||
|
|
||||||
|
|
||||||
namespace lib {
|
namespace lib {
|
||||||
|
|
@ -39,9 +47,38 @@ namespace diff{
|
||||||
namespace test{
|
namespace test{
|
||||||
|
|
||||||
// using lumiera::error::LUMIERA_ERROR_LOGIC;
|
// using lumiera::error::LUMIERA_ERROR_LOGIC;
|
||||||
|
using lumiera::error::LUMIERA_ERROR_INVALID;
|
||||||
|
using lumiera::error::LUMIERA_ERROR_BOTTOM_VALUE;
|
||||||
|
|
||||||
namespace {//Test fixture....
|
namespace {//Test fixture....
|
||||||
|
|
||||||
|
using Seq = vector<string>;
|
||||||
|
using RecS = Record<string>;
|
||||||
|
|
||||||
|
template<class IT>
|
||||||
|
inline Seq
|
||||||
|
contents (IT const& it)
|
||||||
|
{
|
||||||
|
Seq collected;
|
||||||
|
append_all (it, collected);
|
||||||
|
return collected;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Seq
|
||||||
|
contents (RecS const& rec_of_strings)
|
||||||
|
{
|
||||||
|
return contents (rec_of_strings.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class X>
|
||||||
|
inline Seq
|
||||||
|
strings (std::initializer_list<X> const& con)
|
||||||
|
{
|
||||||
|
Seq collected;
|
||||||
|
for (auto elm : con)
|
||||||
|
collected.push_back(elm);
|
||||||
|
return collected;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}//(End)Test fixture
|
}//(End)Test fixture
|
||||||
|
|
@ -52,11 +89,9 @@ namespace test{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************************************//**
|
||||||
|
|
||||||
/*****************************************************************************//**
|
|
||||||
* @test Verify properties of a special collection type meant for external representation
|
* @test Verify properties of a special collection type meant for external representation
|
||||||
* of object-loke data.
|
* of object-like data.
|
||||||
*
|
*
|
||||||
* @see IndexTable
|
* @see IndexTable
|
||||||
* @see DiffListApplication_test
|
* @see DiffListApplication_test
|
||||||
|
|
@ -68,40 +103,230 @@ namespace test{
|
||||||
run (Arg)
|
run (Arg)
|
||||||
{
|
{
|
||||||
simpleUsage();
|
simpleUsage();
|
||||||
verifySnapshot();
|
verifyCreation();
|
||||||
sequenceIteration();
|
verifyMutations();
|
||||||
duplicateDetection();
|
|
||||||
copy_and_move();
|
copy_and_move();
|
||||||
|
equality();
|
||||||
|
wrapRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
simpleUsage()
|
simpleUsage()
|
||||||
{
|
{
|
||||||
|
RecS enterprise("starship"
|
||||||
|
, strings ({"Name = USS Enterprise"
|
||||||
|
,"Registry = NCC-1701-D"
|
||||||
|
,"Class = Galaxy"
|
||||||
|
,"Owner = United Federation of Planets"
|
||||||
|
,"built=2363"
|
||||||
|
})
|
||||||
|
, strings ({"Picard", "Riker", "Data", "Troi", "Worf", "Crusher", "La Forge"})
|
||||||
|
);
|
||||||
|
|
||||||
|
CHECK (enterprise.getType() == "starship");
|
||||||
|
CHECK (enterprise.get("Registry") == "NCC-1701-D");
|
||||||
|
|
||||||
|
CHECK (enterprise.hasAttribute("Owner"));
|
||||||
|
CHECK (!enterprise.hasAttribute("owner"));
|
||||||
|
CHECK (!enterprise.hasAttribute("Owner "));
|
||||||
|
|
||||||
|
CHECK (enterprise.contains("Data"));
|
||||||
|
CHECK (!enterprise.contains("Woof"));
|
||||||
|
CHECK (util::contains (enterprise, "Worf"));
|
||||||
|
|
||||||
|
VERIFY_ERROR (INVALID, enterprise.get("warp10"));
|
||||||
|
|
||||||
|
cout << "enterprise = " << string(enterprise)<<endl;
|
||||||
|
for (string elm : enterprise) cout << elm<<endl;
|
||||||
|
for (string mbr : enterprise.scope()) cout << mbr<<endl;
|
||||||
|
for (string att : enterprise.attribs()) cout << att<<endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
verifySnapshot()
|
verifyCreation()
|
||||||
{
|
{
|
||||||
}
|
RecS nil;
|
||||||
|
CHECK (isnil(nil));
|
||||||
|
CHECK ("NIL" == nil.getType());
|
||||||
|
|
||||||
|
CHECK (!nil.begin());
|
||||||
|
CHECK (nil.begin() == nil.end());
|
||||||
|
|
||||||
|
|
||||||
void
|
RecS untyped({"x"});
|
||||||
sequenceIteration()
|
CHECK (!isnil(untyped));
|
||||||
{
|
CHECK ("NIL" == untyped.getType());
|
||||||
}
|
CHECK (Seq{"x"} == contents(untyped));
|
||||||
|
CHECK (Seq{"x"} == contents(untyped.scope()));
|
||||||
|
CHECK (isnil (untyped.attribs()));
|
||||||
|
|
||||||
|
RecS untyped2({"x=y", "z"});
|
||||||
|
CHECK (!isnil(untyped2));
|
||||||
|
CHECK ("NIL" == untyped2.getType());
|
||||||
|
CHECK (Seq({"x=y", "z"}) == contents(untyped2));
|
||||||
|
CHECK (Seq{"x"} == contents (untyped2.keys()));
|
||||||
|
CHECK (Seq{"y"} == contents (untyped2.vals()));
|
||||||
|
CHECK (Seq{"z"} == contents (untyped2.scope()));
|
||||||
|
|
||||||
|
|
||||||
void
|
RecS something({"type=thing", "a=1", "b=2", "c", "d"});
|
||||||
duplicateDetection()
|
CHECK (!isnil(something));
|
||||||
{
|
CHECK ("thing" == something.getType());
|
||||||
|
CHECK (Seq({"type=thing", "a=1", "b=2", "c", "d"}) == contents(something));
|
||||||
|
CHECK (Seq({"a", "b"}) == contents (something.keys()));
|
||||||
|
CHECK (Seq({"1", "2"}) == contents (something.vals()));
|
||||||
|
CHECK (Seq({"c", "d"}) == contents (something.scope()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
copy_and_move()
|
copy_and_move()
|
||||||
{
|
{
|
||||||
|
RecS a({"type=thing", "a=1", "b=2", "c", "d"});
|
||||||
|
RecS b(a);
|
||||||
|
CHECK (a.getType() == b.getType());
|
||||||
|
CHECK (contents(a) == contents(b));
|
||||||
|
CHECK (contents(a.attribs()) == contents(b.attribs()));
|
||||||
|
|
||||||
|
CHECK (!isSameObject (a.get("a"), b.get("a")));
|
||||||
|
CHECK (!isSameObject (*a.scope(), *b.scope()));
|
||||||
|
|
||||||
|
string const& c = *b.scope();
|
||||||
|
CHECK ("c" == c);
|
||||||
|
|
||||||
|
RecS bb;
|
||||||
|
CHECK (isnil(bb));
|
||||||
|
bb = move(b);
|
||||||
|
CHECK ("b" == bb.get("b"));
|
||||||
|
CHECK (isSameObject(c, *bb.scope()));
|
||||||
|
|
||||||
|
swap (a, bb);
|
||||||
|
CHECK (!isSameObject(c, *bb.scope()));
|
||||||
|
CHECK ( isSameObject(c, *a.scope()));
|
||||||
|
|
||||||
|
CHECK (isnil (b));
|
||||||
|
b = bb;
|
||||||
|
CHECK (!isnil (b));
|
||||||
|
CHECK (!isSameObject(b.get("a"), bb.get("a")));
|
||||||
|
CHECK (!isSameObject(*b.scope(), *bb.scope()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
equality()
|
||||||
|
{
|
||||||
|
RecS a({"a"});
|
||||||
|
RecS aa({"a","aa"});
|
||||||
|
RecS aaa({"a","a"});
|
||||||
|
RecS ax({"type=a","a"});
|
||||||
|
RecS ay({"a=a","a"});
|
||||||
|
|
||||||
|
CHECK (a != aa); CHECK (aa != a);
|
||||||
|
CHECK (aa != aaa); CHECK (aaa != aa);
|
||||||
|
CHECK (a != aaa); CHECK (aaa != a);
|
||||||
|
CHECK (a != ax); CHECK (ax != a);
|
||||||
|
CHECK (a != ay); CHECK (ay != a);
|
||||||
|
CHECK (ax != ay); CHECK (ay != ax);
|
||||||
|
CHECK (aaa != ay); CHECK (ay != aaa);
|
||||||
|
|
||||||
|
RecS a2({"a","aa"});
|
||||||
|
CHECK (aa == a2); CHECK (a2 == aa);
|
||||||
|
|
||||||
|
RecS o1("oo", strings({"a=α", "b=β"}), strings({"γ", "δ", "ε"}));
|
||||||
|
RecS o2({"type=oo", "a = α", "b = β", "γ", "δ", "ε"});
|
||||||
|
RecS o3({"type=oO", "a = α", "b = β", "γ", "δ", "ε"});
|
||||||
|
RecS o4({"type=oo", "a = α", "b = β", "c=γ", "δ", "ε"});
|
||||||
|
RecS o5({"type=oo", "a = α", "b = β", "γ", "ε", "δ"});
|
||||||
|
RecS o6({"type=oo", "a = α", "b = β", "γ", "δ"});
|
||||||
|
|
||||||
|
CHECK (o1 == o2); CHECK (o2 == o1);
|
||||||
|
CHECK (o2 != o3); CHECK (o3 != o2);
|
||||||
|
CHECK (o3 != o4); CHECK (o4 != o3);
|
||||||
|
CHECK (o4 != o5); CHECK (o5 != o4);
|
||||||
|
CHECK (o5 != o6); CHECK (o6 != o5);
|
||||||
|
CHECK (o1 != o3); CHECK (o3 != o1);
|
||||||
|
CHECK (o1 != o4); CHECK (o4 != o1);
|
||||||
|
CHECK (o1 != o5); CHECK (o5 != o1);
|
||||||
|
CHECK (o1 != o6); CHECK (o6 != o1);
|
||||||
|
CHECK (o2 != o4); CHECK (o4 != o2);
|
||||||
|
CHECK (o2 != o5); CHECK (o5 != o2);
|
||||||
|
CHECK (o2 != o6); CHECK (o6 != o2);
|
||||||
|
CHECK (o3 != o5); CHECK (o5 != o3);
|
||||||
|
CHECK (o3 != o6); CHECK (o6 != o3);
|
||||||
|
CHECK (o4 != o6); CHECK (o6 != o4);
|
||||||
|
|
||||||
|
RecS o7({"type=oo", "b = β", "a = α", "γ", "δ", "ε"});
|
||||||
|
CHECK (o2 != o7); CHECK (o7 != o2);
|
||||||
|
// ideally, they would be equal, but this would require
|
||||||
|
// a way more expensive implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
verifyMutations()
|
||||||
|
{
|
||||||
|
RecS a;
|
||||||
|
CHECK (isnil (a));
|
||||||
|
CHECK ("NIL" == a.getType());
|
||||||
|
|
||||||
|
RecS::Mutator mut(a);
|
||||||
|
mut.setType("u");
|
||||||
|
mut.appendChild("a");
|
||||||
|
mut.set("a", "1");
|
||||||
|
|
||||||
|
RecS aa(mut);
|
||||||
|
CHECK (a != aa);
|
||||||
|
CHECK ("u" == aa.getType());
|
||||||
|
CHECK (Seq({"type=u", "a=1", "a"}) == contents(aa));
|
||||||
|
CHECK (Seq({"a"}) == contents (aa.keys()));
|
||||||
|
CHECK (Seq({"1"}) == contents (aa.vals()));
|
||||||
|
CHECK (Seq({"a"}) == contents (aa.scope()));
|
||||||
|
|
||||||
|
CHECK (mut == aa);
|
||||||
|
|
||||||
|
mut.prependChild("⟂");
|
||||||
|
mut.set("b", "β");
|
||||||
|
mut.set("a", "α");
|
||||||
|
|
||||||
|
CHECK (mut != aa);
|
||||||
|
|
||||||
|
mut.replace(a);
|
||||||
|
CHECK (isnil (mut));
|
||||||
|
CHECK (Seq({"type=u", "a=α", "a=β", "⟂", "a"}) == contents(a));
|
||||||
|
CHECK (Seq({"type=u", "a=1", "a"}) == contents(aa));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
wrapRef()
|
||||||
|
{
|
||||||
|
RecS oo({"type = 🌰", "☿ = mercury", "♀ = venus", "♁ = earth", "♂ = mars", "♃ = jupiter", "♄ = saturn"});
|
||||||
|
|
||||||
|
RecordRef<string> empty;
|
||||||
|
CHECK (bool(empty) == false);
|
||||||
|
CHECK (nullptr == empty.get());
|
||||||
|
VERIFY_ERROR (BOTTOM_VALUE, empty.operator RecS&() );
|
||||||
|
|
||||||
|
RecordRef<string> ref(oo);
|
||||||
|
CHECK (ref);
|
||||||
|
CHECK (ref.get() == &oo);
|
||||||
|
|
||||||
|
RecS& oor = ref;
|
||||||
|
CHECK ("🌰" == oor.getType());
|
||||||
|
CHECK (oor.get("♄") == "saturn");
|
||||||
|
|
||||||
|
// are copyable and assignable
|
||||||
|
RecordRef<string> r2 = ref;
|
||||||
|
CHECK (r2);
|
||||||
|
CHECK (r2.get() == ref.get());
|
||||||
|
CHECK (!isSameObject (r2, ref));
|
||||||
|
|
||||||
|
empty = std::move(r2);
|
||||||
|
CHECK (empty);
|
||||||
|
CHECK (!r2);
|
||||||
|
CHECK (nullptr == r2.get());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -79,9 +79,7 @@ namespace test{
|
||||||
run (Arg)
|
run (Arg)
|
||||||
{
|
{
|
||||||
simpleAttributeBinding();
|
simpleAttributeBinding();
|
||||||
verifySnapshot();
|
|
||||||
sequenceIteration();
|
sequenceIteration();
|
||||||
duplicateDetection();
|
|
||||||
copy_and_move();
|
copy_and_move();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -113,24 +111,12 @@ namespace test{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
verifySnapshot()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
sequenceIteration()
|
sequenceIteration()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
duplicateDetection()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
copy_and_move()
|
copy_and_move()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ namespace test{
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************************//**
|
/***********************************************************************************//**
|
||||||
* @test Demonstrate how to build, discover and traverse tree-like data representation.
|
* @test Demonstrate how to build, explore and traverse tree-like data representation.
|
||||||
*
|
*
|
||||||
* @see IndexTable
|
* @see IndexTable
|
||||||
* @see DiffListApplication_test
|
* @see DiffListApplication_test
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,22 @@
|
||||||
|
|
||||||
#include "lib/test/run.hpp"
|
#include "lib/test/run.hpp"
|
||||||
#include "lib/format-util.hpp"
|
#include "lib/format-util.hpp"
|
||||||
|
#include "lib/format-string.hpp"
|
||||||
|
#include "lib/iter-adapter-stl.hpp"
|
||||||
#include "lib/error.hpp"
|
#include "lib/error.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
using lib::transformIterator;
|
||||||
|
using lib::iter_stl::eachElm;
|
||||||
|
using util::_Fmt;
|
||||||
|
|
||||||
|
using std::vector;
|
||||||
|
using std::string;
|
||||||
|
using std::to_string;
|
||||||
using std::cout;
|
using std::cout;
|
||||||
using std::endl;
|
using std::endl;
|
||||||
|
|
||||||
|
|
@ -46,22 +58,46 @@ namespace test {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class AutoCounter
|
||||||
|
{
|
||||||
|
static uint cnt;
|
||||||
|
|
||||||
|
uint id_;
|
||||||
|
double d_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
AutoCounter(double d)
|
||||||
|
: id_(++cnt)
|
||||||
|
, d_(d*2)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
operator string() const
|
||||||
|
{
|
||||||
|
return _Fmt("Nr.%02d(%3.1f)") % id_ % d_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
uint AutoCounter::cnt = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************//**
|
/***************************************************************************//**
|
||||||
* @test verifies the proper working of some string-formatting helper functions.
|
* @test verifies the proper working of some string-formatting helper functions.
|
||||||
* - util::str() provides a failsafe to-String conversion, preferring
|
* - util::str() provides a failsafe to-String conversion, preferring
|
||||||
* an built-in conversion, falling back to just a mangled type string.
|
* an built-in conversion, falling back to just a mangled type string.
|
||||||
* @see format-util.hpp
|
* @see format-util.hpp
|
||||||
*/
|
*/
|
||||||
class FormatHelper_test : public Test
|
class FormatHelper_test
|
||||||
|
: public Test
|
||||||
{
|
{
|
||||||
void
|
void
|
||||||
run (Arg)
|
run (Arg)
|
||||||
{
|
{
|
||||||
check2String();
|
check2String();
|
||||||
|
checkStringJoin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** @test verify a failasfe to-string conversion. */
|
/** @test verify a failsafe to-string conversion. */
|
||||||
void
|
void
|
||||||
check2String ()
|
check2String ()
|
||||||
{
|
{
|
||||||
|
|
@ -82,7 +118,30 @@ namespace test {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** @test verify delimiter separated joining of arbitrary collections.
|
||||||
|
* - the first test uses a STL container, which means we need to wrap
|
||||||
|
* into a lib::RangeIter. Moreover, lexical_cast is used to convert
|
||||||
|
* the double numbers into strings.
|
||||||
|
* - the second test uses an inline transforming iterator to build a
|
||||||
|
* series of AutoCounter objects, which provide a custom string
|
||||||
|
* conversion function. Moreover, since the transforming iterator
|
||||||
|
* conforms to the Lumiera Forward Iterator concept, we can just
|
||||||
|
* move the rvalue into the formatting function without much ado
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
checkStringJoin()
|
||||||
|
{
|
||||||
|
vector<double> dubious;
|
||||||
|
for (uint i=0; i<10; ++i)
|
||||||
|
dubious.push_back(1.1*i);
|
||||||
|
|
||||||
|
std::function<AutoCounter(double)> justCount = [](double d){ return AutoCounter(d); };
|
||||||
|
|
||||||
|
|
||||||
|
cout << join(dubious, "--+--") << endl;
|
||||||
|
cout << join(transformIterator(eachElm(dubious)
|
||||||
|
,justCount)) << endl;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
LAUNCHER (FormatHelper_test, "unit common");
|
LAUNCHER (FormatHelper_test, "unit common");
|
||||||
|
|
|
||||||
|
|
@ -58,9 +58,14 @@ namespace test{
|
||||||
run (Arg)
|
run (Arg)
|
||||||
{
|
{
|
||||||
demonstrate_boost_hash_weakness();
|
demonstrate_boost_hash_weakness();
|
||||||
|
verify_Knuth_workaround();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef boost::hash<string> BoostStringHasher;
|
||||||
|
typedef std::map<size_t, string> StringsTable;
|
||||||
|
|
||||||
|
|
||||||
/** @test demonstrate a serious weakness of boost::hash for strings.
|
/** @test demonstrate a serious weakness of boost::hash for strings.
|
||||||
* When hashing just the plain string representation of integers,
|
* When hashing just the plain string representation of integers,
|
||||||
* we get collisions already with small numbers below 100000.
|
* we get collisions already with small numbers below 100000.
|
||||||
|
|
@ -73,9 +78,6 @@ namespace test{
|
||||||
void
|
void
|
||||||
demonstrate_boost_hash_weakness ()
|
demonstrate_boost_hash_weakness ()
|
||||||
{
|
{
|
||||||
typedef boost::hash<string> BoostStringHasher;
|
|
||||||
typedef std::map<size_t, string> StringsTable;
|
|
||||||
|
|
||||||
BoostStringHasher hashFunction;
|
BoostStringHasher hashFunction;
|
||||||
StringsTable hashValues;
|
StringsTable hashValues;
|
||||||
string prefix = "Entry.";
|
string prefix = "Entry.";
|
||||||
|
|
@ -103,6 +105,50 @@ namespace test{
|
||||||
CHECK (0 < collisions, "boost::hash for strings is expected to produce collisions");
|
CHECK (0 < collisions, "boost::hash for strings is expected to produce collisions");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** @test verify a well-known pragmatic trick to help with unevenly spaced hash values.
|
||||||
|
* The boost::hash function is known to perform poorly on strings with common prefix
|
||||||
|
* plus running number. The mentioned trick (attributed to Donald Knuth) is spread the
|
||||||
|
* input numbers by something below the full domain, best close to the golden ratio;
|
||||||
|
* bonus points if this number is also a prime. An additional factor of 2 does not hurt
|
||||||
|
* (so in case of 64bit platform).
|
||||||
|
*
|
||||||
|
* In our case, it is sufficient to apply this trick to the trailing two digits;
|
||||||
|
* without this trick, we get the first collisions after about 20000 running numbers.
|
||||||
|
* @see BareEntryID
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
verify_Knuth_workaround()
|
||||||
|
{
|
||||||
|
StringsTable hashValues;
|
||||||
|
string prefix = "Entry.";
|
||||||
|
const size_t seed = rand();
|
||||||
|
|
||||||
|
const size_t KNUTH_MAGIC = 2654435761;
|
||||||
|
|
||||||
|
uint collisions(0);
|
||||||
|
for (uint i=0; i<100000; ++i)
|
||||||
|
{
|
||||||
|
string candidate = prefix + lexical_cast<string> (i);
|
||||||
|
size_t l = candidate.length();
|
||||||
|
size_t hashVal = seed;
|
||||||
|
|
||||||
|
boost::hash_combine(hashVal, KNUTH_MAGIC * candidate[l-1]);
|
||||||
|
boost::hash_combine(hashVal, KNUTH_MAGIC * candidate[l-2]);
|
||||||
|
boost::hash_combine(hashVal, candidate);
|
||||||
|
|
||||||
|
if (contains (hashValues, hashVal))
|
||||||
|
{
|
||||||
|
++collisions;
|
||||||
|
string other = hashValues[hashVal];
|
||||||
|
cout << "Hash collision between " << i << " and " << other <<endl;
|
||||||
|
}
|
||||||
|
hashValues[hashVal] = candidate;
|
||||||
|
}
|
||||||
|
CHECK (!collisions, "the Knuth trick failed to spread our hash values evenly enough, what a shame...");
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
#include "lib/util-foreach.hpp"
|
#include "lib/util-foreach.hpp"
|
||||||
|
|
||||||
#include "lib/iter-adapter.hpp"
|
#include "lib/iter-adapter.hpp"
|
||||||
|
#include "lib/iter-adapter-ptr-deref.hpp"
|
||||||
|
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
@ -139,10 +140,12 @@ namespace test{
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Implementation of Iteration-logic: detect iteration end.
|
/** Implementation of Iteration-logic: detect iteration end.
|
||||||
* @note the problem here is that this implementation chooses
|
* @note the problem here is that this implementation chooses to use
|
||||||
* to use two representations of "bottom" (end, invalid).
|
* two representations of ⟂ ("bottom", end, invalid). The reason is,
|
||||||
* The reason is, we want the default-constructed IterAdapter
|
* we want the default-constructed IterAdapter also be the ⟂ value.
|
||||||
* also be the "bottom" value. Thus, when we detect the
|
* This is in accordance with the »Lumiera Forward Iterator« concept,
|
||||||
|
* which requires the default constructed iterator to mark the iteration
|
||||||
|
* end and to evaluate to \c bool(false). Thus, when we detect the
|
||||||
* iteration end by internal logic (\c numberz_.end() ), we
|
* iteration end by internal logic (\c numberz_.end() ), we
|
||||||
* immediately transform this into the official "bottom"
|
* immediately transform this into the official "bottom"
|
||||||
*/
|
*/
|
||||||
|
|
@ -151,11 +154,11 @@ namespace test{
|
||||||
checkPoint (const TestContainer* src, ITER& pos)
|
checkPoint (const TestContainer* src, ITER& pos)
|
||||||
{
|
{
|
||||||
REQUIRE (src);
|
REQUIRE (src);
|
||||||
if ((pos != ITER(0)) && (pos != src->numberz_.end()))
|
if ((pos != ITER()) && (pos != src->numberz_.end()))
|
||||||
return true;
|
return true;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pos = ITER(0);
|
pos = ITER();
|
||||||
return false;
|
return false;
|
||||||
} }
|
} }
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1970,7 +1970,7 @@ It would thus be desirable to have a fixed-sized allocation, able to hold the pl
|
||||||
!!!Storage
|
!!!Storage
|
||||||
Explicit placements are value objects and stored at the respective usage site, most notably the [[Segmentation]]. They are //not// attached to the placement index in the session, nor do they bear any referential or indexing semantics. The only dynamic side effect of an explicit placement is to keep the reference count of the corresponding MObject up and thus keep it alive and accessible.</pre>
|
Explicit placements are value objects and stored at the respective usage site, most notably the [[Segmentation]]. They are //not// attached to the placement index in the session, nor do they bear any referential or indexing semantics. The only dynamic side effect of an explicit placement is to keep the reference count of the corresponding MObject up and thus keep it alive and accessible.</pre>
|
||||||
</div>
|
</div>
|
||||||
<div title="ExternalTreeDescription" creator="Ichthyostega" modifier="Ichthyostega" created="201505081647" modified="201505090059" tags="Concepts Model design spec draft" changecount="19">
|
<div title="ExternalTreeDescription" creator="Ichthyostega" modifier="Ichthyostega" created="201505081647" modified="201506121606" tags="Concepts Model design spec draft" changecount="27">
|
||||||
<pre>//to symbolically represent hierarchically structured elements, without actually implementing them.//
|
<pre>//to symbolically represent hierarchically structured elements, without actually implementing them.//
|
||||||
The purpose of this »external« description is to remove the need of a central data model to work against. We consider such a foundation data model as a good starting point, yet harmful for the evolution of any larger structure to be built. According to the subsidiarity principle, we prefer to turn the working data representation into a local concern. Which leaves us with the issue of collaboration. Any collaboration requires, as an underlying, some kind of common understanding. And any formalised, mechanical collaboration requires to represent that common point of attachment -- at least as symbolic representation. The ExternalTreeDescription is shaped to fulfil this need: //in theory,// the whole field could be represented, symbolically, as a network of hierarchically structured elements. Yet, //in practice,// all we need is to conceive the presence of such a representation, as a backdrop to work against. And we do so -- we work against that symbolic representation, by describing ''changes'' made to the structure and its elements. Thus, the description of changes, the ''diff language'', refers to and partially embodies such symbolically represented elements and relations.
|
The purpose of this »external« description is to remove the need of a central data model to work against. We consider such a foundation data model as a good starting point, yet harmful for the evolution of any larger structure to be built. According to the subsidiarity principle, we prefer to turn the working data representation into a local concern. Which leaves us with the issue of collaboration. Any collaboration requires, as an underlying, some kind of common understanding. And any formalised, mechanical collaboration requires to represent that common point of attachment -- at least as symbolic representation. The ExternalTreeDescription is shaped to fulfil this need: //in theory,// the whole field could be represented, symbolically, as a network of hierarchically structured elements. Yet, //in practice,// all we need is to conceive the presence of such a representation, as a backdrop to work against. And we do so -- we work against that symbolic representation, by describing ''changes'' made to the structure and its elements. Thus, the description of changes, the ''diff language'', refers to and partially embodies such symbolically represented elements and relations.
|
||||||
&rarr; TreeDiffFundamentals
|
&rarr; TreeDiffFundamentals
|
||||||
|
|
@ -1985,9 +1985,9 @@ For practical purposes, we have to introduce some distinctions and limitations.
|
||||||
* to the contrary, a Record has an associated, symbolic type-ID, plus it can potentially be associated with and thus relate to further elements, with the relation originating at the Record.
|
* to the contrary, a Record has an associated, symbolic type-ID, plus it can potentially be associated with and thus relate to further elements, with the relation originating at the Record.
|
||||||
* and we distinguish two different kinds of relations possibly originating from a Record:
|
* and we distinguish two different kinds of relations possibly originating from a Record:
|
||||||
** ''attributes'' are known by-name; they can be addressed through this name-ID as a key, while the value is again a generic node, possibly even another record.
|
** ''attributes'' are known by-name; they can be addressed through this name-ID as a key, while the value is again a generic node, possibly even another record.
|
||||||
** ''children'' to the contrary can only be ennumerated; they are considered to be within (and form) the ''scope'' of the given Record (object).
|
** ''children'' to the contrary can only be enumerated; they are considered to be within (and form) the ''scope'' of the given Record (object).
|
||||||
|
|
||||||
And there is a further limitation: Tthe domain of possible data is fixed, even hard wired. Implementation-wise, this turns the data within the generic node into a »Variant« (typesafe union). Basically, this opens two different ways to //access// the data within a given GenNode: either you know the type to expect beforehand (and the validity of this assumption is checked on each access; please recall, all of this is meant for symbolic representation, not for implementation of high performance computing). Or we offer the ability for //generic access// through a ''variant visitor'' (double dispatch). The latter includes the option not to handle all possible content types (making the variant visitor a //partial function// -- as in any non exhaustive pattern match).
|
And there is a further limitation: The domain of possible data is fixed, even hard wired. Implementation-wise, this turns the data within the generic node into a »Variant« (typesafe union). Basically, this opens two different ways to //access// the data within a given GenNode: either you know the type to expect beforehand (and the validity of this assumption is checked on each access; please recall, all of this is meant for symbolic representation, not for implementation of high performance computing). Or we offer the ability for //generic access// through a ''variant visitor'' (double dispatch). The latter includes the option not to handle all possible content types (making the variant visitor a //partial function// -- as in any non exhaustive pattern match).
|
||||||
|
|
||||||
Basically, you can expect to encounter the following kinds of data
|
Basically, you can expect to encounter the following kinds of data
|
||||||
*{{{int}}}, {{{int64_t}}}, {{{short}}}, {{{char}}}
|
*{{{int}}}, {{{int64_t}}}, {{{short}}}, {{{char}}}
|
||||||
|
|
@ -2010,16 +2010,16 @@ Operationally, a modad can be constructed to wrap-up and embody a given element.
|
||||||
Now, the interesting question is: //what does "join" mean?// --
|
Now, the interesting question is: //what does "join" mean?// --
|
||||||
*will it drill down?
|
*will it drill down?
|
||||||
*will it lift the contents of generated monads into the parent level, or attach them as new subtrees?
|
*will it lift the contents of generated monads into the parent level, or attach them as new subtrees?
|
||||||
*will the function get to see {{{Record}}} elements, or will it imediately see the "contents", the attributes or the children?
|
*will the function get to see {{{Record}}} elements, or will it immediately see the "contents", the attributes or the children?
|
||||||
|
|
||||||
!!!names, identity and typing
|
!!!names, identity and typing
|
||||||
It was a design decision that the GenNode shall not embodiy a readable type field, just a type selector within the variant to hold the actual data elements.
|
It was a design decision that the GenNode shall not embody a readable type field, just a type selector within the variant to hold the actual data elements.
|
||||||
This decision more or less limits the usefulness of simple values as children to those cases, where all children are of uniform type, or where we agree to deal with all children through variant visitation solely. Of course, we can still use simple values as attributes, since those are known and addressed by name. And we can use filtereing by type to limit access to some children of type record, since every record does indeed embody a symbolic type name. It must be that way, since otherwise, records would be pretty much useless as representation for any object like entity.
|
This decision more or less limits the usefulness of simple values as children to those cases, where all children are of uniform type, or where we agree to deal with all children through variant visitation solely. Of course, we can still use simple values as //attributes,// since those are known and addressed by name. And we can use filtering by type to limit access to some children of type {{{Record}}}, since every record does indeed embody a symbolic type name, an attribute named {{{"type"}}}. It must be that way, since otherwise, records would be pretty much useless as representation for any object like entity.
|
||||||
|
|
||||||
The discriminating ID of any GenNode can serve as a name, and indeed will be used as the name of an attribute within a record.
|
The discriminating ID of any GenNode can serve as a name, and indeed will be used as the name of an attribute within a record.
|
||||||
Now, the interesting question is: what constitues the full identity? Is it the ~ID-string? does it also include some kind of type information, so that two children with the same name, but different types would be considered different? And, moreover, we could even go as far as to make the path part of the identity, so that two otherwise identical elements would be different, when located at different positions within the graph. But since we did not rule out cyclic graphs, the latter idea would necessitate the notion of an //optimal path// --
|
Now, the interesting question is: what constitutes the full identity? Is it the ~ID-string? does it also include some kind of type information, so that two children with the same name, but different types would be considered different? And, moreover, we could even go as far as to make the path part of the identity, so that two otherwise identical elements would be different, when located at different positions within the graph. But since we did not rule out cyclic graphs, the latter idea would necessitate the notion of an //optimal path// --
|
||||||
|
|
||||||
A somewhat similar question is the ordering and uniqueness of children. While attributes -- due to the usage of the attribute node's ID as name-key -- are bound to be unique within a given Record, children within the scope of a record could be required to be unique too, making the scope a set. And, of course, children could be focribly ordered, or just retaining the initial ordering, or even be completely unordered. On a second thought, it seems wise not to impose any guarantees in that regard, beyond the simple notion of retaining an initial sequence order. All these more specific ordering properties can be considered the concern of some specific kinds of objects -- which then just happen to "supply" a list of children for symbolic representation as they see fit.
|
A somewhat similar question is the ordering and uniqueness of children. While attributes -- due to the usage of the attribute node's ID as name-key -- are bound to be unique within a given Record, children within the scope of a record could be required to be unique too, making the scope a set. And, of course, children could be forcibly ordered, or just retain the initial ordering, or even be completely unordered. On a second thought, it seems wise not to impose any guarantees in that regard, beyond the simple notion of retaining an initial sequence order, the way a »stable« sorting algorithm does. All these more specific ordering properties can be considered the concern of some specific kinds of objects -- which then just happen to "supply" a list of children for symbolic representation as they see fit.
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
<div title="Factories" modifier="Ichthyostega" created="200708100401" modified="201310132317" tags="def Concepts" changecount="6">
|
<div title="Factories" modifier="Ichthyostega" created="200708100401" modified="201310132317" tags="def Concepts" changecount="6">
|
||||||
|
|
@ -2219,7 +2219,7 @@ Of course, we can place other ~MObjects relative to some fork (that's the main r
|
||||||
&rarr; [[Anatomy of the high-level model|HighLevelModel]]
|
&rarr; [[Anatomy of the high-level model|HighLevelModel]]
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
<div title="ForwardIterator" modifier="Ichthyostega" created="200910312114" modified="200912190027" tags="Concepts def spec">
|
<div title="ForwardIterator" modifier="Ichthyostega" created="200910312114" modified="201507042115" tags="Concepts def spec" changecount="1">
|
||||||
<pre>The situation focussed by this concept is when an API needs to expose a sequence of results, values or objects, instead of just yielding a function result value. As the naive solution of passing an pointer or array creates coupling to internals, it was superseded by the ~GoF [[Iterator pattern|http://en.wikipedia.org/wiki/Iterator]]. Iteration can be implemented by convention, polymorphically or by generic programming; we use the latter approach.
|
<pre>The situation focussed by this concept is when an API needs to expose a sequence of results, values or objects, instead of just yielding a function result value. As the naive solution of passing an pointer or array creates coupling to internals, it was superseded by the ~GoF [[Iterator pattern|http://en.wikipedia.org/wiki/Iterator]]. Iteration can be implemented by convention, polymorphically or by generic programming; we use the latter approach.
|
||||||
|
|
||||||
!Lumiera Forward Iterator concept
|
!Lumiera Forward Iterator concept
|
||||||
|
|
@ -2237,6 +2237,17 @@ The Lumiera Forward Iterator concept is a blend of the STL iterators and iterato
|
||||||
|
|
||||||
Another notable difference to the STL iterators is the default ctor and the {{{bool}}} conversion. The latter allows using iterators painlessly within {{{for}}} and {{{while}}} loops; a default constructed iterator is equivalent to the STL container's {{{end()}}} value &mdash; indeed any //container-like// object exposing Lumiera Forward Iteration is encouraged to provide such an {{{end()}}}-function, additionally enabling iteration by {{{std::for_each}}} (or Lumiera's even more convenient {{{util::for_each()}}}).
|
Another notable difference to the STL iterators is the default ctor and the {{{bool}}} conversion. The latter allows using iterators painlessly within {{{for}}} and {{{while}}} loops; a default constructed iterator is equivalent to the STL container's {{{end()}}} value &mdash; indeed any //container-like// object exposing Lumiera Forward Iteration is encouraged to provide such an {{{end()}}}-function, additionally enabling iteration by {{{std::for_each}}} (or Lumiera's even more convenient {{{util::for_each()}}}).
|
||||||
|
|
||||||
|
!!!interoperation with the C++11 range-for construct
|
||||||
|
Lumiera Forward Iterators can be made to work together with the 'range for loop', as introduced with C++11. The preferred solution is to define the necessary free functions {{{begin}}} and {{{end}}} for ADL. This is best done on a per implementation base. We consider a generic solution not worth the effort. See {{{71167be9c9aaa}}}.
|
||||||
|
|
||||||
|
This is to say, these two concepts can be made to work together well. While, at a conceptual level, they are not really compatible, and build on a different understanding: The standard for-loop assumes //a container,// while our Forward Iterator Concept deals with //abstract data sources.//.
|
||||||
|
The user needs to understand the fine points of that conceptual difference:
|
||||||
|
* if you apply the range-`for` construct on a container, you can iterate as often as you like. Even if the iterators of that container are implemented in compliance with the Lumiera Forward Iterator concept.
|
||||||
|
* but if you apply the range-`for` construct on //a given iterator, // you can do so only once. There is no way to reset that iterator, other than obtaining a new one.
|
||||||
|
|
||||||
|
The bridge methods are usually defined so that the {{{end}}}-function just returns a default constructed iterator, which -- by concept -- is the marker for iteration end
|
||||||
|
|
||||||
|
|
||||||
!!Implementation notes
|
!!Implementation notes
|
||||||
''iter-adapter.hpp'' provides some helper templates for building Lumiera Forward Iterators.
|
''iter-adapter.hpp'' provides some helper templates for building Lumiera Forward Iterators.
|
||||||
* __~IterAdapter__ is the most flexible variant, intended for use by custom facilities. An ~IterAdapter maintains an internal back-link to a facilitiy exposing an iteration control API, which is accessed through free functions as extension point. This iteration control API is similar to C#, allowing to advance to the next result and to check the current iteration state.
|
* __~IterAdapter__ is the most flexible variant, intended for use by custom facilities. An ~IterAdapter maintains an internal back-link to a facilitiy exposing an iteration control API, which is accessed through free functions as extension point. This iteration control API is similar to C#, allowing to advance to the next result and to check the current iteration state.
|
||||||
|
|
@ -2305,13 +2316,17 @@ For this Lumiera design, we could consider making GOP just another raw media dat
|
||||||
&rarr;see in [[Wikipedia|http://en.wikipedia.org/wiki/Group_of_pictures]]
|
&rarr;see in [[Wikipedia|http://en.wikipedia.org/wiki/Group_of_pictures]]
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
<div title="GenNode" creator="Ichthyostega" modifier="Ichthyostega" created="201501171413" modified="201505081546" tags="Model GuiIntegration GuiPattern def draft" changecount="11">
|
<div title="GenNode" creator="Ichthyostega" modifier="Ichthyostega" created="201501171413" modified="201507031718" tags="Model GuiIntegration GuiPattern def draft" changecount="13">
|
||||||
<pre>//Abstract generic node element to build a ~DOM-like rendering of Lumiera's [[session model|HighLevelModel]].//
|
<pre>//Abstract generic node element to build a ~DOM-like rendering of Lumiera's [[session model|HighLevelModel]].//
|
||||||
GenNode elements are values, yet behave polymorphic. They are rather light-weight, have an well established identity and can be compared. They are //generic// insofar they encompass several heterogeneous ordering systems, which in themselves can not be subsumed into a single ordering hierarchy. The //purpose// of these generic nodes is to build a symbolic representation, known as [[external tree description|ExternalTreeDescription]], existing somewhere "outside", at a level where the fine points of ordering system relations do not really matter. Largely, this external description is not represented or layed down as a whole. Rather, it is used as a conceptual point of reference to describe //differences and changes.// Obviously, this means that parts of the altered structures have to appear in the description of the modifications. So, practically speaking, the prime purpose of GenNode elements is to appear as bits of information within a ''diff language'' to exchange such information of changes.
|
GenNode elements are values, yet behave polymorphic. They are rather light-weight, have an well established identity and can be compared. They are //generic// insofar they encompass several heterogeneous ordering systems, which in themselves can not be subsumed into a single ordering hierarchy. The //purpose// of these generic nodes is to build a symbolic representation, known as [[external tree description|ExternalTreeDescription]], existing somewhere "outside", at a level where the fine points of ordering system relations do not really matter. Largely, this external description is not represented or layed down as a whole. Rather, it is used as a conceptual reference frame to describe //differences and changes.// Obviously, this means that parts of the altered structures have to appear in the description of the modifications. So, practically speaking, the prime purpose of GenNode elements is to appear as bits of information within a ''diff language'' to exchange such information of changes.
|
||||||
|
|
||||||
To be more specific, within the actual model there are [[Placements|Placement]]. These refer to [[M-Objects|MObject]]. Which in turn rely on [[Assets|Asset]]. Moreover, we have some processing rules, and -- last but not least -- the "objects" encountered in the model have state, visible as attributes of atomic value type (integral, floating point, string, boolean, time, time ranges and [[quantised time entities|TimeQuant]]).
|
To be more specific, within the actual model there are [[Placements|Placement]]. These refer to [[M-Objects|MObject]]. Which in turn rely on [[Assets|Asset]]. Moreover, we have some processing rules, and -- last but not least -- the "objects" encountered in the model have state, visible as attributes of atomic value type (integral, floating point, string, boolean, time, time ranges and [[quantised time entities|TimeQuant]]).
|
||||||
A generic node may //represent any of these kind// -- and it may have ~GenNode children, forming a tree. Effectively all of this together makes ~GenNode a ''Monad''.
|
A generic node may //represent any of these kind// -- and it may have ~GenNode children, forming a tree. Effectively all of this together makes ~GenNode a ''Monad''.
|
||||||
|
|
||||||
|
GenNode elements are conceived as values, and can thus be treated as mutable or immutable; it is up to the user to express this intent through const correctness.
|
||||||
|
Especially the nested structures, i.e. a GenNode holding an embedded {{{diff::Record}}}, are by default immutable, but expose a object builder API for remoulding. This again places the actual decision about mutations into the usage context, since the remoulded Record has to be assigned explicitly.
|
||||||
|
|
||||||
|
|
||||||
!to reflect or not reflect
|
!to reflect or not reflect
|
||||||
When dealing with this external model representation, indeed there are some rather global concerns which lend themselves to a generic programming style. Simply because, otherwise, we'd end up explicating and thereby duplicating the structure of the model all over the code. Frequently, such a situation is quoted as the reason to demand introspection facilities on any data structure. We doubt this is a valid conclusion. Since introspection allows to accept just //any element// -- followed by an open-ended //reaction on the received type// -- we might arrive at the impression that our code reaches a maximum of flexibility and "openness". Unfortunately, this turns out to be a self-deception, since code to do any meaningful operation needs pre-established knowledge about the meaning of the data to be processed. More so, when, as in any hierarchical data organisation, the relevant meaning is attached to the structure itself, so consequently this pre-established knowledge tends to be scattered over several, superficially "open" handler functions. What looks open and flexible at first sight is in fact littered with obscure and scattered, non obvious additional presumptions.
|
When dealing with this external model representation, indeed there are some rather global concerns which lend themselves to a generic programming style. Simply because, otherwise, we'd end up explicating and thereby duplicating the structure of the model all over the code. Frequently, such a situation is quoted as the reason to demand introspection facilities on any data structure. We doubt this is a valid conclusion. Since introspection allows to accept just //any element// -- followed by an open-ended //reaction on the received type// -- we might arrive at the impression that our code reaches a maximum of flexibility and "openness". Unfortunately, this turns out to be a self-deception, since code to do any meaningful operation needs pre-established knowledge about the meaning of the data to be processed. More so, when, as in any hierarchical data organisation, the relevant meaning is attached to the structure itself, so consequently this pre-established knowledge tends to be scattered over several, superficially "open" handler functions. What looks open and flexible at first sight is in fact littered with obscure and scattered, non obvious additional presumptions.
|
||||||
This observation from coding practice gets us to the conclusion, that we do not really want to support the full notion of data and type introspection. We //do want// some kind of passive matching on structure, where the receiver explicitly has to supply structural presuppositions. In a fully functional language with a correspondingly rich type system, a partial function (pattern match) would be the solution of choice. Under the given circumstances, we're able to emulate this pattern based on our variant visitor -- which basically calls a different virtual function for each of the types possibly to be encountered "within" a ~GenNode.</pre>
|
This observation from coding practice gets us to the conclusion, that we do not really want to support the full notion of data and type introspection. We //do want// some kind of passive matching on structure, where the receiver explicitly has to supply structural presuppositions. In a fully functional language with a correspondingly rich type system, a partial function (pattern match) would be the solution of choice. Under the given circumstances, we're able to emulate this pattern based on our variant visitor -- which basically calls a different virtual function for each of the types possibly to be encountered "within" a ~GenNode.</pre>
|
||||||
|
|
@ -2433,7 +2448,7 @@ The workspace starts out with a single element, corresponding to the »model roo
|
||||||
Speaking of implementation, this state and update mechanics relies on two crucial provisions: Lumiera's framework for [[tree diff representation|TreeDiffModel]] and the ExternalTreeDescription, which is an abstracted, ~DOM-like rendering of the relevant parts of the session; this model tree is comprised of [[generic node elements|GenNode]] acting as proxy for [[calls into|SessionInterface]] the [[session model|HighLevelModel]] proper.
|
Speaking of implementation, this state and update mechanics relies on two crucial provisions: Lumiera's framework for [[tree diff representation|TreeDiffModel]] and the ExternalTreeDescription, which is an abstracted, ~DOM-like rendering of the relevant parts of the session; this model tree is comprised of [[generic node elements|GenNode]] acting as proxy for [[calls into|SessionInterface]] the [[session model|HighLevelModel]] proper.
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
<div title="GuiModelUpdate" creator="Ichthyostega" modifier="Ichthyostega" created="201410250121" modified="201503221633" tags="GuiIntegration GuiPattern design decision discuss draft" changecount="30">
|
<div title="GuiModelUpdate" creator="Ichthyostega" modifier="Ichthyostega" created="201410250121" modified="201506040022" tags="GuiIntegration GuiPattern design decision discuss draft" changecount="31">
|
||||||
<pre>Considerations regarding the [[structure of custom timeline widgets|GuiTimelineWidgetStructure]] highlight again the necessity of a clean separation of concerns and an "open closed design". For the purpose of updating the timeline(s) to reflect the HighLevelModel in Proc-Layer, several requirements can be identified
|
<pre>Considerations regarding the [[structure of custom timeline widgets|GuiTimelineWidgetStructure]] highlight again the necessity of a clean separation of concerns and an "open closed design". For the purpose of updating the timeline(s) to reflect the HighLevelModel in Proc-Layer, several requirements can be identified
|
||||||
* we need incremental updates: we must not start redrawing each and everything on each tiny change
|
* we need incremental updates: we must not start redrawing each and everything on each tiny change
|
||||||
* we need recursive programming, since this is the only sane way to deal with tree like nested structures.
|
* we need recursive programming, since this is the only sane way to deal with tree like nested structures.
|
||||||
|
|
@ -2468,6 +2483,9 @@ A relevant question to be settled is as to where the core of each change is cons
|
||||||
* we might, at the moment of performing the update, acquire a lock from the ProcDispatcher. The update process may then effectively query down into the session datastructure proper, even through the proxy of a diffing process. The obvious downside is that GUI response might block waiting on an extended operation in Proc, especially when a new build process was started meanwhile. A remedy might be to abort the update in such cases, since its effects will be obsoleted by the build process anyway.
|
* we might, at the moment of performing the update, acquire a lock from the ProcDispatcher. The update process may then effectively query down into the session datastructure proper, even through the proxy of a diffing process. The obvious downside is that GUI response might block waiting on an extended operation in Proc, especially when a new build process was started meanwhile. A remedy might be to abort the update in such cases, since its effects will be obsoleted by the build process anyway.
|
||||||
* alternatively, we might incorporate a complete snapshot of all information relevant for the GUI into the GuiModel. Update messages from Proc must be complete and self contained in this case, since our goal is to avoid callbacks. Following this scheme, the first stage of any update would be a push from Proc to the GuiModel, followed by a callback pull from within the individual widgets receiving the notification later. This is the approach we choose for the Lumiera GUI.
|
* alternatively, we might incorporate a complete snapshot of all information relevant for the GUI into the GuiModel. Update messages from Proc must be complete and self contained in this case, since our goal is to avoid callbacks. Following this scheme, the first stage of any update would be a push from Proc to the GuiModel, followed by a callback pull from within the individual widgets receiving the notification later. This is the approach we choose for the Lumiera GUI.
|
||||||
|
|
||||||
|
!!!information to represent and to derive
|
||||||
|
The purpose of the GuiModel is to represent an anchor point for the structures //actually relevant for the UI.// To put that into context, the model in the session is not bound to represent matters exactly in the way to be rendered within the GUI. All we can expect is for the //build process// -- upon completion -- to generate a view of the actually altered parts, detailing the information relevant for presentation. Thus we do retain an ExternalTreeDescription of all the information received this way within the GuiModel. Whenever a completed build process sends an updated state, we use the diff framework to determine the actually relevant differences -- both for triggering the corresponding GUI widgets, and for forwarding this focussed diff information to these widgets when they call back from the UI event thread to pull the actual changes.
|
||||||
|
|
||||||
!!!switch of typed sub-context
|
!!!switch of typed sub-context
|
||||||
When dealing with structural (tree) diffing, there is a specific twist regarding child nodes of mixed type: In the general case, we can not assume that all children of a given node are of the same kind. The classical example is (X)HTML, where a node has //attributes,// various //nested tags// and //nested text content.// The //generic node// thus must be modelled as having several collections of children -- both ordered and un-ordered collections are possible -- and the content of each such sub-collection is itself polymorphic. This constitutes a challenge for the representation of data within the tree diff format. These difficulties can be overcome as follows
|
When dealing with structural (tree) diffing, there is a specific twist regarding child nodes of mixed type: In the general case, we can not assume that all children of a given node are of the same kind. The classical example is (X)HTML, where a node has //attributes,// various //nested tags// and //nested text content.// The //generic node// thus must be modelled as having several collections of children -- both ordered and un-ordered collections are possible -- and the content of each such sub-collection is itself polymorphic. This constitutes a challenge for the representation of data within the tree diff format. These difficulties can be overcome as follows
|
||||||
#anything, even nested "raw" content is represented //as node//
|
#anything, even nested "raw" content is represented //as node//
|
||||||
|
|
@ -7503,7 +7521,7 @@ Thus no server and no network connection is needed. Simply open the file in your
|
||||||
* see [[Homepage|http://tiddlywiki.com]], [[Wiki-Markup|http://tiddlywiki.org/wiki/TiddlyWiki_Markup]]
|
* see [[Homepage|http://tiddlywiki.com]], [[Wiki-Markup|http://tiddlywiki.org/wiki/TiddlyWiki_Markup]]
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
<div title="TimeMutation" modifier="Ichthyostega" created="201101231344" modified="201105261700" tags="spec discuss draft">
|
<div title="TimeMutation" modifier="Ichthyostega" created="201101231344" modified="201506032222" tags="spec discuss draft" changecount="1">
|
||||||
<pre>Simple time points are just like values and thus easy to change. The difficulties arise when time values are to be //quantised to an existing time grid.// The first relevant point to note is that for quantised time values, the effect of a change can be disproportional to the cause. Small changes below the threshold might be accumulated, and a tiny change might trigger a jump to the next grid point. While this might be annoying, the yet more complex questions arise when we acknowledge that the amount of the change itself might be related to a time grid.
|
<pre>Simple time points are just like values and thus easy to change. The difficulties arise when time values are to be //quantised to an existing time grid.// The first relevant point to note is that for quantised time values, the effect of a change can be disproportional to the cause. Small changes below the threshold might be accumulated, and a tiny change might trigger a jump to the next grid point. While this might be annoying, the yet more complex questions arise when we acknowledge that the amount of the change itself might be related to a time grid.
|
||||||
|
|
||||||
The problem with modification of quantised values highlights an inner contradiction or conflicting goals within the design
|
The problem with modification of quantised values highlights an inner contradiction or conflicting goals within the design
|
||||||
|
|
@ -7579,7 +7597,7 @@ Rationale: allowing mutations for Time bears the danger of making ~TimeVar obsol
|
||||||
* err, because MObject will include a Duration separate from the start time in the Placement, Duration needs to be mutable too
|
* err, because MObject will include a Duration separate from the start time in the Placement, Duration needs to be mutable too
|
||||||
|
|
||||||
!!!usage considerations
|
!!!usage considerations
|
||||||
{{red{Question 5/11}}} when moving a clip taken from 50fps media, the new position might be quantised to the 50fps grid established by the media, while the target timeline runs with 25fps, allowing for finer adjustments based on the intermediate frames present in the source material.
|
{{red{Question 5/11}}} when moving a clip taken from 50fps media, the new position might be quantised to the 50fps grid established by the media, even when the target timeline runs with 25fps, allowing for finer adjustments based on the intermediate frames present in the source material.
|
||||||
|
|
||||||
!!!design draft
|
!!!design draft
|
||||||
The special focus of this problem seems to lead itself to a __visitor pattern__ based implementation. Because the basic hierarchy of applicable types is fixed, but the behaviour is open ended (and not yet fully determined). A conventional implementation would scatter this behaviour over all the time entities, thus making it hard to understand and reason about. The classical ~GoF cyclic visitor solution to the contrary allows us to arrange closely related behaviour into thematically grouped visitor classes. As a plus, the concrete action can be bound dynamically, allowing for more flexibility when it comes to dealing with the intricate situations when a quantised time span (= a clip) recieves a quantised mutation (= is re-alligend to a possibly different frame grid)
|
The special focus of this problem seems to lead itself to a __visitor pattern__ based implementation. Because the basic hierarchy of applicable types is fixed, but the behaviour is open ended (and not yet fully determined). A conventional implementation would scatter this behaviour over all the time entities, thus making it hard to understand and reason about. The classical ~GoF cyclic visitor solution to the contrary allows us to arrange closely related behaviour into thematically grouped visitor classes. As a plus, the concrete action can be bound dynamically, allowing for more flexibility when it comes to dealing with the intricate situations when a quantised time span (= a clip) recieves a quantised mutation (= is re-alligend to a possibly different frame grid)
|
||||||
|
|
@ -7929,7 +7947,7 @@ Used this way, diff representation helps to separate structure and raw data in e
|
||||||
:Chunks of raw data are attached inline to the structural diff, assuming that each element implicitly knows the kind of data to expect
|
:Chunks of raw data are attached inline to the structural diff, assuming that each element implicitly knows the kind of data to expect
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
<div title="TreeDiffImplementation" creator="Ichthyostega" modifier="Ichthyostega" created="201412210015" modified="201504290114" tags="Model GuiPattern design draft" changecount="31">
|
<div title="TreeDiffImplementation" creator="Ichthyostega" modifier="Ichthyostega" created="201412210015" modified="201507041449" tags="Model GuiPattern design draft" changecount="38">
|
||||||
<pre>//This page details decisions taken for implementation of Lumiera's diff handling framework//
|
<pre>//This page details decisions taken for implementation of Lumiera's diff handling framework//
|
||||||
This topic is rather abstract, since diff handling is multi purpose within Lumiera: Diff representation is seen as a meta language and abstraction mechanism; it enables tight collaboration without the need to tie and tangle the involved implementation data structures. Used this way, diff representation reduces coupling and helps to cut down overall complexity -- so to justify the considerable amount of complexity seen within the diff framework implementation.
|
This topic is rather abstract, since diff handling is multi purpose within Lumiera: Diff representation is seen as a meta language and abstraction mechanism; it enables tight collaboration without the need to tie and tangle the involved implementation data structures. Used this way, diff representation reduces coupling and helps to cut down overall complexity -- so to justify the considerable amount of complexity seen within the diff framework implementation.
|
||||||
|
|
||||||
|
|
@ -7982,6 +8000,18 @@ This design prefers the //pull// approach, with a special twist: we provide a co
|
||||||
!!!representation of objects
|
!!!representation of objects
|
||||||
It should be noted, that the purpose of this whole architecture is to deal with »remote« stuff -- things we somehow need to refer and deal with, but nothing we can influence immediately, right here: every actual manipulation has to be turned into a message and sent //elsewhere.// This is the only context, where some, maybe even partial, generic and introspective object representation makes sense.
|
It should be noted, that the purpose of this whole architecture is to deal with »remote« stuff -- things we somehow need to refer and deal with, but nothing we can influence immediately, right here: every actual manipulation has to be turned into a message and sent //elsewhere.// This is the only context, where some, maybe even partial, generic and introspective object representation makes sense.
|
||||||
|
|
||||||
|
{{red{open questions 6/15}}}
|
||||||
|
* do we need to //alter// object contents -- or do we just replace?
|
||||||
|
* to what degree is the distinction between attributes and children even relevant -- beyond the ability to address attributes by-name?
|
||||||
|
* how do we describe an object from scratch? &larr;''object builder''
|
||||||
|
* how do we represent the break between attributes and children in this linearised description?
|
||||||
|
** using a separator element?
|
||||||
|
** by convention through the element names? &larr; ''This''
|
||||||
|
** as additional metadata information sent beforehand?
|
||||||
|
* we need an object-reference element, since we do not want to copy whole subtrees while processing a diff
|
||||||
|
|
||||||
|
"Objects" can be spelled out literally in code. We care to make the respective ctor syntax expressive enough. For nested objects, i.e. values of type {{{diff::Record}}}, a dedicated object builder notation is provided, because this is the point, where the syntax gets convoluted
|
||||||
|
|
||||||
Within this framework, we represent //object-like// entities through a special flavour of the GenNode: Basically, an object is a flat collection of children, yet given in accordance to a distinct protocol. The relevant ''meta'' information is spelled out first, followed by the ''attributes'' and finally the ''children''. The distinction between these lies in the mode of handling. Meta information is something we need to know before we're able to deal with the actual stuff. Prominent example is the type of the object. Attributes are considered unordered, and will typically be addressed by-name. Children are an ordered collection of recursive instances of the same data structure. (Incidentally, we do not rule out the possibility that also an attribute holds a recursive subtree; only the mode of access is what makes the distinction).
|
Within this framework, we represent //object-like// entities through a special flavour of the GenNode: Basically, an object is a flat collection of children, yet given in accordance to a distinct protocol. The relevant ''meta'' information is spelled out first, followed by the ''attributes'' and finally the ''children''. The distinction between these lies in the mode of handling. Meta information is something we need to know before we're able to deal with the actual stuff. Prominent example is the type of the object. Attributes are considered unordered, and will typically be addressed by-name. Children are an ordered collection of recursive instances of the same data structure. (Incidentally, we do not rule out the possibility that also an attribute holds a recursive subtree; only the mode of access is what makes the distinction).
|
||||||
|
|
||||||
!!!handling of actual mutation
|
!!!handling of actual mutation
|
||||||
|
|
@ -7994,7 +8024,7 @@ Within the context of GuiModelUpdate, we discern two distinct situations necessi
|
||||||
the second case is what poses the real challenge in terms of writing well organised code. Since in that case, the receiver side has to translate generic diff verbs into operations on hard wired language level data structures -- structures, we can not control, predict or limit beforhand. We deal with this situation by introducing a specific intermediary, the &rarr; TreeMutator.
|
the second case is what poses the real challenge in terms of writing well organised code. Since in that case, the receiver side has to translate generic diff verbs into operations on hard wired language level data structures -- structures, we can not control, predict or limit beforhand. We deal with this situation by introducing a specific intermediary, the &rarr; TreeMutator.
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
<div title="TreeDiffModel" creator="Ichthyostega" modifier="Ichthyostega" created="201410270313" modified="201505310130" tags="Model GuiPattern spec draft" changecount="54">
|
<div title="TreeDiffModel" creator="Ichthyostega" modifier="Ichthyostega" created="201410270313" modified="201506072246" tags="Model GuiPattern spec draft" changecount="61">
|
||||||
<pre>for the purpose of handling updates in the GUI timeline display efficiently, we need to determine and represent //structural differences//
|
<pre>for the purpose of handling updates in the GUI timeline display efficiently, we need to determine and represent //structural differences//
|
||||||
This leads to what could be considered the very opposite of data-centric programming. Instead of embody »the truth« into a central data model with predefined layout, we base our achitecture on a set of actors and their collaboration. In the mentioned example this would be the high-level view in the Session, the Builder, the UI-Bus and the presentation elements within the timeline view. Underlying to each such collaboration is a shared conception of data. There is no need to //actually represent that data// -- it can be conceived to exist in a more descriptive, declarative [[external tree description (ETD)|ExternalTreeDescription]]. In fact, what we //do represent// is a ''diff'' against such an external rendering.
|
This leads to what could be considered the very opposite of data-centric programming. Instead of embody »the truth« into a central data model with predefined layout, we base our achitecture on a set of actors and their collaboration. In the mentioned example this would be the high-level view in the Session, the Builder, the UI-Bus and the presentation elements within the timeline view. Underlying to each such collaboration is a shared conception of data. There is no need to //actually represent that data// -- it can be conceived to exist in a more descriptive, declarative [[external tree description (ETD)|ExternalTreeDescription]]. In fact, what we //do represent// is a ''diff'' against such an external rendering.
|
||||||
|
|
||||||
|
|
@ -8041,19 +8071,30 @@ Thus, for our specific usage scenario, the foremost relevant question is //how t
|
||||||
__Implementation note__:The representation chosen here uses terms of constant size for the individual diff steps; in most cases, the argument is redundant and can be used for verification when applying the diff -- with the exception of the {{{ins}}} term, where it actually encodes additional information. Especially the {{{find}}}-representation is a compromise, since we encode as "search for the term a~~5~~ and insert it at curent position". The more obvious rendering -- "push term a~~4~~ back by +1 steps" -- requires an additional integer argument not neccesary for any of the other diff verbs, defeating a fixed size value implementation.
|
__Implementation note__:The representation chosen here uses terms of constant size for the individual diff steps; in most cases, the argument is redundant and can be used for verification when applying the diff -- with the exception of the {{{ins}}} term, where it actually encodes additional information. Especially the {{{find}}}-representation is a compromise, since we encode as "search for the term a~~5~~ and insert it at curent position". The more obvious rendering -- "push term a~~4~~ back by +1 steps" -- requires an additional integer argument not neccesary for any of the other diff verbs, defeating a fixed size value implementation.
|
||||||
|
|
||||||
!!!extension to tree changes
|
!!!extension to tree changes
|
||||||
Basically we could send messages for recursive descent right after each {{{pick}}} token -- yet, while minimal, such a representation would be unreadable, and requires a dedicated stack storage on both sides. Thus we arrange for the //recursive treatment of children// to be sent //postfix,// after the messages for the current node. Recursive descent is indicated by explicit (and slightly redundant) //bracketing tokens://
|
Diff description and diff handling can be applied to tree-like data structures as well. Some usages of textual comparison (e.g. diffing of programming language texts) are effectively working on tree structures -- yet they do not build on the structure of the diffed data explicitly. But if we represent the data structures symbolically, the change form text diffing to data structure diffing is marginal. The only relevant change is to handle embedded recursive diff descriptions of the child nodes. As it stands, each node or "object" can be represented as a list of properties plus the attachment of child nodes. This list can be treated with the methods developed for a stream of text tokes.
|
||||||
*{{{open}}}(node-ID) : recurse into the designated node, which must be present already as result of the preceding changes
|
|
||||||
*{{{close}}}(node-ID) : close the current node context and return one step up; the node-ID is given for verification, but can be used to restore the working position at parent level
|
Basically the transition from text diffing to changes on data structures is achieved by exchanging the //type of the tokens.// Instead of words, or lines of text, we now use //data elements.// To do so, we introduce a symbolic ExternalTreeDescription of tree-like core data structures. The elementary token element used in this tree diff, the GenNode, embodies either simple plain data elements (numbers, strings, booleans, id-hashes, time values) -- or it describes a //recursive data element,// given as {{{Record<GenNode>}}}. Such a recursive data element describes object-like entities as a sequence of metadata, named attributes and ordered child-nodes -- it is handled in two phases: the first step is to treat the presence and ordering of child data elements, insertions and deletes. The second phase opens for each structurally changed child data element a recursive bracketing construct, as indicated by explicit (and slightly redundant) //bracketing tokens://
|
||||||
In addition, we might consider to introduce up/down folding primitives
|
*{{{mut}}}(node-ID) : recurse into the designated node, which must be present already as result of the preceding changes. The following diff tokens describe //mutations// of the child
|
||||||
*{{{fold}}}(//num//, node-ID) : pick the next //num// elements and fold them down into a new child with given node-ID
|
*{{{emu}}}(node-ID) : close the current node context and return one step up; the node-ID is given for verification, but can be used to restore the working position at parent level
|
||||||
|
In addition, in a future extension, we might consider to introduce up/down folding primitives
|
||||||
|
*{{{fold}}}(node-ID) : pick the following elements and fold them down into a new child with given node-ID. The downfolding continues until the next {{{emu}}} token
|
||||||
*{{{lift}}}(node-ID) : remove the next child node, which must be node-ID, and insert its children at current position
|
*{{{lift}}}(node-ID) : remove the next child node, which must be node-ID, and insert its children at current position
|
||||||
|
|
||||||
|
Since the bracketing construct for mutation of child structures bears the ID of the parent, a certain degree of leeway is introduced. In theory, we could always open such a bracketing construct right after the {{{pick}}} token accepting the parent -- yet, while minimal, such a strictly depth-first representation would be hard to read -- so we allow to group the recursive treatement of children //post-fix,// after the messages for the current node. In a similar vein, we introduce another token to describe a //short-cut://
|
||||||
|
*{{{after}}}(node-ID) : fast-forward through the sequence of elements at current level until the position after the designated element.
|
||||||
|
To complement this language construct, we define some special, magical (meta) element-~IDs
|
||||||
|
*{{{_CHILD_}}} : marks an //unnamed// ID. Mostly, the implementation exploits this specific marker to distinguish between nodes which are (named) attributes of an object, and real children
|
||||||
|
*{{{_THIS_}}} : can be used to refer to the immediately preceding element without knowing its name. Typically used to open a {{{mut(_THIS_)}}} ... {{{emu(_THIS_)}}} bracket to populate a newly inserted object
|
||||||
|
*{{{_ATTRIBS_}}} : can be used to jump {{{after(_ATTRIBS_)}}} when mutating the contents of an object. So the following diff verbs will immediately start working on the children
|
||||||
|
*{{{_END_}}} : likewise can be used to jump {{{after(_END_)}}} to start appending new elements without caring for the existing current content.
|
||||||
|
All these additional language constructs aren't strictly necessary, but widen the usability of the langauge, also to cover the description of incomplete or fuzzy diffs.
|
||||||
|
|
||||||
!!!deriving conventional representations
|
!!!deriving conventional representations
|
||||||
On receiving the terms of this "diff language", it is possible to generate the well known and more conventional diff representations,
|
On receiving the terms of this "diff language", it is possible to generate the well known and more conventional diff representations,
|
||||||
i.e. a ''unified diff'' or the ''predicate notation'' used above to describe the list diffing algorithm, just by accumulating changes.
|
i.e. a ''unified diff'' or the ''predicate notation'' used above to describe the list diffing algorithm, just by accumulating changes.
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
<div title="TreeMutator" creator="Ichthyostega" modifier="Ichthyostega" created="201503292115" modified="201505310130" tags="Model Concepts GuiPattern design draft" changecount="50">
|
<div title="TreeMutator" creator="Ichthyostega" modifier="Ichthyostega" created="201503292115" modified="201505312250" tags="Model Concepts GuiPattern design draft" changecount="52">
|
||||||
<pre>The TreeMutator is an intermediary to translate a generic structure pattern into heterogeneous local invocation sequences.
|
<pre>The TreeMutator is an intermediary to translate a generic structure pattern into heterogeneous local invocation sequences.
|
||||||
|
|
||||||
!Motivation
|
!Motivation
|
||||||
|
|
@ -8106,7 +8147,7 @@ This construction pattern can be extended to offer several optional extension ho
|
||||||
* how to integrate typed children
|
* how to integrate typed children
|
||||||
|
|
||||||
!!!working with children
|
!!!working with children
|
||||||
Handling tree structured object data imposes some additional constraints, in comparision to generic changes done to a flat list. One notable difference is that there are pre-existing //attributes,// which can not be added and deleted, are known by-name, not by positional order. Another point worth noting is the fact that child objects may be segregated into several collections by type. Since our goal is to provide an intermediary with the ability to map to arbitrary structures, we need to define the primitive operations necessary for implementing the structural operations represented in the form of a diff
|
Handling tree structured object data imposes some additional constraints, in comparision to generic changes done to a flat list. One notable difference is that there are pre-existing //attributes,// which can not be added and deleted, are known by-name, not by positional order. Another point worth noting is the fact that child objects may be segregated into several collections by type. Since our goal is to provide an intermediary with the ability to map to arbitrary structures, we need to define the primitive operations necessary for implementing the concrete structural operations represented in the form of a diff
|
||||||
* add a child
|
* add a child
|
||||||
* remove a child
|
* remove a child
|
||||||
* step to the next child
|
* step to the next child
|
||||||
|
|
@ -8118,7 +8159,7 @@ All these basic operations are implicitly stateful, i.e. they work against an as
|
||||||
To ease the repetitive part of the wiring, which is necessary for each individual application case, we can allow for some degree of //duck typing,// as far as building the TreeMutator is concerned. If there is a type, which provides the above mentioned functions for child management, these can be hooked up automatically into a suitable adapter. Otherwise, the client may supply closures, using the same definition pattern as shown for the attributes above. Here, the ID argument is optional and denotes a //type filter,// whereas the closure itself must accept a name-ID argument. The purpose of this construction is the ability to manage collections of similar children. For example
|
To ease the repetitive part of the wiring, which is necessary for each individual application case, we can allow for some degree of //duck typing,// as far as building the TreeMutator is concerned. If there is a type, which provides the above mentioned functions for child management, these can be hooked up automatically into a suitable adapter. Otherwise, the client may supply closures, using the same definition pattern as shown for the attributes above. Here, the ID argument is optional and denotes a //type filter,// whereas the closure itself must accept a name-ID argument. The purpose of this construction is the ability to manage collections of similar children. For example
|
||||||
{{{
|
{{{
|
||||||
.addChild("Fork"), [&](string type, string id) {
|
.addChild("Fork"), [&](string type, string id) {
|
||||||
ForkType kind = determineForkkType(type);
|
ForkType kind = determineForkType(type);
|
||||||
this.forks_.push_back(MyForkImpl(kind, id);
|
this.forks_.push_back(MyForkImpl(kind, id);
|
||||||
})
|
})
|
||||||
.mutateChild("Fork"), [&](string id) {
|
.mutateChild("Fork"), [&](string id) {
|
||||||
|
|
|
||||||
1088
wiki/thinkPad.ichthyo.mm
Normal file
1088
wiki/thinkPad.ichthyo.mm
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue