add special iteration mechanism to visit enclosed child data

the rationale is that I deliberately do not want to provide
a mechanism to iterate "over all contents in stringified form".
Because this could be seen as an invitation to process GenNode-
datastructures in an imperative way. Please recall we do not
want that. Users shall either *match* contents (using a visitor),
or they are required to know the type of the contents beforehand.
Both cases favour structural and type based programming over
dynamic run-time based inspection of contents

The actual task prompting me to add this iteration mechanism
is that I want to build a diagnostic, which allows to verify
that a binding message was sent over the bus with some
specific parameter values.
This commit is contained in:
Fischlurch 2016-02-05 04:03:11 +01:00
parent 1913620f37
commit 536a3a94b9
2 changed files with 62 additions and 3 deletions

View file

@ -192,6 +192,18 @@ namespace diff{
X& get();
template<typename X>
X const& get() const;
/** visit _children_ of a nested `Record<GenNode>` */
Rec::scopeIter
childIter() const
{
const Rec* rec = unConst(this)->maybeGet<Rec>();
if (!rec)
return Rec::scopeIter();
else
return rec->scope();
}
};
@ -262,7 +274,7 @@ namespace diff{
/** @internal diagnostics helper. Include format-helper.cpp on use */
/** @internal diagnostics helper */
operator string() const
{
return "GenNode-"+string(idi)+"-"+string(data);
@ -310,6 +322,27 @@ namespace diff{
iterator end() const;
using ChildDataIter = TransformIter<Rec::scopeIter, DataCap const&>;
/** visit the _data_ of nested child elements
* @return an iterator over the DataCap elements of all children,
* in case this GenNode actually holds a Record.
* Otherwise an empty iterator.
* @note this iterator visits _only_ the children, which are
* by definition unnamed. It does _not_ visit attributes.
*/
friend ChildDataIter
childData (GenNode const& n)
{
return ChildDataIter{ n.data.childIter()
, [](GenNode const& child) ->DataCap const&
{
return child.data;
}
};
}
friend string
name (GenNode const& node)
{

View file

@ -76,7 +76,7 @@ namespace test{
* - 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
* - a special notation is provided to create "id references", which
* 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.
@ -222,7 +222,7 @@ namespace test{
CHECK (hamID.getHash() == ham.idi.getHash());
CHECK (contains (string(hamID), "spam")); // Lovely spam!
Ref ref1("egg bacon sausage and spam");
Ref ref1("egg bacon sausage and spam"); // empty placeholder
Ref ref2(ham);
CHECK (ref1.idi == ham.idi);
@ -328,6 +328,32 @@ namespace test{
CHECK (0 == iter.level());
CHECK (isnil (iter));
// another kind of iteration: shallow child data sequence
// note: exposing the DataCap of each child
auto child = childData(n);
CHECK (!isnil (child));
CHECK ('*' == child->get<char>());
++child;
CHECK ("★" == child->get<string>());
++child;
CHECK (almostEqual (PI, child->get<double>()));
++child;
CHECK ("ham" == child->get<Rec>().getType());
CHECK ("eggs" == child->get<Rec>().child(0).data.get<string>());
++child;
CHECK (TimeSpan(Time::ZERO, FSecs(23,25)) == child->get<TimeSpan>());
++child;
CHECK (42 == child->get<int64_t>());
++child;
CHECK (isnil (child));
}