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:
parent
1913620f37
commit
536a3a94b9
2 changed files with 62 additions and 3 deletions
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue