LUMIERA.clone/src/lib/iter-explorer.hpp
Ichthyostega 7be1b7d35d Switch from TR1 preveiw to the new standard headers
- functional
- memory
- unordered collections
2014-04-03 22:42:48 +02:00

1007 lines
39 KiB
C++

/*
ITER-EXPLORER.hpp - building blocks for iterator evaluation strategies
Copyright (C) Lumiera.org
2012, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/** @file iter-explorer.hpp
** Helper template(s) for establishing various evaluation strategies for hierarchical data structures.
** Based on the <b>Lumiera Forward Iterator</b> concept and using the basic IterAdaptor templates,
** these components allow to implement typical evaluation strategies, like e.g. depth-first or
** breadth-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.
** The implementation is based on the IterStateWrapper, which is one of the basic helper templates
** provided by iter-adapter.hpp.
**
** \par Iterators as Monad
** The fundamental idea behind the implementation technique used here is the \em Monad pattern
** known from functional programming. A Monad is a (abstract) container created by using some specific functions.
** This is an rather abstract 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 \em bind a function into the monad; this function will work on the \em internals of the
** monad 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.
**
** \par 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. The transformation to apply can be selected at runtime (as a functor), and
** also the logic how to combine elements can be implemented elsewhere. The monad pattern defines a sane
** way of representing this 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)
**
** \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.
** - the more low-level RecursiveSelfIntegration combinator strategy actually
** delegates to the result set iterator implementation to perform the collecting
** and re-integrating of intermediary results. This approach is what we actually
** use in the proc::engine::Dispatcher
**
** Alternatively, just the basic IterExplorer template can be used together with a custom
** "combinator strategy" and typically even a specific iterator or sequence 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.
** All the other preconfigured variants defined here 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
** @see IterSource (completely opaque iterator)
**
*/
#ifndef LIB_ITER_EXPLORER_H
#define LIB_ITER_EXPLORER_H
#include "lib/error.hpp"
#include "lib/meta/function.hpp"
#include "lib/iter-adapter.hpp"
#include "lib/iter-stack.hpp"
#include "lib/meta/trait.hpp"
#include "lib/null-value.hpp"
#include "lib/util.hpp"
#include <boost/utility/enable_if.hpp>
#include <stack>
namespace lib {
namespace iter_explorer {
template<class SRC, class FUN>
class DefaultCombinator;
}
/**
* Adapter for using an Iterator in the way of a Monad
* This allows to "bind" or "flatMap" a functor, thereby creating
* a derived version of the iterator, yielding the (flattened) combination
* of all the results generated by this bound functor. The rationale is
* to apply some exploration or expansion pattern on the elements of the
* source sequence (source iterator) -- while completely separating out
* the \em mechanics how to treat and combine individual elements.
*
* \par implementation approach
* IterExplorer is a thin wrapper, based on IterStateWrapper; thus the assumption
* is for the actual elements to be generated by a "state core", which is embedded
* right into each instance. To provide the monad bind operator \c >>= , we need
* the help of a strategy template, the so called \em Combinator. This strategy
* contains the details how to combine the results of various iterators and
* to join them together into a single new IterExplorer instance. Thus, obviously
* this Combinator strategy template relies on additional knowledge about the
* source iterator's implementation. Such is unavoidable, since C++ isn't a
* functional programming language.
*
* When invoking the bind (flat map) operator, a suitably represented \em functor
* is embedded into an instance of the Combinator template. Moreover, a copy of
* the current IterExplorer is embedded alongside. The resulting object becomes
* the state core of the new IterExplorer object returned as result.
* So the result \em is an iterator, but -- when "pulled" -- it will in turn
* pull from the source iterator and feed the provided elements through the
* \em exploration functor, which this way has been \em bound into the resulting
* monad. The purpose of the Combinator strategy is to join together various
* resulting iterators, thereby "flattening" one level of "monad packaging"
* (hence the name "flat map operator").
*
* @remarks figuring out what happens here just from the code might lead to confusion.
* You really need to grasp the monad concept first, which is a design pattern
* commonly used in functional programming. For the practical purpose in question
* here, you might consider it a "programmable semicolon": it links together a
* chain of operations detailed elsewhere, and provided in a dynamic fashion
* (as functor at runtime). More specifically, these operations will expand
* and explore a dynamic source data set on the fly. Notably this allows
* us to handle such an "exploration" in a flexible way, without the need
* to allocate heap memory to store intermediary results, but also without
* using the stack and recursive programming.
* @warning be sure to consider the effects of copying iterators on any hidden state
* referenced by the source iterator(s). Basically any iterator must behave
* sane when copied while in iteration: IterExplorer first evaluates the
* head element of the source (the explorer function should build an
* independent, new result sequence based on this first element).
* Afterwards, the source is \em advanced and then \em copied
* into the result iterator.
* @warning IterExplorer and all the provided combination strategies are deliberately
* designed to work on sequences <b>of values</b>. These values will indeed
* be \em copied for invocation of the exploration function. The rationale
* for this choice is data locality and the danger of dangling references
* to an implicitly created temporary (since in it is so common practice
* in C++ to use \c const& ). Thus, if you need to work on references
* to a common data structure, you need to use either pointers or
* some reference wrapper explicitly as value type right from start.
* @param SRC the source sequence or iterator to wrap
* @param _COM_ "Combinator" strategy template. When binding (\c >>= ) a function,
* an instance of that strategy becomes the new SRC for the created new
* IterExplorer. This instantiation of the strategy gets as type parameters:
* - this IterExplorer's instance type
* - the type of the function bound with \c >>=
*/
template<class SRC
,template<class,class> class _COM_ = iter_explorer::DefaultCombinator
>
class IterExplorer
: public IterStateWrapper<typename SRC::value_type, SRC>
{
public:
typedef typename SRC::value_type value_type;
typedef typename SRC::reference reference;
typedef typename SRC::pointer pointer;
/** Metafunction: the resulting type when binding ("flat mapping")
* a functor of type FUN. Basically the result of binding a function
* is again an IterExplorer (with an "expanded" state core type) */
template<class FUN>
struct FlatMapped
{
typedef IterExplorer<_COM_<IterExplorer,FUN>, _COM_> Type;
};
/** by default create an empty iterator */
IterExplorer() { }
/** wrap an iterator-like state representation
* to build it into a monad. The resulting entity
* is both an iterator yielding the elements generated
* by the core, and it provides the (monad) bind operator.
*/
explicit
IterExplorer (SRC const& iterStateCore)
: IterStateWrapper<value_type, SRC> (iterStateCore)
{ }
/** monad bind ("flat map") operator.
* Using a specific function to explore and work
* on the "contents" of this IterExplorer, with the goal
* to build a new IterExplorer combining the results of this
* function application. The enclosing IterExplorer instance
* provides a Strategy template _COM_, which defines how those
* results are actually to be combined. An instantiation of
* this "Combinator" strategy becomes the state core
* of the result iterator.
*/
template<class FUN>
typename FlatMapped<FUN>::Type
operator >>= (FUN explorer)
{
typedef _COM_<IterExplorer,FUN> Combinator; // instantiation of the combinator strategy
typedef typename FlatMapped<FUN>::Type ResultsIter; // result IterExplorer using that instance as state core
return ResultsIter (
Combinator (explorer // build a new iteration state core
,accessRemainingElements())); // based on a copy of this iterator / sequence
}
private:
IterExplorer const&
accessRemainingElements()
{
return *this;
}
};
namespace iter_explorer { ///< predefined policies and configurations
using util::unConst;
using boost::enable_if;
using boost::disable_if;
using std::function;
using meta::_Fun;
/**
* Building block: evaluating 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.
*/
template<class SIG>
struct ExploreByFunction
: function<SIG>
{
template<typename FUN>
ExploreByFunction(FUN explorationFunctionDefinition)
: function<SIG>(explorationFunctionDefinition)
{ }
ExploreByFunction() { } ///< by default initialised to bottom function
};
/**
* Support for a special use case: an Iterator of Iterators, joining results.
* In this case, already the source produces a sequence of Iterators, which
* just need to be passed through to the output buffer unaltered. Using this
* within the DefaultCombinator strategy creates a combined, flattened iterator
* of all the source iterator's contents.
*/
template<class SIG>
struct UnalteredPassThrough;
template<class IT>
struct UnalteredPassThrough<IT(IT)>
{
IT operator() (IT elm) const { return elm; }
bool operator! () const { return false; } ///< identity function is always valid
};
/**
* Building block: evaluate and combine a sequence of iterators.
* This implementation helper provides two kinds of "buffers" (actually implemented
* as iterators): A result buffer (iterator) which holds a sequence of already prepared
* result elements, which can be retrieved through iteration right away. And a supply buffer
* (iterator) holding raw source elements. When the result buffer is exhausted, the next source
* element will be pulled from there and fed through the "evaluation strategy", which typically
* is a function processing the source element and producing a new result buffer (iterator).
*/
template<class SRC, class FUN
,template<class> class _EXP_ = ExploreByFunction ///< Strategy: how to store and evaluate the function to apply on each element
>
class CombinedIteratorEvaluation
{
typedef typename _Fun<FUN>::Ret ResultIter;
typedef typename SRC::value_type SrcElement;
typedef _EXP_<ResultIter(SrcElement)> Explorer;
SRC srcSeq_;
ResultIter results_;
Explorer explorer_;
public:
typedef typename ResultIter::value_type value_type;
typedef typename ResultIter::reference reference;
typedef typename ResultIter::pointer pointer;
CombinedIteratorEvaluation() { }
CombinedIteratorEvaluation(FUN explorerFunction)
: srcSeq_()
, results_()
, explorer_(explorerFunction)
{ }
// using standard copy operations
void
setSourceSequence (SRC const& followUpSourceElements)
{
REQUIRE (explorer_);
srcSeq_ = followUpSourceElements;
}
private:
bool
findNextResultElement()
{
while (!results_ && srcSeq_)
{
results_ = explorer_(*srcSeq_);
++srcSeq_;
}
return bool(results_);
}
/* === Iteration control API for IterStateWrapper== */
friend bool
checkPoint (CombinedIteratorEvaluation const& seq)
{
return unConst(seq).findNextResultElement();
}
friend reference
yield (CombinedIteratorEvaluation const& seq)
{
return *(seq.results_);
}
friend void
iterNext (CombinedIteratorEvaluation & seq)
{
++(seq.results_);
}
};
/**
* 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.
* @note the implementation stores the functor into a std::function object,
* which might cause heap allocations, depending on given function.
* 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
* when the initial results are exhausted.
*/
template<class SRC, class FUN>
class DefaultCombinator
: public CombinedIteratorEvaluation<SRC,FUN>
{
typedef typename _Fun<FUN>::Ret ResultIter;
public:
DefaultCombinator() { }
DefaultCombinator(FUN explorerFunction, SRC const& sourceElements)
: CombinedIteratorEvaluation<SRC,FUN>(explorerFunction)
{
this->setSourceSequence (sourceElements);
}
};
/** Metafunction to detect an iterator yielding an iterator sequence */
template<class IT>
struct _is_iterator_of_iterators
{
typedef typename IT::value_type IteratorElementType;
enum{ value = meta::can_IterForEach<IteratorElementType>::value };
};
template<class ITI, class SEQ>
class ChainedIteratorImpl
: public CombinedIteratorEvaluation<ITI, SEQ(SEQ)
, UnalteredPassThrough
>
{ };
/**
* Special iterator configuration for combining / flattening the
* results of a sequence of iterators. This sequence of source iterators
* is assumed to be available as "Iterator yielding Iterators".
* The resulting class is a Lumiera Forward Iterator, delivering all the
* elements of all source iterators in sequence.
* @remarks this is quite similar to the IterExplorer monad, but without
* binding an exploration function to produce the result sequences.
* Rather, the result sequences are directly pulled from the source
* sequence, which thus needs to be an "Iterator of Iterators".
* Beyond that, the implementation relies on the same building
* blocks as used for the full-blown IterExplorer.
* @param ITI iterator of iterators
* @param SEQ type of the individual sequence (iterator).
* The value_type of this sequence will be the overall
* resulting value type of the flattened sequence
*/
template<class ITI, class SEL = void>
class ChainedIters;
template<class ITI>
class ChainedIters<ITI, typename enable_if< _is_iterator_of_iterators<ITI> >::type
>
: public IterStateWrapper<typename ITI::value_type::value_type
,ChainedIteratorImpl<ITI, typename ITI::value_type>
>
{
public:
ChainedIters(ITI const& iteratorOfIterators)
{ // note: default ctor on parent -> empty sequences
this->stateCore().setSourceSequence (iteratorOfIterators);
}
};
/**
* Convenience specialisation: manage the sequence of iterators automatically.
* @note in this case the \em first template parameter denotes the \em element sequence type;
* we use a IterStack to hold the sequence-of-iterators in heap storage.
* @warning this specialisation will not be picked, if the \em value-type
* of the given iterator is itself an iterator
*/
template<class SEQ>
class ChainedIters<SEQ, typename disable_if< _is_iterator_of_iterators<SEQ> >::type
>
: public IterStateWrapper<typename SEQ::value_type
,ChainedIteratorImpl<IterStack<SEQ>, SEQ>
>
{
public:
typedef IterStack<SEQ> IteratorIterator;
ChainedIters(IteratorIterator const& iteratorOfIterators)
{
this->stateCore().setSourceSequence (iteratorOfIterators);
}
/** empty result sequence by default */
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. (While this contradicts
* the full requirements for building a Monad, we can always work around that kind
* of restriction by producing the element type of the target sequence by implicit
* type conversion)
*
* \par strategy requirements
* 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, this 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.
* - \c Strategy::getFeed() accesses the point from where
* to pull the next element to be expanded. This function <i>must not</i>
* yield an empty sequence, \em unless the overall exploration is exhausted
* - \c Strategy::feedBack() re-integrates the results of an expansion step
*/
template<class SRC, class FUN
,template<class> class _BUF_
>
class RecursiveExhaustingEvaluation
{
typedef typename _Fun<FUN>::Ret ResultIter;
typedef typename SRC::value_type Val; // note: deliberately using the value
typedef function<ResultIter(Val)> Explorer;
typedef _BUF_<ResultIter> Buffer;
Buffer resultBuf_;
Explorer explore_;
public:
typedef typename ResultIter::value_type value_type;
typedef typename ResultIter::reference reference;
typedef typename ResultIter::pointer pointer;
RecursiveExhaustingEvaluation (Explorer fun, SRC const& src)
: resultBuf_()
, explore_(fun)
{
resultBuf_.feedBack(
initEvaluation (src));
}
RecursiveExhaustingEvaluation() { };
// standard copy operations
private:
/** Extension point: build the initial evaluation state
* based on the source sequence (typically an IterExplorer).
* This is a tricky problem, since the source sequence is not
* necessarily assignment compatible to the ResultIter type
* and there is no general method to build a ResultIter.
* The solution is to rely on a "builder trait", which
* needs to be defined alongside with the concrete
* ResultIter type. The actual builder trait will
* be picked up through a free function (ADL). */
ResultIter
initEvaluation (SRC const& initialElements)
{
ResultIter startSet;
return build(startSet).usingSequence(initialElements);
} // extension point: free function build (...)
/** @note \c _BUF_::getFeed is required to yield a non-empty sequence,
* until everything is exhausted. Basically the buffer- and re-integrated
* result sequences can be expected to be pulled until finding the next
* non-empty supply. This is considered hidden internal state and thus
* concealed within this \em const and \em idempotent function.
*/
ResultIter &
feed() const
{
return unConst(this)->resultBuf_.getFeed();
}
void
iterate ()
{
REQUIRE (feed());
ResultIter nextStep = explore_(*feed());
++ feed();
resultBuf_.feedBack (nextStep);
}
/* === Iteration control API for IterStateWrapper== */
friend bool
checkPoint (RecursiveExhaustingEvaluation const& seq)
{
return bool(seq.feed());
}
friend reference
yield (RecursiveExhaustingEvaluation const& seq)
{
reference result = *(seq.feed());
return result;
}
friend void
iterNext (RecursiveExhaustingEvaluation & seq)
{
seq.iterate();
}
};
/**
* 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 IT
, template<class> class _QUEUE_ ///< the actual container to use for storage of intermediary results
>
class EvaluationBufferStrategy
{
_QUEUE_<IT> 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.
*/
IT &
emptySequence()
{
return unConst(NullValue<IT>::get());
} // unsafe during shutdown
public:
IT &
getFeed ()
{
// fast forward to find the next non-empty result sequence
while (intermediaryResults_ && ! *intermediaryResults_)
++intermediaryResults_;
if (intermediaryResults_)
return *intermediaryResults_;
else
return emptySequence();
}
void
feedBack (IT const& newEvaluationResults)
{
intermediaryResults_.insert (newEvaluationResults);
}
};
/**
* concrete strategy for recursive \em depth-first evaluation.
* Using heap allocated storage in a STL Deque (used stack-like)
*/
template<class IT>
struct DepthFirstEvaluationBuffer
: EvaluationBufferStrategy<IT, IterStack>
{ };
/**
* concrete strategy for recursive \em breadth-first evaluation.
* Using heap allocated storage in a STL Deque (used queue-like)
*/
template<class IT>
struct BreadthFirstEvaluationBuffer
: EvaluationBufferStrategy<IT, IterQueue>
{ };
/**
* preconfigured IterExplorer "state core" resulting in
* depth-first exhaustive evaluation
*/
template<class SRC, class FUN>
struct DepthFirstEvaluationConbinator
: RecursiveExhaustingEvaluation<SRC, FUN, DepthFirstEvaluationBuffer>
{
DepthFirstEvaluationConbinator() { }
DepthFirstEvaluationConbinator(FUN explorerFunction, SRC const& sourceElements)
: RecursiveExhaustingEvaluation<SRC, FUN, DepthFirstEvaluationBuffer> (explorerFunction,sourceElements)
{ }
};
/**
* preconfigured IterExplorer "state core" resulting in
* breadth-first exhaustive evaluation
*/
template<class SRC, class FUN>
struct BreadthFirstEvaluationConbinator
: RecursiveExhaustingEvaluation<SRC, FUN, BreadthFirstEvaluationBuffer>
{
BreadthFirstEvaluationConbinator() { }
BreadthFirstEvaluationConbinator(FUN explorerFunction, SRC const& sourceElements)
: RecursiveExhaustingEvaluation<SRC, FUN, BreadthFirstEvaluationBuffer> (explorerFunction,sourceElements)
{ }
};
/**
* IterExplorer "state core" for progressively expanding
* an initial result set. This initial set can be conceived to hold the seed
* or starting points of evaluation. Elements are consumed by an iterator, at
* the front. Each element is fed to the "explorer function". This exploration
* returns an expanded result sequence, which is immediately integrated into the
* overall result sequence, followed by further exploration of the then-to-be first
* element of the result sequence. All this exploration is driven on-demand, by
* consuming the result sequence. Exploration will proceed until exhaustion,
* in which case the exploration function will yield an empty result set.
*
* This strategy is intended for use with the IterExplorer -- most prominently
* in use for discovering render prerequisites and creating new render jobs for
* the engine. The RecursiveSelfIntegration strategy is a partially reduced
* and hard-coded variation on the #RecursiveExhaustingEvaluation in depth-first
* configuration.
* This setup works in conjunction with a <i>special result sequence</i> type,
* with the ability to re-integrate results yielded by partial evaluation.
* But the working pattern is more similar to the #CombinedIteratorEvaluation,
* where the focal point of further expansion is always at the front end of
* further items yet to be consumed and expanded; thus the evaluation is
* bound to proceed depth-first (i.e. it is \em not possible to "integrate"
* any intermediary result with the \em whole result set, only with the part
* reachable immediately at the evaluation front)
*
* \par usage considerations
* There needs to be a specific sequence or iterator type, which is used to
* hold the result set(s). This custom type together with the Explorer function
* are performing the actual expansion and re-integration steps. The latter is
* accessed through the free function \c build(sequence) -- which is expected
* to return a "builder trait" for manipulating the element set yielded by
* the custom iterator type returned by the Explorer function.
*
* @param SRC the initial result set sequence; this iterator needs to yield
* values of the special ResultIter type, which are then expanded
* until exhaustion by repeated calls to the Explorer function
* @param FUN the Explorer function of type ResultIter -> ResultIter
* @note the ResultIter type is defined implicitly through the result type
* of the Explorer function. Similarly the result value type
* is defined through the typedef \c ResultIter::value_type
*/
template<class SRC, class FUN>
class RecursiveSelfIntegration
{
typedef typename _Fun<FUN>::Ret ResultIter;
typedef typename SRC::value_type Val;
typedef function<ResultIter(Val)> Explorer;
SRC srcSeq_;
ResultIter outSeq_;
Explorer explore_;
public:
typedef typename ResultIter::value_type value_type;
typedef typename ResultIter::reference reference;
typedef typename ResultIter::pointer pointer;
RecursiveSelfIntegration (Explorer fun, SRC const& src)
: srcSeq_(src)
, outSeq_()
, explore_(fun)
{ }
RecursiveSelfIntegration() { };
// standard copy operations
private:
/** assure the next elements to be processed
* will appear at outSeq_ head. When outSeq_
* is still empty after this function,
* we're done.
* @note \em not calling this function after
* construction, because the typical user
* of this template will do that implicitly
* through invocation of #checkPoint */
bool
findNextResultElement()
{
while (!outSeq_ && srcSeq_)
{
Val& nextElement(*srcSeq_);
build(outSeq_).wrapping(nextElement); // extension point: free function build(...).wrapping(...)
++srcSeq_;
}
return bool(outSeq_);
}
void
iterate ()
{
REQUIRE (outSeq_);
ResultIter nextSteps = explore_(*outSeq_);
++ outSeq_;
build(outSeq_).usingSequence(nextSteps); // extension point: free function build(...).usingSequence(...)
}
/* === Iteration control API for IterStateWrapper== */
friend bool
checkPoint (RecursiveSelfIntegration const& seq)
{
return unConst(seq).findNextResultElement();
}
friend reference
yield (RecursiveSelfIntegration const& seq)
{
return *(seq.outSeq_);
}
friend void
iterNext (RecursiveSelfIntegration & seq)
{
seq.iterate();
}
};
/**
* Helper template to bootstrap a chain of IterExplorers.
* This is a "state core", which basically just wraps a given
* source iterator and provides the necessary free functions
* (iteration control API) to use this as iteration state
* within IterExplorer.
* @note to ease building such an initial version of the Iterator Monad,
* use the free function \link #exploreIter \endlink
*/
template<class IT>
class WrappedSequence
: public IT
{
public:
WrappedSequence()
: IT()
{ }
WrappedSequence(IT const& srcIter)
: IT(srcIter)
{ }
/* === Iteration control API for IterStateWrapper == */
friend bool
checkPoint (WrappedSequence const& sequence)
{
return bool(sequence);
}
friend typename IT::reference
yield (WrappedSequence const& sequence)
{
return *sequence;
}
friend void
iterNext (WrappedSequence & sequence)
{
++sequence;
}
};
template<class SRC>
struct DepthFirst
: IterExplorer<WrappedSequence<SRC>, DepthFirstEvaluationConbinator>
{
DepthFirst() { };
DepthFirst(SRC const& srcSeq)
: IterExplorer<WrappedSequence<SRC>, DepthFirstEvaluationConbinator> (srcSeq)
{ }
};
template<class SRC>
struct BreadthFirst
: IterExplorer<WrappedSequence<SRC>, BreadthFirstEvaluationConbinator>
{
BreadthFirst() { };
BreadthFirst(SRC const& srcSeq)
: IterExplorer<WrappedSequence<SRC>, BreadthFirstEvaluationConbinator> (srcSeq)
{ }
};
}//(End) namespace iter_explorer : predefined policies and configurations
/* ==== convenient builder free functions ==== */
template<class IT>
inline IterExplorer<iter_explorer::WrappedSequence<IT> >
exploreIter (IT const& srcSeq)
{
return IterExplorer<iter_explorer::WrappedSequence<IT> > (srcSeq);
}
template<class IT>
inline iter_explorer::DepthFirst<IT>
depthFirst (IT const& srcSeq)
{
return iter_explorer::DepthFirst<IT> (srcSeq);
}
template<class IT>
inline iter_explorer::BreadthFirst<IT>
breadthFirst (IT const& srcSeq)
{
return iter_explorer::BreadthFirst<IT> (srcSeq);
}
template<class IT>
inline iter_explorer::ChainedIters<IT>
iterChain(IT const& seq)
{
typename iter_explorer::ChainedIters<IT>::IteratorIterator sequenceOfIterators;
sequenceOfIterators.push (seq);
return iter_explorer::ChainedIters<IT>(sequenceOfIterators);
}
template<class IT>
inline iter_explorer::ChainedIters<IT>
iterChain(IT const& seq1, IT const& seq2)
{
typename iter_explorer::ChainedIters<IT>::IteratorIterator sequenceOfIterators;
sequenceOfIterators.push (seq2);
sequenceOfIterators.push (seq1);
return iter_explorer::ChainedIters<IT>(sequenceOfIterators);
}
template<class IT>
inline iter_explorer::ChainedIters<IT>
iterChain(IT const& seq1, IT const& seq2, IT const& seq3)
{
typename iter_explorer::ChainedIters<IT>::IteratorIterator sequenceOfIterators;
sequenceOfIterators.push (seq3);
sequenceOfIterators.push (seq2);
sequenceOfIterators.push (seq1);
return iter_explorer::ChainedIters<IT>(sequenceOfIterators);
}
template<class IT>
inline iter_explorer::ChainedIters<IT>
iterChain(IT const& seq1, IT const& seq2, IT const& seq3, IT const& seq4)
{
typename iter_explorer::ChainedIters<IT>::IteratorIterator sequenceOfIterators;
sequenceOfIterators.push (seq4);
sequenceOfIterators.push (seq3);
sequenceOfIterators.push (seq2);
sequenceOfIterators.push (seq1);
return iter_explorer::ChainedIters<IT>(sequenceOfIterators);
}
template<class IT>
inline iter_explorer::ChainedIters<IT>
iterChain(IT const& seq1, IT const& seq2, IT const& seq3, IT const& seq4, IT const& seq5)
{
typename iter_explorer::ChainedIters<IT>::IteratorIterator sequenceOfIterators;
sequenceOfIterators.push (seq5);
sequenceOfIterators.push (seq4);
sequenceOfIterators.push (seq3);
sequenceOfIterators.push (seq2);
sequenceOfIterators.push (seq1);
return iter_explorer::ChainedIters<IT>(sequenceOfIterators);
}
} // namespace lib
#endif