From e6a105fbc1195b6950b849b1232714ec6d7f50e3 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Wed, 27 Jun 2012 02:50:36 +0200 Subject: [PATCH] iterator exploring monad finished, passes unit test --- src/lib/iter-explorer.hpp | 124 ++++++++++++++++++++++++++----- src/lib/iter-stack.hpp | 13 ++++ tests/40components.tests | 10 +++ tests/lib/iter-explorer-test.cpp | 5 +- 4 files changed, 130 insertions(+), 22 deletions(-) diff --git a/src/lib/iter-explorer.hpp b/src/lib/iter-explorer.hpp index ef2e1456f..6379cf6ea 100644 --- a/src/lib/iter-explorer.hpp +++ b/src/lib/iter-explorer.hpp @@ -50,6 +50,24 @@ ** - 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) ** + ** \par preconfigured solutions + ** This header provides some preconfigured applications of this pattern + ** - the DefaultCombinator processes the source elements on demand, feeding them through + ** the given functor and using the resulting iterator to deliver the result elements + ** - Chained iterator uses similar building blocks just to get the "flattening" of + ** a sequence of iterators into a single result iterator + ** - the RecursiveExhaustingEvaluation is another kind of combination strategy, + ** which recursively evaluates the given function and combines the results + ** such as to produce classical depth-first and breadth-first search orders. + ** + ** Alternatively, just the basic IterExplorer template can be used together with a custom + ** "combinator strategy" to implement very specific and optimised data structure evaluation patterns. + ** This strategy needs to define some way to hold onto the original source elements, feed them through + ** the functor on demand and recombine the result sets into a new sequence to be delivered on demand. + ** Actually this is what we utilise for the continuous render job generation within the scheduler. + ** The preconfigured variants where created as proof-of-concept, to document and verify this + ** implementation technique as such. + ** ** @see IterExplorer_test ** @see iter-adapter.hpp ** @see itertools.hpp @@ -63,7 +81,6 @@ #include "lib/error.hpp" -//#include "lib/bool-checkable.hpp" #include "lib/meta/function.hpp" #include "lib/iter-adapter.hpp" #include "lib/iter-stack.hpp" @@ -71,7 +88,6 @@ #include "lib/null-value.hpp" #include "lib/util.hpp" -//#include #include #include @@ -240,10 +256,16 @@ namespace lib { return *this; } }; - - - - + + + + + + + + + + namespace iter_explorer { ///< predefined policies and configurations using util::unConst; @@ -286,6 +308,7 @@ namespace lib { }; + /** * Building block: evaluate and combine a sequence of iterators. * This implementation helper provides two kinds of "buffers" (actually implemented @@ -313,7 +336,7 @@ namespace lib { typedef typename ResultIter::value_type value_type; typedef typename ResultIter::reference reference; typedef typename ResultIter::pointer pointer; - + CombinedIteratorEvaluation() { } @@ -474,6 +497,9 @@ namespace lib { + + + /** * A "Combinator strategy" allowing to expand and evaluate a * (functional) data structure successively and recursively. @@ -598,24 +624,29 @@ namespace lib { /** - * Strategy for recursive exhausting \em depth-first evaluation. - * Implemented using a heap-allocated stack of partially evaluated iterators. - * The next evaluation step will happen at the iterator returned by #getFeed, - * which is the most recently pushed intermediary result. + * Strategy building block for recursive exhausting evaluation. + * Allows to create depth-fist or breadth-first evaluation patters, just + * by using a suitably intermediary storage container to hold the partially + * evaluated iterators created at each evaluation step. Using a stack and + * pushing results will create a depth-first pattern, while using a queue + * will evaluate in layers (breadth-first). In both cases, the next + * evaluation step will happen at the iterator returned by #getFeed. * @warning uses an empty-iterator marker object to signal exhaustion * - this marker \c IT() may be re-initialised concurrently * - accessing this marker during app shutdown might access * an already defunct object */ - template - class DepthFirstEvaluationBuffer + template< class IT + , template class _QUEUE_ ///< the actual container to use for storage of intermediary results + > + class EvaluationBufferStrategy { - IterStack intermediaryResults_; + _QUEUE_ intermediaryResults_; /** @return default constructed (=empty) iterator * @remarks casting away const is safe here, since all - * you can do with an NIL iterator is to test for emptiness. + * you can do with an NIL iterator is to test for emptiness. */ IT & emptySequence() @@ -641,13 +672,35 @@ namespace lib { void feedBack (IT const& newEvaluationResults) { - intermediaryResults_.push (newEvaluationResults); + intermediaryResults_.insert (newEvaluationResults); } }; + /** - * preconfigured IterExplorer "state core" resulting in depth-first exhaustive evaluation + * concrete strategy for recursive \em depth-first evaluation. + * Using heap allocated storage in a STL Deque (used stack-like) + */ + template + struct DepthFirstEvaluationBuffer + : EvaluationBufferStrategy + { }; + + /** + * concrete strategy for recursive \em breadth-first evaluation. + * Using heap allocated storage in a STL Deque (used queue-like) + */ + template + struct BreadthFirstEvaluationBuffer + : EvaluationBufferStrategy + { }; + + + + /** + * preconfigured IterExplorer "state core" resulting in + * depth-first exhaustive evaluation */ template struct DepthFirstEvaluationConbinator @@ -660,6 +713,21 @@ namespace lib { { } }; + /** + * preconfigured IterExplorer "state core" resulting in + * breadth-first exhaustive evaluation + */ + template + struct BreadthFirstEvaluationConbinator + : RecursiveExhaustingEvaluation + { + BreadthFirstEvaluationConbinator() { } + + BreadthFirstEvaluationConbinator(FUN explorerFunction, SRC const& sourceElements) + : RecursiveExhaustingEvaluation (explorerFunction,sourceElements) + { } + }; + /** * Helper template to bootstrap a chain of IterExplorers. @@ -685,7 +753,7 @@ namespace lib { /* === Iteration control API for IterStateWrapper == */ - + friend bool checkPoint (WrappedSequence const& sequence) { @@ -716,12 +784,24 @@ namespace lib { { } }; + template + struct BreadthFirst + : IterExplorer, BreadthFirstEvaluationConbinator> + { + BreadthFirst() { }; + BreadthFirst(SRC const& srcSeq) + : IterExplorer, BreadthFirstEvaluationConbinator> (srcSeq) + { } + }; + }//(End) namespace iter_explorer : predefined policies and configurations + /* ==== convenient builder free functions ==== */ + template inline IterExplorer > exploreIter (IT const& srcSeq) @@ -738,6 +818,14 @@ namespace lib { } + template + inline iter_explorer::BreadthFirst + breadthFirst (IT const& srcSeq) + { + return iter_explorer::BreadthFirst (srcSeq); + } + + template inline iter_explorer::ChainedIters diff --git a/src/lib/iter-stack.hpp b/src/lib/iter-stack.hpp index 29f20b8a0..35206e91e 100644 --- a/src/lib/iter-stack.hpp +++ b/src/lib/iter-stack.hpp @@ -122,6 +122,13 @@ namespace lib { return *this; } + IterStack& + insert (TY const& elm) + { + return push(elm); + } + + TY pop() { @@ -162,6 +169,12 @@ namespace lib { return *this; } + IterQueue& + insert (TY const& elm) + { + return feed(elm); + } + TY pop() { diff --git a/tests/40components.tests b/tests/40components.tests index 856084940..cae759715 100644 --- a/tests/40components.tests +++ b/tests/40components.tests @@ -508,11 +508,21 @@ out: values_4_key(::[0-9]{1,2})+ END +TEST "Iterator monad variations" IterExplorer_test +out: 1-2-3-4-5-6-7-8 +out: 0-1-2-3-4-0-1-2-3-4-5-6-0-1-2-3-4-5-6-7-8 +out: 0-1-2-3-4-5-6-7-8 +out: 0-1-2-3-4-5-6-7-8 +END + + TEST "Stack-like iterator" IterStack_test +return: 0 END TEST "Queue-like iterator" IterQueue_test +return: 0 END diff --git a/tests/lib/iter-explorer-test.cpp b/tests/lib/iter-explorer-test.cpp index e8bcbbeff..60f8ddce3 100644 --- a/tests/lib/iter-explorer-test.cpp +++ b/tests/lib/iter-explorer-test.cpp @@ -52,8 +52,7 @@ namespace test{ using lumiera::error::LUMIERA_ERROR_ITER_EXHAUST; - namespace { // test material: simple number sequence iterator - + namespace { // test substrate: simple number sequence iterator /** * This iteration "state core" type describes @@ -444,11 +443,9 @@ namespace test{ void verifyBreadthFirstExploration () { -#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #892 NumberSeries root = elements(30); string explorationResult = materialise (breadthFirst(root) >>= exploreChildren); CHECK (explorationResult == "30-6-10-15-2-3-2-5-3-5-1-1-1-1-1-1"); -#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #892 }