the new design takes the old name
The second design from 2017, based on a pipeline builder, is now renamed `TreeExplorer` ⟼ `IterExplorer` and uses the memorable entrance point `lib::explore(<seq>)` ✔
This commit is contained in:
parent
d109f5e1fb
commit
130bc095d9
18 changed files with 187 additions and 214 deletions
|
|
@ -330,7 +330,7 @@ namespace lib {
|
|||
* The resulting iterator will hold an instance of ST, which thus
|
||||
* needs to be copyable and default constructible to the extent
|
||||
* this is required for the iterator as such.
|
||||
* @see IterExplorer an iterator monad built on top of IterStateWrapper
|
||||
* @see IterExplorer a pipeline builder framework on top of IterStateWrapper
|
||||
* @see iter-explorer-test.hpp
|
||||
* @see iter-adaptor-test.cpp
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@
|
|||
** capture extended facilities within the scope _enclosing_ the pipeline, as long
|
||||
** as this scope remains intact during the whole usage time of the pipeline.
|
||||
** - the resulting entity, an instantiation of the IterChainSearch template, is
|
||||
** not a generic TreeExplorer (builder). Be careful when using any builder
|
||||
** not a generic IterExplorer (builder). Be careful when using any builder
|
||||
** functions still accessible. The only functions meant to be used in
|
||||
** builder style are the IterChainSearch::search() variations.
|
||||
** - if you copy, the embedded state is copied alongside, but not
|
||||
|
|
@ -78,7 +78,7 @@
|
|||
|
||||
|
||||
#include "lib/error.hpp"
|
||||
#include "lib/iter-tree-explorer.hpp"
|
||||
#include "lib/iter-explorer.hpp"
|
||||
#include "lib/meta/util.hpp"
|
||||
|
||||
#include <utility>
|
||||
|
|
@ -102,7 +102,7 @@ namespace iter {
|
|||
auto
|
||||
buildSearchFilter (SRC&& dataSource)
|
||||
{
|
||||
return treeExplore (forward<SRC> (dataSource))
|
||||
return explore (forward<SRC> (dataSource))
|
||||
.mutableFilter();
|
||||
}
|
||||
|
||||
|
|
@ -116,7 +116,7 @@ namespace iter {
|
|||
|
||||
/**
|
||||
* @internal helper to rebind on inferred types.
|
||||
* @remark we use the TreeExplorer framework to assemble the processing pipeline
|
||||
* @remark we use the IterExplorer framework to assemble the processing pipeline
|
||||
* from suitable building blocks configured with some lambdas. However, we
|
||||
* also want to _inherit_ from this filter pipeline, so to expose the typical
|
||||
* iterator operations without much ado. Thus we use some (static) helper function
|
||||
|
|
@ -304,7 +304,7 @@ namespace iter {
|
|||
* container, or a [»State Core«](\ref lib::IterStateWrapper) object.
|
||||
* @warning if you capture the result of this call by an auto variable,
|
||||
* be sure to understand that invoking any further builder operation on
|
||||
* TreeExplorer will invalidate that variable (by moving it into the
|
||||
* IterExplorer will invalidate that variable (by moving it into the
|
||||
* augmented iterator returned from such builder call).
|
||||
*/
|
||||
template<class SRC>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
ITER-TREE-EXPLORER.hpp - building blocks for iterator evaluation strategies
|
||||
ITER-EXPLORER.hpp - building blocks for iterator evaluation strategies
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2017, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
|
@ -20,9 +20,9 @@
|
|||
|
||||
*/
|
||||
|
||||
/** @file iter-tree-explorer.hpp
|
||||
/** @file iter-explorer.hpp
|
||||
** Building tree expanding and backtracking evaluations within hierarchical scopes.
|
||||
** Based on the *Lumiera Forward Iterator* concept and using the basic IterAdaptor templates,
|
||||
** Based on the *Lumiera Forward Iterator* concept and using the basic IterAdapter templates,
|
||||
** these components allow to implement typical evaluation strategies, like conditional expanding
|
||||
** or depth-first exploration of a hierarchical structure. Since the access to this structure is
|
||||
** abstracted through the underlying iterator, what we effectively get is a functional datastructure.
|
||||
|
|
@ -30,39 +30,26 @@
|
|||
** itself (value semantics) -- similar to the IterStateWrapper, which is one of the basic helper templates
|
||||
** provided by iter-adapter.hpp.
|
||||
**
|
||||
** @remark as of 2017, this template, as well as the initial IterExplorer (draft from 2012) can be
|
||||
** seen as steps towards designing a framework of building blocks for tree expanding and
|
||||
** backtracking algorithms. Due to the nature of Lumiera's design, we repeatedly encounter
|
||||
** this kind of computation pattern, when it comes to matching flexible configuration against
|
||||
** a likewise hierarchical and rules based model. To keep the code base maintainable,
|
||||
** we deem it crucial to reduce the inherent complexity in such algorithms by clearly
|
||||
** separate the _mechanics of evaluation_ from the actual logic of the target domain.
|
||||
** @remark historically, this template, as well as the initial IterExplorer (draft from 2012) can be
|
||||
** seen as steps towards a framework of building blocks for tree expanding and backtracking
|
||||
** algorithms — driven by a persistent need for this computation pattern, which lies in the
|
||||
** nature of Lumiera's design: matching flexible configuration against a likewise hierarchical
|
||||
** and rules based model.
|
||||
**
|
||||
** # Iterators as Monad
|
||||
** # Background: Iterators as Monad
|
||||
** The fundamental idea behind the implementation technique used here is the _Monad pattern_
|
||||
** known from functional programming. A Monad is a container holding some arbitrarily typed base value; the monad can
|
||||
** be seen as "amplifying" and enhancing the contained base value by attaching additional properties or capabilities
|
||||
** be seen as „amplifying“ and enhancing the contained base value by attaching additional properties or capabilities
|
||||
** This is a rather detached concept with a wide variety of applications (things like IO state, parsers, combinators,
|
||||
** calculations with exception handling but also simple data structures like lists or trees). The key point with any
|
||||
** monad is the ability to _bind a function_ into the monad; this function will work on the _contained base values_
|
||||
** and produce a modified new monad instance. In the simple case of a list, "binding" a function basically means
|
||||
** to _map the function onto_ the elements in the list. (actually it means the `flatMap` operation)
|
||||
**
|
||||
** ## Rationale
|
||||
** The primary benefit of using the monad pattern is to separate the transforming operation completely from
|
||||
** the mechanics of applying that operation and combining the results. More specifically, we rely on an iterator
|
||||
** to represent an abstracted source of data and we expose the combined and transformed results again as such
|
||||
** an abstracted data sequence. While the transformation to apply can be selected at runtime (as a functor),
|
||||
** the monad pattern defines a sane way to represent partial evaluation state without requiring a container
|
||||
** for intermediary results. This is especially helpful when
|
||||
** - a flexible and unspecific source data structure needs to be processed
|
||||
** - and this evaluation needs to be done asynchronously and in parallel (no locking, immutable data)
|
||||
** - and a partial evaluation needs to be stored as continuation (not relying on the stack for partial results)
|
||||
** to _map the function onto_ the elements in the list. (strictly speaking, it means the `flatMap` operation)
|
||||
**
|
||||
** # A Pipeline builder
|
||||
** Based on such concepts, structures and evaluation patterns, the TreeExplorer serves the purpose to provide
|
||||
** Based on such concepts, structures and evaluation patterns, the IterExplorer serves the purpose to provide
|
||||
** building blocks to assemble a _processing pipeline_, where processing will happen _on demand,_ while iterating.
|
||||
** TreeExplorer itself is both a Lumiera Forward Iterator based on some wrapped data source, and at the same time
|
||||
** IterExplorer itself is both a Lumiera Forward Iterator based on some wrapped data source, and at the same time
|
||||
** it is a builder to chain up processing steps to work on the data pulled from that source. These processing steps
|
||||
** are attached as _decorators_ wrapping the source, in the order the corresponding builder functions were invoked.
|
||||
** - the *expand operation* installs a function to consume one element and replace it by the sequence of elements
|
||||
|
|
@ -75,12 +62,20 @@
|
|||
** - in concert, expand- and transform operation allow to build hierarchy evaluation algorithms without exposing
|
||||
** any knowledge regarding the concrete hierarchy used and explored as data source.
|
||||
**
|
||||
** In itself, the TreeExplorer is an iterator with implementation defined type (all operations being inlined).
|
||||
** In itself, the IterExplorer is an iterator with implementation defined type (all operations being inlined).
|
||||
** But it is possible to package this structure behind a conventional iteration interface with virtual functions.
|
||||
** By invoking the terminal builder function TreeExplorer::asIterSource(), the iterator compound type, as created
|
||||
** By invoking the terminal builder function IterExplorer::asIterSource(), the iterator compound type, as created
|
||||
** thus far, will be moved into a heap allocation, returning a front-end based on IterSource. In addition, the
|
||||
** actually returned type, IterExplorerSource, exposes the `expandChildren()` operation as discussed above.
|
||||
**
|
||||
** ## Rationale
|
||||
** This design leads to a complete separation of the transforming operation from the mechanics how to apply that
|
||||
** operation and combine the results. More specifically, we rely on an iterator to represent an abstracted source
|
||||
** of data and we expose the combined and transformed results again as such an abstracted data sequence. Thereby,
|
||||
** a trend towards separation of concerns is introduced; the data source remains opaque, while the manipulation
|
||||
** to apply can be selected at runtime or written inline as Lambda. The iterator itself is a self-contained
|
||||
** value and represents partial evaluation state without requiring a container for intermediary results.
|
||||
**
|
||||
** ## some implementation details
|
||||
** The builder operations assemble a heavily nested type, each builder call thereby adding yet another layer of
|
||||
** subclassing. The templates involved into this build process are _specialised_, as driven by the actual functor
|
||||
|
|
@ -94,22 +89,19 @@
|
|||
** of the newly built subclass object. The previously existing pipeline is defunct after that
|
||||
** move; if you captured it into a variable, be sure to capture the _result_ of the new
|
||||
** builder operation as well and don't use the old variable anymore. Moreover, it should
|
||||
** be ensured that any "state core" used within TreeExplorer has an efficient move ctor;
|
||||
** be ensured that any "state core" used within IterExplorer has an efficient move ctor;
|
||||
** including RVO, the compiler is typically able to optimise such move calls away altogether.
|
||||
**
|
||||
** @see IterTreeExplorer_test
|
||||
** @see IterExplorer_test
|
||||
** @see iter-adapter.hpp
|
||||
** @see itertools.hpp
|
||||
** @see IterSource (completely opaque iterator)
|
||||
**
|
||||
** @warning as of 4/2023 the alternative Monad-style iterator framework "iter-explorer" will be retracted
|
||||
** and replaced by this design here, which will then be renamed into IterExplorer //////////////////////////////TICKET #1276
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
#ifndef LIB_ITER_TREE_EXPLORER_H
|
||||
#define LIB_ITER_TREE_EXPLORER_H
|
||||
#ifndef LIB_ITER_EXPLORER_H
|
||||
#define LIB_ITER_EXPLORER_H
|
||||
|
||||
|
||||
#include "lib/error.hpp"
|
||||
|
|
@ -333,7 +325,7 @@ namespace lib {
|
|||
|
||||
|
||||
|
||||
namespace { // TreeExplorer traits
|
||||
namespace { // IterExplorer traits
|
||||
|
||||
using meta::enable_if;
|
||||
using meta::disable_if;
|
||||
|
|
@ -394,11 +386,11 @@ namespace lib {
|
|||
};
|
||||
|
||||
|
||||
/** decide how to adapt and embed the source sequence into the resulting TreeExplorer */
|
||||
/** decide how to adapt and embed the source sequence into the resulting IterExplorer */
|
||||
template<class SRC, typename SEL=void>
|
||||
struct _DecoratorTraits
|
||||
{
|
||||
static_assert (!sizeof(SRC), "Can not build TreeExplorer: Unable to figure out how to iterate the given SRC type.");
|
||||
static_assert (!sizeof(SRC), "Can not build IterExplorer: Unable to figure out how to iterate the given SRC type.");
|
||||
};
|
||||
|
||||
template<class SRC>
|
||||
|
|
@ -473,7 +465,7 @@ namespace lib {
|
|||
using pointer = typename ValueTypeBinding<CommonType>::pointer;
|
||||
};
|
||||
|
||||
}//(End) TreeExplorer traits
|
||||
}//(End) IterExplorer traits
|
||||
|
||||
|
||||
|
||||
|
|
@ -484,12 +476,12 @@ namespace lib {
|
|||
constexpr auto ACCEPT_ALL = [](auto){return true;};
|
||||
|
||||
/**
|
||||
* @internal technical details of binding a functor into the TreeExplorer.
|
||||
* @internal technical details of binding a functor into the IterExplorer.
|
||||
* Notably, this happens when adapting an _"expansion functor"_ to allow expanding a given element
|
||||
* from the TreeExploer (iterator) into a sequence of child elements. A quite similar situation
|
||||
* arises when binding a _transformation function_ to be mapped onto each result element.
|
||||
*
|
||||
* The TreeExplorer::expand() operation accepts various flavours of functors, and depending on
|
||||
* The IterExplorer::expand() operation accepts various flavours of functors, and depending on
|
||||
* the signature of such a functor, an appropriate adapter will be constructed here, allowing to
|
||||
* write a generic Expander::expandChildren() operation. The following details are handled here:
|
||||
* - detect if the passed functor is generic, or a regular "function-like" entity.
|
||||
|
|
@ -602,7 +594,7 @@ namespace lib {
|
|||
|
||||
/**
|
||||
* @internal Base of pipe processing decorator chain.
|
||||
* TreeExplorer allows to create a stack out of various decorating processors
|
||||
* IterExplorer allows to create a stack out of various decorating processors
|
||||
* - each decorator is itself a _"state core"_, adding some on-demand processing
|
||||
* - each wraps and adapts a source iterator, attaching to and passing-on the iteration logic
|
||||
* Typically each such layer is configured with actual functionality provided as lambda or functor.
|
||||
|
|
@ -611,7 +603,7 @@ namespace lib {
|
|||
* call, where some "expansion layer" consumes the current element and replaces it by an expanded
|
||||
* series of new elements. Other layers might need to sync to this operation, and thus it is passed
|
||||
* down the chain. For that reason, we need a dedicated BaseAdapter to adsorb such chained calls.
|
||||
* @remark when building the TreeExplorer, the to-be-wrapped source is fed down into its place
|
||||
* @remark when building the IterExplorer, the to-be-wrapped source is fed down into its place
|
||||
* within BaseAdapter. For that reason, it is not sufficient just to lift the copy ctors
|
||||
* of the base (as inheriting the base class ctors would do). Rather, we need dedicated
|
||||
* further copy ctors to clone and move from the _undecorated base type._
|
||||
|
|
@ -630,7 +622,7 @@ namespace lib {
|
|||
|
||||
|
||||
/**
|
||||
* @internal Decorator for TreeExplorer adding the ability to "expand children".
|
||||
* @internal Decorator for IterExplorer adding the ability to "expand children".
|
||||
* The expandChildren() operation is the key element of a depth-first evaluation: it consumes
|
||||
* one element and performs a preconfigured _expansion functor_ on that element to yield
|
||||
* its "children". These are given in the form of another iterator, which needs to be
|
||||
|
|
@ -652,7 +644,7 @@ namespace lib {
|
|||
* bindings of the passed raw functor, one to work on the source sequence, and the other
|
||||
* one to work on the result sequence of a recursive child expansions; these two sequences
|
||||
* need not be implemented in the same way, which simplifies the definition of algorithms.
|
||||
* @tparam SRC the wrapped source iterator, typically a TreeExplorer or nested decorator.
|
||||
* @tparam SRC the wrapped source iterator, typically a IterExplorer or nested decorator.
|
||||
* @tparam FUN the concrete type of the functor passed. Will be dissected to find the signature
|
||||
*/
|
||||
template<class SRC, class RES>
|
||||
|
|
@ -677,7 +669,7 @@ namespace lib {
|
|||
|
||||
template<typename FUN>
|
||||
Expander (SRC&& parentExplorer, FUN&& expandFunctor)
|
||||
: SRC{move (parentExplorer)} // NOTE: slicing move to strip TreeExplorer (Builder)
|
||||
: SRC{move (parentExplorer)} // NOTE: slicing move to strip IterExplorer (Builder)
|
||||
, expandRoot_ {_FunTraits<FUN,SRC> ::adaptFunctor (forward<FUN> (expandFunctor))} // adapt to accept SRC&
|
||||
, expandChild_{_FunTraits<FUN,ResIter>::adaptFunctor (forward<FUN> (expandFunctor))} // adapt to accept RES&
|
||||
, expansions_{}
|
||||
|
|
@ -867,7 +859,7 @@ namespace lib {
|
|||
|
||||
|
||||
/**
|
||||
* @internal Decorator for TreeExplorer to map a transformation function on all results.
|
||||
* @internal Decorator for IterExplorer to map a transformation function on all results.
|
||||
* The transformation function is invoked on demand, and only once per item to be treated,
|
||||
* storing the treated result into an universal value holder buffer. The given functor
|
||||
* is adapted in a similar way as the "expand functor", so to detect and convert the
|
||||
|
|
@ -896,7 +888,7 @@ namespace lib {
|
|||
|
||||
template<typename FUN>
|
||||
Transformer (SRC&& dataSrc, FUN&& transformFunctor)
|
||||
: SRC{move (dataSrc)} // NOTE: slicing move to strip TreeExplorer (Builder)
|
||||
: SRC{move (dataSrc)} // NOTE: slicing move to strip IterExplorer (Builder)
|
||||
, trafo_{_FunTraits<FUN,SRC>::adaptFunctor (forward<FUN> (transformFunctor))}
|
||||
{ }
|
||||
|
||||
|
|
@ -953,7 +945,7 @@ namespace lib {
|
|||
|
||||
|
||||
/**
|
||||
* @internal Decorator for TreeExplorer to filter elements based on a predicate.
|
||||
* @internal Decorator for IterExplorer to filter elements based on a predicate.
|
||||
* Similar to the Transformer, the given functor is adapted as appropriate. However,
|
||||
* we require the functor's result type to be convertible to bool, to serve as approval test.
|
||||
* The filter predicate and thus the source iterator is evaluated _eagerly_, to establish the
|
||||
|
|
@ -1215,7 +1207,7 @@ namespace lib {
|
|||
|
||||
|
||||
/**
|
||||
* @internal Decorator for TreeExplorer to cut iteration once a predicate ceases to be true.
|
||||
* @internal Decorator for IterExplorer to cut iteration once a predicate ceases to be true.
|
||||
* Similar to Filter, the given functor is adapted as appropriate, yet is required to yield
|
||||
* a bool convertible result. The functor will be evaluated whenever the »exhausted« state
|
||||
* of the resulting iterator is checked, on each access and before iteration; this evaluation
|
||||
|
|
@ -1262,7 +1254,7 @@ namespace lib {
|
|||
|
||||
/**
|
||||
* Interface to indicate and expose the ability for _child expansion_.
|
||||
* This interface is used when packaging a TreeExplorer pipeline opaquely into IterSource.
|
||||
* This interface is used when packaging a IterExplorer pipeline opaquely into IterSource.
|
||||
* @remark the depth() call indicates the depth of the child expansion tree. This information
|
||||
* can be used by a "downstream" consumer to react according to a nested scope structure.
|
||||
* @todo expandChildren() should not return the value pointer.
|
||||
|
|
@ -1282,22 +1274,22 @@ namespace lib {
|
|||
};
|
||||
|
||||
/**
|
||||
* @internal Decorator to package a whole TreeExplorer pipeline suitably to be handled through
|
||||
* an IterSource based front-end. Such packaging is performed by the TreeExplorer::asIterSource()
|
||||
* @internal Decorator to package a whole IterExplorer pipeline suitably to be handled through
|
||||
* an IterSource based front-end. Such packaging is performed by the IterExplorer::asIterSource()
|
||||
* terminal builder function. In addition to [wrapping the iterator](\ref WrappedLumieraIter),
|
||||
* the `expandChildren()` operation is exposed as virtual function, to allow invocation through
|
||||
* the type-erased front-end, without any knowledge about the concrete implementation type
|
||||
* of the wrapped TreeIterator pipeline.
|
||||
*/
|
||||
template<class SRC>
|
||||
class PackagedTreeExplorerSource
|
||||
class PackagedIterExplorerSource
|
||||
: public WrappedLumieraIter<SRC>
|
||||
, public ChildExpandableSource<typename SRC::value_type>
|
||||
{
|
||||
using Parent = WrappedLumieraIter<SRC>;
|
||||
using Val = typename SRC::value_type; ///////////////////////////////////TICKET #1125 : get rid of Val
|
||||
|
||||
~PackagedTreeExplorerSource() { }
|
||||
~PackagedIterExplorerSource() { }
|
||||
public:
|
||||
using Parent::Parent;
|
||||
|
||||
|
|
@ -1323,12 +1315,12 @@ namespace lib {
|
|||
|
||||
|
||||
/**
|
||||
* Iterator front-end to manage and operate a TreeExplorer pipeline opaquely.
|
||||
* Iterator front-end to manage and operate a IterExplorer pipeline opaquely.
|
||||
* In addition to the usual iterator functions, this front-end also exposes an
|
||||
* `expandChildren()`-function, to activate the _expansion functor_ installed
|
||||
* through TreeExplorer::expand().
|
||||
* through IterExplorer::expand().
|
||||
* @remarks A iterator pipeline is assembled through invocation of the builder functions
|
||||
* on TreeExplorer -- this way creating a complex implementation defined iterator type.
|
||||
* on IterExplorer — thereby creating a complex implementation defined iterator type.
|
||||
* This front-end manages such a pipeline in heap allocated storage (by shared_ptr), while
|
||||
* exposing only a simple conventional interface (templated to the resulting value type `VAL`).
|
||||
* This allows to pass it over interfaces as "unspecified data source", without disclosing
|
||||
|
|
@ -1366,13 +1358,13 @@ namespace lib {
|
|||
|
||||
private:
|
||||
template<class SRC>
|
||||
friend class TreeExplorer;
|
||||
friend class IterExplorer;
|
||||
|
||||
template<class IT>
|
||||
IterExploreSource (IT&& opaqueSrcPipeline)
|
||||
: IterSource<VAL>::iterator {
|
||||
IterSource<VAL>::build (
|
||||
new iter_explorer::PackagedTreeExplorerSource<IT> {
|
||||
new iter_explorer::PackagedIterExplorerSource<IT> {
|
||||
move (opaqueSrcPipeline)})}
|
||||
{ }
|
||||
|
||||
|
|
@ -1380,7 +1372,7 @@ namespace lib {
|
|||
expandableSource() const
|
||||
{
|
||||
if (not this->source())
|
||||
throw error::State ("operating on a disabled default constructed TreeExplorer"
|
||||
throw error::State ("operating on a disabled default constructed IterExplorer"
|
||||
,error::LUMIERA_ERROR_BOTTOM_VALUE);
|
||||
|
||||
auto source = unConst(this)->source().get();
|
||||
|
|
@ -1392,7 +1384,7 @@ namespace lib {
|
|||
|
||||
|
||||
|
||||
/* ======= TreeExplorer pipeline builder and iterator ======= */
|
||||
/* ======= IterExplorer pipeline builder and iterator ======= */
|
||||
|
||||
/**
|
||||
* Adapter to build a demand-driven tree expanding and exploring computation
|
||||
|
|
@ -1406,16 +1398,16 @@ namespace lib {
|
|||
* into an instance of the iter_explorer::BaseAdapter template
|
||||
*
|
||||
* \par usage
|
||||
* TreeExplorer is meant to be used as *Builder* for a processing pipeline.
|
||||
* IterExplorer is meant to be used as *Builder* for a processing pipeline.
|
||||
* For this to work, it is essential to pick the `SRC` baseclass properly.
|
||||
* - to build a TreeExplorer, use the treeExplore() free function,
|
||||
* - to build a IterExplorer, use the \ref explore() free function,
|
||||
* which cares to pick up and possibly adapt the given iteration source
|
||||
* - to add processing layers, invoke the builder operations on TreeExplorer
|
||||
* - to add processing layers, invoke the builder operations on IterExplorer
|
||||
* in a chained fashion, thereby binding functors or lambdas. Capture the
|
||||
* final result with an auto variable.
|
||||
* - the result is iterable in accordance to »Lumiera Forward Iterator«
|
||||
*
|
||||
* @warning deliberately, the builder functions exposed on TreeExplorer will
|
||||
* @warning deliberately, the builder functions exposed on IterExplorer will
|
||||
* _move_ the old object into the new, augmented iterator. This is
|
||||
* possibly dangerous, since one might be tempted to invoke such a
|
||||
* builder function on an existing iterator variable captured by auto.
|
||||
|
|
@ -1425,7 +1417,7 @@ namespace lib {
|
|||
* builder API and unleashes or slices down to the iterator instead.
|
||||
*/
|
||||
template<class SRC>
|
||||
class TreeExplorer
|
||||
class IterExplorer
|
||||
: public SRC
|
||||
{
|
||||
static_assert(can_IterForEach<SRC>::value, "Lumiera Iterator required as source");
|
||||
|
|
@ -1443,7 +1435,7 @@ namespace lib {
|
|||
|
||||
/* ==== Builder functions ==== */
|
||||
|
||||
/** preconfigure this TreeExplorer to allow for _"expansion of children"_.
|
||||
/** preconfigure this IterExplorer to allow for _"expansion of children"_.
|
||||
* The resulting iterator exposes an `expandChildren()` function, which consumes
|
||||
* the current head element of this iterator and feeds it through the
|
||||
* _expansion functor_, which was provided to this builder function here.
|
||||
|
|
@ -1466,10 +1458,10 @@ namespace lib {
|
|||
* reason, the functor may take its argument by reference, and a produced
|
||||
* new "child state core" may likewise collaborate with that original
|
||||
* data source or state core behind the scenes; the latter is guaranteed
|
||||
* to exist during the whole lifetime of this TreeExplorer.
|
||||
* to exist during the whole lifetime of this IterExplorer.
|
||||
* @note there is limited support for generic lambdas, but only for the second case.
|
||||
* The reason is, we can not "probe" a template or generic lambda for possible
|
||||
* argument and result types. Thus, if you provide a generic lambda, TreeExplorer
|
||||
* argument and result types. Thus, if you provide a generic lambda, IterExplorer
|
||||
* tries to pass it a `SrcIter &` (reference to the embedded original iterator).
|
||||
* For any other cases, please provide a lambda or functor with a single, explicitly
|
||||
* typed argument. Obviously, argument and result type should also make sense for
|
||||
|
|
@ -1486,7 +1478,7 @@ namespace lib {
|
|||
using ResCore = iter_explorer::Expander<SRC, ExpandedChildren>;
|
||||
using ResIter = typename _DecoratorTraits<ResCore>::SrcIter;
|
||||
|
||||
return TreeExplorer<ResIter> (ResCore {move(*this), forward<FUN>(expandFunctor)});
|
||||
return IterExplorer<ResIter> (ResCore {move(*this), forward<FUN>(expandFunctor)});
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1507,7 +1499,7 @@ namespace lib {
|
|||
using ResCore = iter_explorer::AutoExpander<SRC>;
|
||||
using ResIter = typename _DecoratorTraits<ResCore>::SrcIter;
|
||||
|
||||
return TreeExplorer<ResIter> (ResCore {move(*this)});
|
||||
return IterExplorer<ResIter> (ResCore {move(*this)});
|
||||
}
|
||||
|
||||
/** shortcut notation to invoke \ref expand(expandFunctor) followed by \ref expandAll() */
|
||||
|
|
@ -1535,11 +1527,11 @@ namespace lib {
|
|||
using ResCore = iter_explorer::ScheduledExpander<SRC>;
|
||||
using ResIter = typename _DecoratorTraits<ResCore>::SrcIter;
|
||||
|
||||
return TreeExplorer<ResIter> (ResCore {move(*this)});
|
||||
return IterExplorer<ResIter> (ResCore {move(*this)});
|
||||
}
|
||||
|
||||
|
||||
/** adapt this TreeExplorer to pipe each result value through a transformation function.
|
||||
/** adapt this IterExplorer to pipe each result value through a transformation function.
|
||||
* Several "layers" of mapping can be piled on top of each other, possibly mixed with the
|
||||
* other types of adaptation, like the child-expanding operation, or a filter. Obviously,
|
||||
* when building such processing pipelines, the input and output types of the functors
|
||||
|
|
@ -1558,11 +1550,11 @@ namespace lib {
|
|||
using ResCore = iter_explorer::Transformer<SRC, Product>;
|
||||
using ResIter = typename _DecoratorTraits<ResCore>::SrcIter;
|
||||
|
||||
return TreeExplorer<ResIter> (ResCore {move(*this), forward<FUN>(transformFunctor)});
|
||||
return IterExplorer<ResIter> (ResCore {move(*this), forward<FUN>(transformFunctor)});
|
||||
}
|
||||
|
||||
|
||||
/** adapt this TreeExplorer to iterate only as long as a condition holds true.
|
||||
/** adapt this IterExplorer to iterate only as long as a condition holds true.
|
||||
* @return processing pipeline with attached [stop condition](\ref iter_explorer::StopTrigger)
|
||||
*/
|
||||
template<class FUN>
|
||||
|
|
@ -1574,11 +1566,11 @@ namespace lib {
|
|||
using ResCore = iter_explorer::StopTrigger<SRC>;
|
||||
using ResIter = typename _DecoratorTraits<ResCore>::SrcIter;
|
||||
|
||||
return TreeExplorer<ResIter> (ResCore {move(*this), forward<FUN>(whileCond)});
|
||||
return IterExplorer<ResIter> (ResCore {move(*this), forward<FUN>(whileCond)});
|
||||
}
|
||||
|
||||
|
||||
/** adapt this TreeExplorer to iterate until a condition becomes first true.
|
||||
/** adapt this IterExplorer to iterate until a condition becomes first true.
|
||||
* @return processing pipeline with attached [stop condition](\ref iter_explorer::StopTrigger)
|
||||
*/
|
||||
template<class FUN>
|
||||
|
|
@ -1591,7 +1583,7 @@ namespace lib {
|
|||
using ResIter = typename _DecoratorTraits<ResCore>::SrcIter;
|
||||
using ArgType = typename iter_explorer::_FunTraits<FUN,SRC>::Arg;
|
||||
|
||||
return TreeExplorer<ResIter> (ResCore { move(*this)
|
||||
return IterExplorer<ResIter> (ResCore { move(*this)
|
||||
,[whileCond = forward<FUN>(untilCond)](ArgType val)
|
||||
{
|
||||
return not whileCond(val);
|
||||
|
|
@ -1600,7 +1592,7 @@ namespace lib {
|
|||
}
|
||||
|
||||
|
||||
/** adapt this TreeExplorer to filter results, by invoking the given functor to approve them.
|
||||
/** adapt this IterExplorer to filter results, by invoking the given functor to approve them.
|
||||
* The previously created source layers will be "pulled" to fast-forward immediately to the
|
||||
* next element confirmed this way by the bound functor. If none of the source elements
|
||||
* is acceptable, the iterator will transition to exhausted state immediately.
|
||||
|
|
@ -1615,7 +1607,7 @@ namespace lib {
|
|||
using ResCore = iter_explorer::Filter<SRC>;
|
||||
using ResIter = typename _DecoratorTraits<ResCore>::SrcIter;
|
||||
|
||||
return TreeExplorer<ResIter> (ResCore {move(*this), forward<FUN>(filterPredicate)});
|
||||
return IterExplorer<ResIter> (ResCore {move(*this), forward<FUN>(filterPredicate)});
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1628,7 +1620,7 @@ namespace lib {
|
|||
* possibly causing the underlying iterator to be pulled until an element matching the condition
|
||||
* is found.
|
||||
* @return processing pipeline with attached [special MutableFilter](\ref iter_explorer::MutableFilter) decorator
|
||||
* @see \ref IterTreeExplorer_test::verify_FilterChanges()
|
||||
* @see \ref IterIterExplorer_test::verify_FilterChanges()
|
||||
* @see \ref iter_explorer::MutableFilter::andFilter()
|
||||
* @see \ref iter_explorer::MutableFilter::andNotFilter()
|
||||
* @see \ref iter_explorer::MutableFilter::orFilter()
|
||||
|
|
@ -1645,7 +1637,7 @@ namespace lib {
|
|||
using ResCore = iter_explorer::MutableFilter<SRC>;
|
||||
using ResIter = typename _DecoratorTraits<ResCore>::SrcIter;
|
||||
|
||||
return TreeExplorer<ResIter> (ResCore {move(*this), forward<FUN>(filterPredicate)});
|
||||
return IterExplorer<ResIter> (ResCore {move(*this), forward<FUN>(filterPredicate)});
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1666,7 +1658,7 @@ namespace lib {
|
|||
* which for the consumer side behave like `iterNext()` calls. If a layer needs to do something special for
|
||||
* `iterNext()`, it needs to perform a similar action for `expandChildren()`.
|
||||
* - it must be behave like a default-constructible, copyable value object
|
||||
* @return augmented TreeExplorer, incorporating and adapting the injected layer
|
||||
* @return augmented IterExplorer, incorporating and adapting the injected layer
|
||||
*/
|
||||
template<template<class> class LAY>
|
||||
auto
|
||||
|
|
@ -1675,7 +1667,7 @@ namespace lib {
|
|||
using ResCore = LAY<SRC>;
|
||||
using ResIter = typename _DecoratorTraits<ResCore>::SrcIter;
|
||||
|
||||
return TreeExplorer<ResIter> (ResCore {move(*this)});
|
||||
return IterExplorer<ResIter> (ResCore {move(*this)});
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1695,7 +1687,7 @@ namespace lib {
|
|||
}
|
||||
|
||||
|
||||
/** _terminal builder_ to strip the TreeExplorer and expose the built Pipeline.
|
||||
/** _terminal builder_ to strip the IterExplorer and expose the built Pipeline.
|
||||
* @return a »Lumiera Forward iterator« incorporating the complete pipeline logic.
|
||||
*/
|
||||
SRC
|
||||
|
|
@ -1714,14 +1706,15 @@ namespace lib {
|
|||
|
||||
/* ==== convenient builder free functions ==== */
|
||||
|
||||
/** start building a TreeExplorer
|
||||
/** start building a IterExplorer
|
||||
* by suitably wrapping the given iterable source.
|
||||
* @return a TreeEplorer, which is an Iterator to yield all the source elements,
|
||||
* but may also be used to build up a complex processing pipeline.
|
||||
* @warning if you capture the result of this call by an auto variable,
|
||||
* be sure to understand that invoking any further builder operation on
|
||||
* TreeExplorer will invalidate that variable (by moving it into the
|
||||
* IterExplorer will invalidate that variable (by moving it into the
|
||||
* augmented iterator returned from such builder call).
|
||||
* @todo this framework should be retrofitted to fit in with C++20 pipelines
|
||||
*
|
||||
* # Usage
|
||||
*
|
||||
|
|
@ -1735,23 +1728,23 @@ namespace lib {
|
|||
* be iterated as "Lumiera Forward Iterator". Any object with suitable extension
|
||||
* points and behaviour can be used, as explained [here](\ref lib::IterStateWrapper).
|
||||
*
|
||||
* The resulting TreeExplorer instance can directly be used as "Lumiera Forward Iterator".
|
||||
* The resulting IterExplorer instance can directly be used as "Lumiera Forward Iterator".
|
||||
* However, typically you might want to invoke the builder functions to configure further
|
||||
* processing steps in a processing pipeline...
|
||||
* - to [filter](\ref TreeExplorer::filter) the results with a predicate (functor)
|
||||
* - to [transform](\ref TreeExplorer::transform) the yielded results
|
||||
* - to bind and configure a [child expansion operation](\ref TreeExplorer::expand), which
|
||||
* - to [filter](\ref IterExplorer::filter) the results with a predicate (functor)
|
||||
* - to [transform](\ref IterExplorer::transform) the yielded results
|
||||
* - to bind and configure a [child expansion operation](\ref IterExplorer::expand), which
|
||||
* can then be triggered by explicitly invoking [.expandChildren()](\ref iter_explorer::Expander::expandChildren)
|
||||
* on the resulting pipeline; the generated child sequence is "flat mapped" into the results
|
||||
* (a *Monad* style usage).
|
||||
* - to [package](\ref TreeExplorer::asIterSource) the pipeline built thus far behind an opaque
|
||||
* - to [package](\ref IterExplorer::asIterSource) the pipeline built thus far behind an opaque
|
||||
* interface and move the implementation into heap memory.
|
||||
*
|
||||
* A typical usage might be...
|
||||
* \code
|
||||
* auto multiply = [](int v){ return 2*v; };
|
||||
*
|
||||
* auto ii = treeExplore (CountDown{7,4})
|
||||
* auto ii = explore (CountDown{7,4})
|
||||
* .transform(multiply);
|
||||
*
|
||||
* CHECK (14 == *ii);
|
||||
|
|
@ -1763,24 +1756,14 @@ namespace lib {
|
|||
*/
|
||||
template<class IT>
|
||||
inline auto
|
||||
treeExplore (IT&& srcSeq)
|
||||
explore (IT&& srcSeq)
|
||||
{
|
||||
using SrcIter = typename _DecoratorTraits<IT>::SrcIter;
|
||||
using Base = iter_explorer::BaseAdapter<SrcIter>;
|
||||
|
||||
return TreeExplorer<Base> (std::forward<IT> (srcSeq));
|
||||
}
|
||||
|
||||
/** synonym for #treeExplore.
|
||||
* @remark this might become an extension to C++20 pipelines
|
||||
*/
|
||||
template<class IT>
|
||||
inline auto
|
||||
explore (IT&& srcSeq)
|
||||
{
|
||||
return treeExplore (std::forward<IT> (srcSeq));
|
||||
return IterExplorer<Base> (std::forward<IT> (srcSeq));
|
||||
}
|
||||
|
||||
|
||||
} // namespace lib
|
||||
#endif /* LIB_ITER_TREE_EXPLORER_H */
|
||||
#endif /* LIB_ITER_EXPLORER_H */
|
||||
|
|
@ -33,7 +33,6 @@
|
|||
|
||||
using util::isnil;
|
||||
using lib::Symbol;
|
||||
using lib::treeExplore;
|
||||
|
||||
|
||||
namespace stage {
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@
|
|||
#include "lib/symbol.hpp"
|
||||
#include "lib/format-string.hpp"
|
||||
#include "stage/interact/ui-coord.hpp"
|
||||
#include "lib/iter-tree-explorer.hpp"
|
||||
#include "lib/iter-explorer.hpp"
|
||||
#include "lib/iter-source.hpp"
|
||||
#include "lib/depend.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
|
@ -177,7 +177,7 @@ namespace interact {
|
|||
static auto
|
||||
buildIterator (TreeStructureNavigator* source)
|
||||
{
|
||||
return lib::treeExplore (source)
|
||||
return lib::explore (source)
|
||||
.expand([](TreeStructureNavigator& parent){ return parent.expandChildren(); });
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@
|
|||
#include "stage/timeline/track-head-widget.hpp"
|
||||
#include "stage/timeline/track-body.hpp"
|
||||
#include "lib/time/timevalue.hpp"
|
||||
#include "lib/iter-tree-explorer.hpp"
|
||||
#include "lib/iter-explorer.hpp"
|
||||
#include "lib/util-coll.hpp"
|
||||
|
||||
#include "lib/nocopy.hpp"
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@
|
|||
#include "stage/gtk-base.hpp"
|
||||
#include "lib/verb-visitor.hpp"
|
||||
|
||||
#include "lib/iter-tree-explorer.hpp"
|
||||
#include "lib/iter-explorer.hpp"
|
||||
#include "lib/symbol.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
|
|
@ -207,8 +207,8 @@ namespace timeline {
|
|||
};
|
||||
|
||||
|
||||
return lib::treeExplore(elements)
|
||||
.filter(CountingFilter{pinnedPrefixCnt, selectPrefixPart});
|
||||
return lib::explore (elements)
|
||||
.filter (CountingFilter{pinnedPrefixCnt, selectPrefixPart});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -46,14 +46,14 @@
|
|||
** must be complete before the main frame job can be started. Since the Job-Planning pipeline is
|
||||
** generic, this kind of detail dependency is modelled as _prerequisite JobTicket,_ leading to
|
||||
** an possibly extended depth-first tree expansion, starting from the »master frame ticket« at
|
||||
** the root. This _tree exploration_ is implemented by the TreeExplorer::Expander building block,
|
||||
** the root. This _tree exploration_ is implemented by the IterExplorer::Expander building block,
|
||||
** which obviously has to maintain a stack of expanded child dependencies. This leads to the
|
||||
** observation, that at any point of this dependency processing, for the complete path from the
|
||||
** child prerequisite up to the root tick there is a sequence of JobPlanning instances placed
|
||||
** into this stack in the Explorer object (each level in this stack is actually an iterator
|
||||
** and handles one level of child prerequisites). The deadline calculation directly exploits
|
||||
** this known arrangement, insofar each JobPlanning has a pointer to its parent (sitting in
|
||||
** the stack level above). See the [IterExplorer unit test](\ref lib::IterTreeExplorer_test::verify_expandOperation)
|
||||
** the stack level above). See the [IterExplorer unit test](\ref lib::IterExplorer_test::verify_expandOperation)
|
||||
** to understand this recursive on-demand processing in greater detail.
|
||||
**
|
||||
** @see JobPlanning_test
|
||||
|
|
|
|||
|
|
@ -328,16 +328,7 @@ return: 0
|
|||
END
|
||||
|
||||
|
||||
TEST "Iterator monad variations (1st draft)" IterExplorer_test <<END
|
||||
out-lit: 1-2-3-4-5-6-7-8
|
||||
out-lit: 0-1-2-3-4-0-1-2-3-4-5-6-0-1-2-3-4-5-6-7-8
|
||||
out-lit: 0-1-2-3-4-5-6-7-8
|
||||
out-lit: 0-1-2-3-4-5-6-7-8
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
||||
TEST "Iterator monad variations (2nd draft)" IterTreeExplorer_test <<END
|
||||
TEST "Iterator tree exploration" IterExplorer_test <<END
|
||||
out-lit: 4-3-2-1
|
||||
out: Search in random tree: toFind = .....
|
||||
out: Protocol of the search: .+\-.+\-.+\-.+\-.+
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
#include "lib/test/test-helper.hpp"
|
||||
#include "steam/engine/mock-dispatcher.hpp"
|
||||
|
||||
#include "lib/iter-tree-explorer.hpp"
|
||||
#include "lib/iter-explorer.hpp"
|
||||
#include "lib/format-string.hpp"
|
||||
#include "lib/format-util.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
using test::Test;
|
||||
using lib::eachNum;
|
||||
using lib::treeExplore;
|
||||
using lib::explore;
|
||||
using lib::time::PQuant;
|
||||
using lib::time::FrameRate;
|
||||
using util::isnil;
|
||||
|
|
@ -161,13 +161,13 @@ namespace test {
|
|||
{
|
||||
auto grid = frameGrid(FrameRate::PAL); // one frame ≙ 40ms
|
||||
|
||||
CHECK (materialise (
|
||||
treeExplore (eachNum(5,13))
|
||||
CHECK (materialise(
|
||||
explore (eachNum(5,13))
|
||||
.transform([&](FrameCnt frameNr)
|
||||
{
|
||||
return grid->timeOf (frameNr);
|
||||
})
|
||||
)
|
||||
)
|
||||
== "200ms-240ms-280ms-320ms-360ms-400ms-440ms-480ms"_expect);
|
||||
|
||||
|
||||
|
|
@ -326,7 +326,7 @@ namespace test {
|
|||
CHECK (visualise(pipeline) == "J(11|200ms⧐1s180ms)"_expect); // first job in pipeline: nominal t=200ms,
|
||||
// .... 10ms engine latency + 10ms job runtime ⟶ deadline 1s180ms
|
||||
CHECK (materialise(
|
||||
treeExplore(move(pipeline))
|
||||
explore(move(pipeline))
|
||||
.transform(visualise)
|
||||
)
|
||||
== "J(11|200ms⧐1s180ms)-J(22|200ms⧐1s150ms)-J(33|200ms⧐1s110ms)-" // ... -(10+10) | -(10+10)-(10+20) | -(10+10)-(10+20)-(10+30)
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
#include "lib/test/test-helper.hpp"
|
||||
#include "steam/engine/mock-dispatcher.hpp"
|
||||
#include "vault/engine/nop-job-functor.hpp"
|
||||
#include "lib/iter-tree-explorer.hpp"
|
||||
#include "lib/iter-explorer.hpp"
|
||||
#include "lib/util-tuple.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
IterTreeExplorer(Test) - verify tree expanding and backtracking iterator
|
||||
IterExplorer(Test) - verify tree expanding and backtracking iterator
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2017, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
|
@ -59,7 +59,7 @@
|
|||
#include "lib/itertools.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
#include "lib/iter-tree-explorer.hpp"
|
||||
#include "lib/iter-explorer.hpp"
|
||||
#include "lib/meta/trait.hpp"
|
||||
|
||||
#include <utility>
|
||||
|
|
@ -216,11 +216,11 @@ namespace test{
|
|||
/*******************************************************************//**
|
||||
* @test use a simple source iterator yielding numbers
|
||||
* to build various functional evaluation pipelines,
|
||||
* based on the \ref TreeExplorer template.
|
||||
* based on the \ref IterExplorer template.
|
||||
* - the adapter to wrap the source, which can either
|
||||
* [be a state core](\ref verify_wrappedState() ), or can
|
||||
* [be a Lumiera Forward Iterator](\ref verify_wrappedIterator() )
|
||||
* - the defining use case for TreeExplorer is to build a
|
||||
* - the defining use case for IterExplorer is to build a
|
||||
* [pipeline for depth-first exploration](\ref verify_expandOperation() )
|
||||
* of a (functional) tree structure. This "tree" is created by invoking
|
||||
* a "expand functor", which can be defined in various ways.
|
||||
|
|
@ -256,10 +256,10 @@ namespace test{
|
|||
* It is up to the monad to decide if, and when those processing steps are applied to the
|
||||
* embedded values and how to combine the results into a new monad.
|
||||
*
|
||||
* @see TreeExplorer
|
||||
* @see IterExplorer
|
||||
* @see IterAdapter
|
||||
*/
|
||||
class IterTreeExplorer_test : public Test
|
||||
class IterExplorer_test : public Test
|
||||
{
|
||||
|
||||
virtual void
|
||||
|
|
@ -287,12 +287,12 @@ namespace test{
|
|||
|
||||
|
||||
/** @test without using any extra functionality,
|
||||
* TreeExplorer just wraps an iterable state.
|
||||
* IterExplorer just wraps an iterable state.
|
||||
*/
|
||||
void
|
||||
verify_wrappedState()
|
||||
{
|
||||
auto ii = treeExplore (CountDown{5,0});
|
||||
auto ii = explore (CountDown{5,0});
|
||||
CHECK (!isnil (ii));
|
||||
CHECK (5 == *ii);
|
||||
++ii;
|
||||
|
|
@ -304,17 +304,17 @@ namespace test{
|
|||
VERIFY_ERROR (ITER_EXHAUST, *ii );
|
||||
VERIFY_ERROR (ITER_EXHAUST, ++ii );
|
||||
|
||||
ii = treeExplore (CountDown{5});
|
||||
ii = explore (CountDown{5});
|
||||
CHECK (materialise(ii) == "5-4-3-2-1");
|
||||
ii = treeExplore (CountDown{7,4});
|
||||
ii = explore (CountDown{7,4});
|
||||
CHECK (materialise(ii) == "7-6-5");
|
||||
ii = treeExplore (CountDown{});
|
||||
ii = explore (CountDown{});
|
||||
CHECK ( isnil (ii));
|
||||
CHECK (!ii);
|
||||
}
|
||||
|
||||
|
||||
/** @test TreeExplorer is able to wrap any _Lumiera Forward Iterator_ */
|
||||
/** @test IterExplorer is able to wrap any _Lumiera Forward Iterator_ */
|
||||
void
|
||||
verify_wrappedIterator()
|
||||
{
|
||||
|
|
@ -325,7 +325,7 @@ namespace test{
|
|||
++ii;
|
||||
CHECK (-2 == *ii);
|
||||
|
||||
auto jj = treeExplore(ii);
|
||||
auto jj = explore(ii);
|
||||
CHECK (!isnil (jj));
|
||||
CHECK (-2 == *jj);
|
||||
++jj;
|
||||
|
|
@ -338,7 +338,7 @@ namespace test{
|
|||
CHECK (materialise(jj) == "3--5-8--13");
|
||||
|
||||
// can even adapt STL container automatically
|
||||
auto kk = treeExplore(numz);
|
||||
auto kk = explore(numz);
|
||||
CHECK (!isnil (kk));
|
||||
CHECK (1 == *kk);
|
||||
CHECK (materialise(kk) == "1--2-3--5-8--13");
|
||||
|
|
@ -368,7 +368,7 @@ namespace test{
|
|||
* which will then be iterated to yield the child elements
|
||||
* - and, quite distinct to the aforementioned "monadic" usage, the expansion functor
|
||||
* may alternatively be written in a way as to collaborate with the "state core" used
|
||||
* when building the TreeExplorer. In this case, the functor typically takes a _reference_
|
||||
* when building the IterExplorer. In this case, the functor typically takes a _reference_
|
||||
* to this underlying state core or iterator. The purpose for this definition variant is
|
||||
* to allow exploring a tree-like evaluation, without the need to disclose anything about
|
||||
* the backing implementation; the expansion functor just happens to know the implementation
|
||||
|
|
@ -386,12 +386,12 @@ namespace test{
|
|||
/* == "monadic flatMap" == */
|
||||
|
||||
verify_treeExpandingIterator(
|
||||
treeExplore(CountDown{5})
|
||||
explore(CountDown{5})
|
||||
.expand([](uint j){ return CountDown{j-1}; }) // expand-functor: Val > StateCore
|
||||
);
|
||||
|
||||
verify_treeExpandingIterator(
|
||||
treeExplore(CountDown{5})
|
||||
explore(CountDown{5})
|
||||
.expand([](uint j){ return NumberSequence{j-1}; }) // expand-functor: Val > Iter
|
||||
); // NOTE: different Iterator type than the source!
|
||||
|
||||
|
|
@ -407,7 +407,7 @@ namespace test{
|
|||
};
|
||||
|
||||
verify_treeExpandingIterator(
|
||||
treeExplore(CountDown{5})
|
||||
explore(CountDown{5})
|
||||
.expand(expandIntoChildBuffer) // expand-functor: Val > STL-container&
|
||||
);
|
||||
|
||||
|
|
@ -419,22 +419,22 @@ namespace test{
|
|||
/* == "state manipulation" use cases == */
|
||||
|
||||
verify_treeExpandingIterator(
|
||||
treeExplore(CountDown{5})
|
||||
explore(CountDown{5})
|
||||
.expand([](CountDown const& core){ return CountDown{ core.yield() - 1}; }) // expand-functor: StateCore const& -> StateCore
|
||||
);
|
||||
|
||||
verify_treeExpandingIterator(
|
||||
treeExplore(CountDown{5})
|
||||
explore(CountDown{5})
|
||||
.expand([](CountDown core){ return NumberSequence{ core.yield() - 1}; }) // expand-functor: StateCore -> Iter
|
||||
);
|
||||
|
||||
verify_treeExpandingIterator(
|
||||
treeExplore(CountDown{5})
|
||||
explore(CountDown{5})
|
||||
.expand([](auto & it){ return CountDown{ *it - 1}; }) // generic Lambda: Iter& -> StateCore
|
||||
);
|
||||
|
||||
verify_treeExpandingIterator(
|
||||
treeExplore(CountDown{5})
|
||||
explore(CountDown{5})
|
||||
.expand([](auto it){ return decltype(it){ *it - 1}; }) // generic Lambda: Iter -> Iter
|
||||
);
|
||||
}
|
||||
|
|
@ -496,7 +496,7 @@ namespace test{
|
|||
void
|
||||
verify_expand_rootCurrent()
|
||||
{
|
||||
auto tree = treeExplore(CountDown{25})
|
||||
auto tree = explore(CountDown{25})
|
||||
.expand([](uint j){ return CountDown{j-1}; });
|
||||
|
||||
CHECK (materialise(tree) == "25-24-23-22-21-20-19-18-17-16-15-14-13-12-11-10-9-8-7-6-5-4-3-2-1");
|
||||
|
|
@ -557,7 +557,7 @@ namespace test{
|
|||
auto formatify = [&](auto it){ return string{embrace % *it}; }; // generic lambda: assumed to take an Iterator&
|
||||
|
||||
|
||||
auto ii = treeExplore (CountDown{7,4})
|
||||
auto ii = explore(CountDown{7,4})
|
||||
.transform(multiply)
|
||||
;
|
||||
|
||||
|
|
@ -577,14 +577,14 @@ namespace test{
|
|||
// demonstrate chaining of several transformation layers
|
||||
vector<int64_t> numz{1,-2,3,-5,8,-13};
|
||||
|
||||
CHECK ("≺1≻-≺-2≻-≺3≻-≺-5≻-≺8≻-≺-13≻" == materialise (treeExplore(numz)
|
||||
CHECK ("≺1≻-≺-2≻-≺3≻-≺-5≻-≺8≻-≺-13≻" == materialise (explore(numz)
|
||||
.transform(formatify)) );
|
||||
|
||||
CHECK ("≺2≻-≺-4≻-≺6≻-≺-10≻-≺16≻-≺-26≻" == materialise (treeExplore(numz)
|
||||
CHECK ("≺2≻-≺-4≻-≺6≻-≺-10≻-≺16≻-≺-26≻" == materialise (explore(numz)
|
||||
.transform(multiply)
|
||||
.transform(formatify)) );
|
||||
|
||||
CHECK ("≺≺4≻≻-≺≺-8≻≻-≺≺12≻≻-≺≺-20≻≻-≺≺32≻≻-≺≺-52≻≻" == materialise (treeExplore(numz)
|
||||
CHECK ("≺≺4≻≻-≺≺-8≻≻-≺≺12≻≻-≺≺-20≻≻-≺≺32≻≻-≺≺-52≻≻" == materialise (explore(numz)
|
||||
.transform(multiply)
|
||||
.transform(multiply)
|
||||
.transform(formatify)
|
||||
|
|
@ -594,7 +594,7 @@ namespace test{
|
|||
// demonstrate the functor is evaluated only once per step
|
||||
int fact = 3;
|
||||
|
||||
auto jj = treeExplore (CountDown{4})
|
||||
auto jj = explore (CountDown{4})
|
||||
.transform([&](int v)
|
||||
{
|
||||
v *=fact;
|
||||
|
|
@ -638,7 +638,7 @@ namespace test{
|
|||
|
||||
// demonstrate a transformer accessing the source state core...
|
||||
// should not be relevant in practice, but works due to the generic adapters
|
||||
auto kk = treeExplore(CountDown{9,4})
|
||||
auto kk = explore (CountDown{9,4})
|
||||
.transform([](CountDown& core)
|
||||
{
|
||||
uint delta = core.p - core.e;
|
||||
|
|
@ -659,7 +659,7 @@ namespace test{
|
|||
|
||||
|
||||
/** @test combine the recursion into children with a tail mapping operation.
|
||||
* Wile basically this is just the layering structure of TreeExplorer put into action,
|
||||
* Wile basically this is just the layering structure of IterExplorer put into action,
|
||||
* you should note one specific twist: the iter_explorer::Expander::expandChildren() call
|
||||
* is meant to be issued from ``downstream'', from the consumer side. Yet the consumer at
|
||||
* that point might well see the items as processed by a transforming step layered on top.
|
||||
|
|
@ -683,7 +683,7 @@ namespace test{
|
|||
void
|
||||
verify_combinedExpandTransform()
|
||||
{
|
||||
auto ii = treeExplore(CountDown{5})
|
||||
auto ii = explore(CountDown{5})
|
||||
.expand([](uint j){ return CountDown{j-1}; })
|
||||
.transform([](int v){ return 2*v; })
|
||||
;
|
||||
|
|
@ -700,7 +700,7 @@ namespace test{
|
|||
// how intermediary processing steps may interact
|
||||
|
||||
CHECK (materialise (
|
||||
treeExplore(CountDown{5})
|
||||
explore(CountDown{5})
|
||||
.expand([](uint j){ return CountDown{j-1}; })
|
||||
.transform([](int v){ return 2*v; })
|
||||
.transform([](auto& it)
|
||||
|
|
@ -748,13 +748,13 @@ namespace test{
|
|||
verify_customProcessingLayer()
|
||||
{
|
||||
CHECK (materialise(
|
||||
treeExplore(CountDown{7})
|
||||
explore(CountDown{7})
|
||||
.processingLayer<MagicTestRubbish>()
|
||||
)
|
||||
== "7-5-3-1");
|
||||
|
||||
CHECK (materialise(
|
||||
treeExplore(CountDown{7})
|
||||
explore(CountDown{7})
|
||||
.transform([](uint v){ return 2*v; })
|
||||
.processingLayer<MagicTestRubbish>()
|
||||
.filter([](int v){ return v % 3; })
|
||||
|
|
@ -771,12 +771,12 @@ namespace test{
|
|||
* Such is especially relevant when searching for a locally or global maximal solution, which
|
||||
* is rather simple to implement with an additional filtering layer -- and this approach requires
|
||||
* us to deliver all partial solutions for the filter layer to act on. Obviously this functionality
|
||||
* leads to additional state and thus is provided as optional layer in the TreeExplorer builder.
|
||||
* leads to additional state and thus is provided as optional layer in the IterExplorer builder.
|
||||
*/
|
||||
void
|
||||
verify_scheduledExpansion()
|
||||
{
|
||||
auto ii = treeExplore(CountDown{6})
|
||||
auto ii = explore(CountDown{6})
|
||||
.expand([](uint j){ return CountDown{j-2}; })
|
||||
.expandOnIteration();
|
||||
|
||||
|
|
@ -833,25 +833,25 @@ namespace test{
|
|||
verify_untilStopTrigger()
|
||||
{
|
||||
CHECK (materialise (
|
||||
treeExplore(CountDown{10})
|
||||
explore (CountDown{10})
|
||||
.iterUntil([](uint j){ return j < 5; })
|
||||
)
|
||||
== "10-9-8-7-6-5"_expect);
|
||||
|
||||
CHECK (materialise (
|
||||
treeExplore(CountDown{10})
|
||||
explore (CountDown{10})
|
||||
.iterWhile([](uint j){ return j > 5; })
|
||||
)
|
||||
== "10-9-8-7-6"_expect);
|
||||
|
||||
CHECK (materialise (
|
||||
treeExplore(CountDown{10})
|
||||
explore (CountDown{10})
|
||||
.iterWhile([](int j){ return j > -5; })
|
||||
)
|
||||
== "10-9-8-7-6-5-4-3-2-1"_expect);
|
||||
|
||||
CHECK (materialise (
|
||||
treeExplore(CountDown{10})
|
||||
explore (CountDown{10})
|
||||
.iterWhile([](uint j){ return j > 25; })
|
||||
)
|
||||
== ""_expect);
|
||||
|
|
@ -870,14 +870,14 @@ namespace test{
|
|||
{
|
||||
// canonical example, using a clean side-effect free predicate based on element values
|
||||
CHECK (materialise (
|
||||
treeExplore(CountDown{10})
|
||||
explore(CountDown{10})
|
||||
.filter([](uint j){ return j % 2; })
|
||||
)
|
||||
== "9-7-5-3-1"_expect);
|
||||
|
||||
|
||||
// Filter may lead to consuming util exhaustion...
|
||||
auto ii = treeExplore(CountDown{10})
|
||||
auto ii = explore(CountDown{10})
|
||||
.filter([](int j){ return j > 9; });
|
||||
|
||||
CHECK (not isnil (ii));
|
||||
|
|
@ -888,7 +888,7 @@ namespace test{
|
|||
|
||||
|
||||
// none of the source elements can be approved here...
|
||||
auto jj = treeExplore(CountDown{5})
|
||||
auto jj = explore(CountDown{5})
|
||||
.filter([](int j){ return j > 9; });
|
||||
|
||||
CHECK (isnil (jj));
|
||||
|
|
@ -901,7 +901,7 @@ namespace test{
|
|||
// uint to float, but the filter interacts directly with the core and thus
|
||||
// judges based on the original values
|
||||
CHECK (materialise (
|
||||
treeExplore(CountDown{10,4})
|
||||
explore(CountDown{10,4})
|
||||
.transform([](float f){ return 0.55 + 2*f; })
|
||||
.filter([](CountDown& core){ return core.p % 2; })
|
||||
)
|
||||
|
|
@ -912,7 +912,7 @@ namespace test{
|
|||
// contrived example to verify interplay of filtering and child expansion;
|
||||
// especially note that the filter is re-evaluated after expansion happened.
|
||||
CHECK (materialise (
|
||||
treeExplore(CountDown{10})
|
||||
explore(CountDown{10})
|
||||
.expand([](uint i){ return CountDown{i%4==0? i-1 : 0}; }) // generate subtree at 8 and 4 ==> 10-9-8-7-6-5-4-3-2-1-3-2-1-7-6-5-4-3-2-1-3-2-1
|
||||
.filter([](uint i){ return i%2 == 0; })
|
||||
.expandAll() // Note: sends the expandChildren down through the filter
|
||||
|
|
@ -927,7 +927,7 @@ namespace test{
|
|||
// - accepting the iterator to trigger child expansion
|
||||
// - which also causes re-evaluation of the preceding transformer
|
||||
bool toggle = false;
|
||||
auto kk = treeExplore(CountDown{10,5})
|
||||
auto kk = explore(CountDown{10,5})
|
||||
.expand([](uint j){ return CountDown{j-1}; })
|
||||
.transform([](int v){ return 2*v; })
|
||||
.filter([&](auto& it)
|
||||
|
|
@ -955,7 +955,7 @@ namespace test{
|
|||
CHECK (materialise(kk.filter([](long i){ return i % 7; }))
|
||||
== "12-10-8-6-4-2-12"_expect);
|
||||
// Explanation:
|
||||
// Since the original TreeExplorer was assigned to variable kk,
|
||||
// Since the original IterExplorer was assigned to variable kk,
|
||||
// the materialise()-Function got a lvalue-ref and thus made a copy
|
||||
// of the whole compound. For that reason, the original state within
|
||||
// kk still rests at 7 -- because the filter evaluates eagerly, the
|
||||
|
|
@ -977,7 +977,7 @@ namespace test{
|
|||
void
|
||||
verify_FilterChanges()
|
||||
{
|
||||
auto seq = treeExplore(CountDown{20})
|
||||
auto seq = explore(CountDown{20})
|
||||
.mutableFilter();
|
||||
|
||||
auto takeEve = [](uint i){ return i%2 == 0; };
|
||||
|
|
@ -1036,7 +1036,7 @@ namespace test{
|
|||
|
||||
|
||||
// verify enabling and disabling...
|
||||
seq = treeExplore(CountDown{10})
|
||||
seq = explore(CountDown{10})
|
||||
.mutableFilter(takeTrd);
|
||||
|
||||
CHECK (9 == *seq);
|
||||
|
|
@ -1063,7 +1063,7 @@ namespace test{
|
|||
|
||||
/** @test package the resulting Iterator as automatically managed,
|
||||
* polymorphic opaque entity implementing the IterSource interface.
|
||||
* The builder operations on TreeExplorer each generate a distinct, implementation
|
||||
* The builder operations on IterExplorer each generate a distinct, implementation
|
||||
* defined type, which is meant to be captured by `auto`. However, the terminal builder
|
||||
* function `asIterSource()` moves the whole compound iterator object, as generated by
|
||||
* preceding builder steps, into a heap allocation and exposes a simplified front-end,
|
||||
|
|
@ -1088,7 +1088,7 @@ namespace test{
|
|||
IterSource<uint>::iterator sequence; // note `sequence` is polymorphic
|
||||
CHECK (isnil (sequence));
|
||||
|
||||
sequence = treeExplore(CountDown{20,10})
|
||||
sequence = explore(CountDown{20,10})
|
||||
.filter([](uint i){ return i % 2; })
|
||||
.asIterSource(); // note this terminal builder function
|
||||
// moves the whole pipeline onto the heap
|
||||
|
|
@ -1097,7 +1097,7 @@ namespace test{
|
|||
|
||||
|
||||
// use one sequence as source to build another one
|
||||
sequence = treeExplore(sequence)
|
||||
sequence = explore(sequence)
|
||||
.transform([](uint i){ return i*2; })
|
||||
.asIterSource();
|
||||
|
||||
|
|
@ -1117,7 +1117,7 @@ namespace test{
|
|||
IterExploreSource<char> exploreIter;
|
||||
CHECK (isnil (exploreIter));
|
||||
|
||||
exploreIter = treeExplore(CountDown{20,10})
|
||||
exploreIter = explore(CountDown{20,10})
|
||||
.filter([](uint i){ return i % 2; })
|
||||
.transform([](uint i){ return i*2; })
|
||||
.filter([](int i){ return i>25; })
|
||||
|
|
@ -1144,7 +1144,7 @@ namespace test{
|
|||
* Contrary to the preceding test case, here the point is to _base the whole pipeline_
|
||||
* on a data source accessible through the IterSource (VTable based) interface. The notable
|
||||
* point with this technique is the ability to use some _extended sub interface of IterSource_
|
||||
* and to rely on this interface to implement some functor bound into the TreeExplorer pipeline.
|
||||
* and to rely on this interface to implement some functor bound into the IterExplorer pipeline.
|
||||
* Especially this allows to delegate the "child expansion" through such an interface and just
|
||||
* return a compatible IterSource as result. This way, the opaque implementation gains total
|
||||
* freedom regarding the concrete implementation of the "child series" iterator. In fact,
|
||||
|
|
@ -1185,14 +1185,14 @@ namespace test{
|
|||
|
||||
|
||||
// simple standard case: create a new heap allocated IterSource implementation.
|
||||
// TreeExplorer will take ownership (by smart-ptr) and build a Lumiera Iterator front-End
|
||||
// IterExplorer will take ownership (by smart-ptr) and build a Lumiera Iterator front-End
|
||||
CHECK ("7-6-5-4-3-2-1" == materialise (
|
||||
treeExplore(new VerySpecificIter{7})));
|
||||
explore (new VerySpecificIter{7})));
|
||||
|
||||
|
||||
// missing source detected
|
||||
PrivateSource* niente = nullptr;
|
||||
CHECK (isnil (treeExplore(niente)));
|
||||
CHECK (isnil (explore (niente)));
|
||||
|
||||
|
||||
// attach to an IterSource living here in local scope...
|
||||
|
|
@ -1201,7 +1201,7 @@ namespace test{
|
|||
// ...and build a child expansion on top, which calls through the PrivateSource-API
|
||||
// Effectively this means we do not know the concrete type of the "expanded children" iterator,
|
||||
// only that it adheres to the same IterSource sub-interface as used on the base iterator.
|
||||
auto ii = treeExplore(vsit)
|
||||
auto ii = explore(vsit)
|
||||
.expand ([](PrivateSource& source){ return source.expandChildren(); });
|
||||
|
||||
CHECK (not isnil (ii));
|
||||
|
|
@ -1258,7 +1258,7 @@ namespace test{
|
|||
verify_depthFirstExploration()
|
||||
{
|
||||
CHECK (materialise(
|
||||
treeExplore(CountDown{4})
|
||||
explore(CountDown{4})
|
||||
.expand([](uint j){ return CountDown{j-1}; })
|
||||
.expandAll()
|
||||
.transform([](int i){ return i*10; })
|
||||
|
|
@ -1277,7 +1277,7 @@ namespace test{
|
|||
};
|
||||
|
||||
CHECK (materialise(
|
||||
treeExplore(CountDown{4})
|
||||
explore(CountDown{4})
|
||||
.transform([](uint i){ return Tu2{i,0}; })
|
||||
.expand(summingExpander)
|
||||
.expandAll()
|
||||
|
|
@ -1289,7 +1289,7 @@ namespace test{
|
|||
|
||||
|
||||
/** @test Demonstration how to build complex algorithms by layered tree expanding iteration
|
||||
* @remarks this is the actual use case which inspired the design of TreeExplorer:
|
||||
* @remarks this is the actual use case which inspired the design of IterExplorer:
|
||||
* Search with backtracking over an opaque (abstracted), tree-shaped search space.
|
||||
* - the first point to note is that the search algorithm knows nothing about its
|
||||
* data source, beyond its ability to delve down (expand) into child nodes
|
||||
|
|
@ -1316,7 +1316,7 @@ namespace test{
|
|||
{
|
||||
// Layer-1: the search space with "hidden" implementation
|
||||
using DataSrc = IterExploreSource<char>;
|
||||
DataSrc searchSpace = treeExplore(RandomSeq{-1})
|
||||
DataSrc searchSpace = explore(RandomSeq{-1})
|
||||
.expand([](char){ return RandomSeq{15}; })
|
||||
.asIterSource();
|
||||
|
||||
|
|
@ -1370,10 +1370,10 @@ namespace test{
|
|||
|
||||
|
||||
// Layer-3: Evaluation pipeline to drive search
|
||||
string toFind = util::join (treeExplore (RandomSeq{5}), "");
|
||||
string toFind = util::join (explore (RandomSeq{5}), "");
|
||||
cout << "Search in random tree: toFind = "<<toFind<<endl;
|
||||
|
||||
auto theSearch = treeExplore(State{searchSpace, toFind})
|
||||
auto theSearch = explore (State{searchSpace, toFind})
|
||||
.filter([](auto& it)
|
||||
{
|
||||
while (it->src.depth() < it->toFind.size() - 1
|
||||
|
|
@ -1392,7 +1392,7 @@ namespace test{
|
|||
|
||||
|
||||
|
||||
LAUNCHER (IterTreeExplorer_test, "unit common");
|
||||
LAUNCHER (IterExplorer_test, "unit common");
|
||||
|
||||
|
||||
}} // namespace lib::test
|
||||
|
|
@ -75,7 +75,7 @@ namespace test{
|
|||
*
|
||||
* @see value-type-binding.hpp
|
||||
* @see lib::RangeIter
|
||||
* @see lib::TreeExplorer::transform()
|
||||
* @see lib::IterExplorer::transform()
|
||||
*/
|
||||
class ValueTypeBinding_test
|
||||
: public Test
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
#include "lib/format-cout.hpp"
|
||||
#include "lib/format-util.hpp"
|
||||
#include "lib/meta/tuple-helper.hpp"
|
||||
#include "lib/iter-tree-explorer.hpp"
|
||||
#include "lib/iter-explorer.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
|
@ -200,7 +200,7 @@ namespace test{
|
|||
DiagnosticRenderer diagnostic;
|
||||
auto render = [&](Receiver& renderer)
|
||||
{
|
||||
return join (lib::treeExplore(tokens)
|
||||
return join (lib::explore(tokens)
|
||||
.transform ([&](Token tok)
|
||||
{
|
||||
return tok.applyTo (renderer);
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@
|
|||
** if this implementation can be used beyond this limited purpose
|
||||
**
|
||||
** @see UICoordResolver_test
|
||||
** @see IterTreeExplorer_test
|
||||
** @see IterExplorer_test
|
||||
** @see ui-coord-resolver.hpp
|
||||
** @see navigator.hpp
|
||||
*/
|
||||
|
|
@ -66,7 +66,7 @@
|
|||
#include "stage/interact/ui-coord-resolver.hpp"
|
||||
#include "lib/diff/gen-node.hpp"
|
||||
#include "lib/format-string.hpp"
|
||||
#include "lib/iter-tree-explorer.hpp"
|
||||
#include "lib/iter-explorer.hpp"
|
||||
#include "lib/iter-source.hpp"
|
||||
#include "lib/itertools.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ namespace test {
|
|||
* UI this would of course not be a configurable property of the
|
||||
* LocationQuery, but rather just reflect the transient window
|
||||
* state and return the currently activated window
|
||||
* @see IterTreeExplorer_test::verify_IterSource() regarding "child exploration"...
|
||||
* @see IterExplorer_test::verify_IterSource() regarding "child exploration"...
|
||||
*/
|
||||
void
|
||||
verify_backingQuery()
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
#include "lib/test/test-helper.hpp"
|
||||
#include "stage/model/canvas-hook.hpp"
|
||||
#include "lib/scoped-collection.hpp"
|
||||
#include "lib/iter-tree-explorer.hpp"
|
||||
#include "lib/iter-explorer.hpp"
|
||||
#include "lib/iter-adapter-stl.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
|
|
@ -84,7 +84,7 @@ namespace test {
|
|||
auto
|
||||
allWidgetIDs() const
|
||||
{
|
||||
return lib::treeExplore(widgets_)
|
||||
return lib::explore(widgets_)
|
||||
.transform([](Attachment const& entry)
|
||||
{
|
||||
return entry.widget.i;
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
#include "lib/test/test-helper.hpp"
|
||||
#include "stage/model/view-hook.hpp"
|
||||
#include "lib/scoped-collection.hpp"
|
||||
#include "lib/iter-tree-explorer.hpp"
|
||||
#include "lib/iter-explorer.hpp"
|
||||
#include "lib/iter-adapter-stl.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
|
|
@ -77,7 +77,7 @@ namespace test {
|
|||
auto
|
||||
allWidgetIDs() const
|
||||
{
|
||||
return lib::treeExplore(widgets_)
|
||||
return lib::explore(widgets_)
|
||||
.transform([](DummyWidget const& entry)
|
||||
{
|
||||
return entry.i;
|
||||
|
|
|
|||
Loading…
Reference in a new issue