diff --git a/src/lib/iter-explorer.hpp b/src/lib/iter-explorer.hpp index ad334b5c4..cda3b3adc 100644 --- a/src/lib/iter-explorer.hpp +++ b/src/lib/iter-explorer.hpp @@ -257,7 +257,7 @@ namespace lib { - namespace iter_explorer { ///< predefined policies and configurations + namespace iter_explorer { ///< predefined "exploration strategies", policies and configurations using util::unConst; using boost::enable_if; @@ -267,7 +267,7 @@ namespace lib { /** - * Building block: evaluating source elements. + * Building block: just evaluate source elements. * This strategy will be tied into a "Combinator" * to hold the actual functor bound into the enclosing * IterExplorer monad to work on the contained elements. @@ -386,9 +386,9 @@ namespace lib { /** * a generic "Combinator strategy" for IterExplorer. * This default / fallback solution doesn't assume anything beyond the - * source and the intermediary result(s) being Lumiera Forward Iterators. + * source and the intermediary result(s) to be Lumiera Forward Iterators. * @note the implementation stores the functor into a std::function object, - * which might cause heap allocations, depending on given function. + * which might cause heap allocations, depending on the function given. * Besides, the implementation holds one instance of the (intermediary) * result iterator (yielded by invoking the function) and a copy of the * original IterExplorer source sequence, to get the further elements diff --git a/src/lib/itertools.hpp b/src/lib/itertools.hpp index 4d6e622ae..92ed94a61 100644 --- a/src/lib/itertools.hpp +++ b/src/lib/itertools.hpp @@ -29,8 +29,8 @@ ** based on the Lumiera Forward Iterator concept. They build on generic ** programming techniques, thus are intended to be combined at compile time ** using definitive type information. Contrast this to an iterator model - ** as in Java's Commons-Collections, where Iterator is an Interface based - ** on virtual functions. Thus, the basic problem to overcome is the lack + ** as in Java's Collections, where Iterator is an Interface based on + ** virtual functions. Thus, the basic problem to overcome is the lack ** of a single common interface, which could serve as foundation for ** type inference. As a solution, we use a "onion" approach, where a ** generic base gets configured with an active core, implementing @@ -55,10 +55,9 @@ ** source iterator. The signature of the functor must match the ** desired value (output) type. ** - ** @todo WIP WIP WIP - ** @todo see Ticket #347 + ** @todo some more building blocks are planned, see Ticket #347 ** - ** @see IterAdapter + ** @see iter-adapter.hpp ** @see itertools-test.cpp ** @see contents-query.hpp */ @@ -142,15 +141,16 @@ namespace lib { * Standard functionality to build up any iterator tool. * IterTool exposes the frontend functions necessary to * comply to the Lumiera Forward Iterator concept. - * The protected part provides the building blocks - * to implement the actual processing/filter logic. + * The protected part provides the _iteration control_ + * building blocks to drive the processing/filter logic, + * which is implemented in the specific core for each tool. */ template class IterTool : public lib::BoolCheckable > { - protected: /* iteration control */ + protected: /* == iteration control == */ CORE core_; bool @@ -158,7 +158,7 @@ namespace lib { { return core_.evaluate() || unConst(this)->iterate(); - } // skipping irrelevant results doesn't count as "mutation" + } // to skip irrelevant results doesn't count as "mutation" bool iterate () @@ -351,7 +351,41 @@ namespace lib { /** - * Helper: predicate returning \c true + * Additional capabilities for FilterIter, + * allowing to extend the filter condition underway. + * This wrapper enables remoulding of the filer functor + * while in the middle of iteration. When the filter is + * modified, current head of iteration gets re-evaluated + * and possible fast-forwarded to the next element + * satisfying the now extended filter condition. + */ + template + class ExtensibleFilterIter + : public FilterIter + { + typedef FilterCore _Filter; + typedef typename _Filter::Val Val; + + public: + template + ExtensibleFilterIter& + andFilter (COND conjunctiveClause) + { + function& filter = this->core_.predicate_; + + filter = [=](Val val) + { + return filter(val) + and conjunctiveClause(val); + }; + return *this; + } + }; + + + + /** + * Helper: predicate returning `true` * whenever the argument value changes * during a sequence of invocations. */ diff --git a/src/lib/test/event-log.hpp b/src/lib/test/event-log.hpp index be73cae7d..bfce0245d 100644 --- a/src/lib/test/event-log.hpp +++ b/src/lib/test/event-log.hpp @@ -73,19 +73,20 @@ namespace test{ { friend class EventLog; - MegaPlonk solution_; +// MegaPlonk solution_; bool eval() { - return !isnil (solution_); + UNIMPLEMENTED ("evaluate current filter condition"); +// return !isnil (solution_); } void enforce() { if (!eval()) - throw error::State("jaleck", error::LUMIERA_ERROR_ASSERTION) + throw error::State("jaleck", error::LUMIERA_ERROR_ASSERTION); } public: @@ -117,7 +118,7 @@ namespace test{ EventMatch& after (string match) { - solution_ = solution_ >>= find(match); +// solution_ = solution_ >>= find(match); enforce(); } diff --git a/tests/library/iter-explorer-test.cpp b/tests/library/iter-explorer-test.cpp index 91ed3d690..66733c260 100644 --- a/tests/library/iter-explorer-test.cpp +++ b/tests/library/iter-explorer-test.cpp @@ -192,6 +192,13 @@ namespace test{ * @test use a simple source iterator yielding numbers * to build various functional evaluation structures, * based on the IterExplorer template. + * - the [state adapter][verifyStateAdapter] iterator + * construction pattern + * - helper to [chain iterators][verifyChainedIterators] + * - building [tree exploring structures][verifyDepthFirstExploration] + * - the [monadic nature][verifyMonadOperator] of IterExplorer + * - a [recursively self-integrating][verifyRecrusiveSelfIntegration] + * evaluation pattern * * \par Explanation * Both this test and the IterExplorer template might be bewildering @@ -212,7 +219,7 @@ namespace test{ * In such a situation, it is beneficial to develop and test both * in isolation. The IterExplorer template applies this pattern * to the task of processing a source sequence. Typically we use - * this in situations where we can't effort building elaborate + * this in situations where we can't afford building elaborate * data structures in (global) memory, but rather strive at * doing everything on-the-fly. A typical example is the * processing of a variably sized data set without @@ -240,13 +247,17 @@ namespace test{ - /** @test all of the following IterExplorer flavours are built on top - * of a special iterator adapter, centred at the notion of an iterable + /** @test demonstrate the underlying solution approach of IterExplorer. + * All of the following IterExplorer flavours are built on top of + * a special iterator adapter, centred at the notion of an iterable * state element type. The actual iterator just embodies one element * of this state representation, and typically this element alone holds - * all the relevant state and information, without any hidden back-link - * to some kind of container in charge of the elements yielded. - * Essentially this means the iterator is self contained. + * all the relevant state and information. Essentially this means the + * iterator is self contained. Contrast this to the more conventional + * approach of iterator implementation, where the iterator entity actually + * maintains a hidden back-link to some kind of container, which in turn + * is the one in charge of the elements yielded by the iterator. + * */ void verifyStateAdapter () @@ -275,7 +286,9 @@ namespace test{ - /** @test a convenient helper built using IterExplorer building blocks. + /** @test verify a helper to chain a series of iterators into a + * "flat" result sequence. This convenience helper is built using + * IterExplorer building blocks. * The resulting iterator \em combines and \em flattens a sequence * of source iterators, resulting in a simple sequence accessible * as iterator again. Here we verify the convenience / default @@ -419,7 +432,7 @@ namespace test{ * * @note technical detail: the result type of the exploration function (here \c exploreChildren() ) determines * the iterator type used within IterExplorer and to drive the evaluation. The source sequence used to - * seed the evaluation process actually can be any iterator yielding assignment compatible values: The + * seed the evaluation process can actually be any iterator yielding assignment compatible values: The * second example uses a NumberSequence with unsigned int values 0..6, while the actual expansion and * evaluation is based on NumberSeries using signed int values. */ @@ -454,8 +467,8 @@ namespace test{ - /** @test a variation of recursive exploration, this time directly - * relying on the result set iterator type to provide the re-integration + /** @test verify a variation of recursive exploration, this time to rely + * directly on the result set iterator type to provide the re-integration * of intermediary results. Since our \c exploreChildren() function returns * a NumberSeries, which basically is a IterQueue, the re-integration of expanded * elements will happen at the end, resulting in breadth-first visitation order -- @@ -465,7 +478,9 @@ namespace test{ * \link #verifyBreadthFirstExploration \endlink, appears here at the end of the * explorationResult sequence * @remarks this "combinator strategy" is really intended for use with custom sequences, - * where the "Explorer" function works together with a specific implementation. + * where the "Explorer" function works together with a specific implementation + * and exploits knowledge about specifically tailored additional properties of + * the input sequence elements to yield the desired overall effect. * Actually this is what we use in the proc::engine::Dispatcher to generate a * series of frame render jobs, including all prerequisite jobs */ @@ -534,6 +549,7 @@ namespace test{ // the ">>=" associates to the right, while the proper monad bind operator should associate to the left } + /** @internal exploration function used in ::verifyMonadOperator */ static NumberSequence explode (uint top) {