From 41180eb99cb991107b1dc09cd8e66750e444e44b Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 12 Jun 2012 05:22:08 +0200 Subject: [PATCH] rework to allow for recursive evaluation this enables expansion of a (functional) data structure until exhaustion -- which is what we need to build job functors by traversing and expanding an arbitrarily nested job definition structure --- src/lib/iter-explorer.hpp | 129 +++++++++++++++++++++++-------- tests/lib/iter-explorer-test.cpp | 25 +++--- 2 files changed, 107 insertions(+), 47 deletions(-) diff --git a/src/lib/iter-explorer.hpp b/src/lib/iter-explorer.hpp index 1df055788..569f9050b 100644 --- a/src/lib/iter-explorer.hpp +++ b/src/lib/iter-explorer.hpp @@ -225,28 +225,17 @@ namespace lib { typedef _COM_ Combinator; // instantiation of the combinator strategy typedef IterExplorer ResultsIter; // result IterExplorer using that instance as state core - Combinator combinator(explorer); // build a new iteration state core - if (this->isValid()) // if source iterator isn't empty... - { - combinator.startWith( explorer(accessHeadElement())); // immediately apply the function to the first element - combinator.followUp (accessRemainingElements()); // and provide state to allow for continued exploration later - } - return ResultsIter (combinator); + return ResultsIter ( + Combinator (explorer // build a new iteration state core + ,accessRemainingElements())); // based on a copy of this iterator / sequence } private: - reference - accessHeadElement() - { - return this->operator* (); - } - IterExplorer const& accessRemainingElements() { - this->operator++ (); return *this; } }; @@ -336,12 +325,6 @@ namespace lib { // using standard copy operations - void - setResultSequence (ResultIter firstExplorationResult) - { - results_ = firstExplorationResult; - } - void setSourceSequence (SRC const& followUpSourceElements) { @@ -402,21 +385,10 @@ namespace lib { public: DefaultCombinator() { } - DefaultCombinator(FUN explorerFunction) + DefaultCombinator(FUN explorerFunction, SRC const& sourceElements) : CombinedIteratorEvaluation(explorerFunction) - { } - - - void - startWith (ResultIter firstExplorationResult) - { - this->setResultSequence (firstExplorationResult); - } - - void - followUp (SRC const& followUpSourceElements) - { - this->setSourceSequence (followUpSourceElements); + { + this->setSourceSequence (sourceElements); } }; @@ -499,6 +471,95 @@ namespace lib { ChainedIters() { } }; + + + /** + * A "Combinator strategy" allowing to expand and evaluate a + * (functional) data structure successively and recursively. + * Contrary to the DefaultCombinator, here the explorer is evaluated + * repeatedly, feeding back the results until exhaustion. The concrete + * exploration function needs to embody some kind of termination condition, + * e.g. by returning an empty sequence at some point, otherwise infinite + * recursion might happen. Another consequence of this repeated re-evaluation + * is the requirement of the source sequence's element type to be compatible + * to the result sequence's element type -- we can't \em transform the contents + * of the source sequence into another data type, just explore and expand those + * contents into sub-sequences based on the same data type. + * + * To build a concrete combinator a special strategy template is required to define + * the actual implementation logic how to proceed with the evaluation (i.e. how to + * find the feed of the "next elements" and how to re-integrate the results of an + * evaluation step into the already expanded sequence of intermediary results. + * Moreover, these implementation strategy pattern is used as a data buffer + * to hold those intermediary results. Together, this allows to create + * various expansion patterns, e.g. depth-first or breadth-first. + */ + template class _BUF_ + > + class RecursiveExhaustingEvaluation + { + typedef typename _Fun::Ret ResultIter; + typedef typename SRC::value_type Val; + typedef typename SRC::reference reference; + typedef function Explorer; + typedef _BUF_ Buffer; + + SRC srcSequence_; + Buffer resultBuf_; + Explorer explore_; + + + public: + RecursiveExhaustingEvaluation() { }; + + RecursiveExhaustingEvaluation (Explorer fun, SRC const& src) + : srcSequence_(src) + , resultBuf_() + , explore_(fun) + { } + + // standard copy operations + + + private: + ResultIter & + feed() + { + return resultBuf_.getFeed (srcSequence_); + } + + void + iterate () + { + ResultIter nextStep = explore_(*feed()); + ++ feed(); + resultBuf_.feedBack (nextStep); + } + + + /* === Iteration control API for IterStateWrapper== */ + + friend bool + checkPoint (RecursiveExhaustingEvaluation const& seq) + { + return bool(unConst(seq).feed()); + } + + friend reference + yield (RecursiveExhaustingEvaluation const& seq) + { + return *(unConst(seq).feed()); + } + + friend void + iterNext (RecursiveExhaustingEvaluation & seq) + { + seq.iterate(); + } + }; + + /** * Helper template to bootstrap a chain of IterExplorers. * This is a "state core", which basically just wraps a given diff --git a/tests/lib/iter-explorer-test.cpp b/tests/lib/iter-explorer-test.cpp index ad7aaf01e..150a3c050 100644 --- a/tests/lib/iter-explorer-test.cpp +++ b/tests/lib/iter-explorer-test.cpp @@ -368,15 +368,14 @@ namespace test{ * \par Test data structure * We build a functional datastructure here, on the fly, while exploring it. * The \c exploreChildren(m) function generates this tree like datastructure: - * For a given node with number value i, it returns the children (2*i-1) and 2*i - * -- but only up to the given maximum value m. + * For a given number, it tries to divide by 5, 3 and 2 respectively, possibly + * generating multiple decimation sequences. * - * If we start such a tree structure with a root node 1, and maximum = 8, this yields: + * If we start such a tree structure e.g. with a root node 30, this scheme yields: * \code - * ( 1 ) - * ( 1 2 ) - * ( 1 2 3 4 ) - * (1 2 3 4 5 6 7 8) + * ( 30 ) + * ( 6 10 15 ) + * ( 2 3 2 5 3 5 ) * \endcode * This tree has no meaning in itself, beyond being an easy testbed for tree exploration schemes. * @@ -401,10 +400,10 @@ namespace test{ { #if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #892 typedef DepthFirstExplorer DepthFirst; - DepthFirst root (seq(1)); + DepthFirst root (seq(30)); - string explorationResult = materialise(root >>= exploreChildren(8)); - CHECK (explorationResult == "1-1-1-1-2-2-3-4-2-3-5-6-4-7-8"); + string explorationResult = materialise(root >>= exploreChildren); + CHECK (explorationResult == "30-6-2-3-10-2-5-15-3-5"); #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #892 } @@ -421,10 +420,10 @@ namespace test{ { #if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #892 typedef BreadthFirstExplorer BreadthFirst; - BreadthFirst root (seq(1)); + BreadthFirst root (seq(30)); - string explorationResult = materialise(root >>= exploreChildren(8)); - CHECK (explorationResult == "1-1-2-1-2-3-4-1-2-3-4-5-6-7-8"); + string explorationResult = materialise(root >>= exploreChildren); + CHECK (explorationResult == "30-6-10-15-2-3-2-5-3-5"); #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #892 }