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
This commit is contained in:
parent
75df583607
commit
41180eb99c
2 changed files with 107 additions and 47 deletions
|
|
@ -225,28 +225,17 @@ namespace lib {
|
|||
typedef _COM_<IterExplorer,FUN> Combinator; // instantiation of the combinator strategy
|
||||
typedef IterExplorer<Combinator, _COM_> 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<SRC,FUN>(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 SRC, class FUN
|
||||
,template<class> class _BUF_
|
||||
>
|
||||
class RecursiveExhaustingEvaluation
|
||||
{
|
||||
typedef typename _Fun<FUN>::Ret ResultIter;
|
||||
typedef typename SRC::value_type Val;
|
||||
typedef typename SRC::reference reference;
|
||||
typedef function<ResultIter(Val)> Explorer;
|
||||
typedef _BUF_<Val> 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
|
||||
|
|
|
|||
|
|
@ -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<NumberSequence> 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<NumberSequence> 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
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue