diff --git a/src/lib/iter-explorer.hpp b/src/lib/iter-explorer.hpp index aa27c363b..cc03ea2bd 100644 --- a/src/lib/iter-explorer.hpp +++ b/src/lib/iter-explorer.hpp @@ -26,7 +26,7 @@ ** 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 IterableStateWrapper, which is one of the basic helper templates + ** The implementation is based on the IterStateWrapper, which is one of the basic helper templates ** provided by iter-adapter.hpp. ** ** @see IterExplorer_test.cpp @@ -43,42 +43,290 @@ #include "lib/error.hpp" //#include "lib/bool-checkable.hpp" +#include "lib/meta/function.hpp" #include "lib/iter-adapter.hpp" //#include namespace lib { + namespace { // internal helpers + + using std::tr1::function; + using meta::FunctionSignature; + + /** + * Helper to dissect an arbitrary function signature, + * irrespective if the parameter is given as function reference, + * function pointer, member function pointer or functor object. + * The base case assumes a (language) function reference. + */ + template + struct _Fun + { + typedef typename FunctionSignature >::Ret Ret; + typedef typename FunctionSignature >::Args Args; + }; + /** Specialisation for using a function pointer */ + template + struct _Fun + { + typedef typename FunctionSignature >::Ret Ret; + typedef typename FunctionSignature >::Args Args; + }; + /** Specialisation for passing a functor */ + template + struct _Fun > + { + typedef typename FunctionSignature >::Ret Ret; + typedef typename FunctionSignature >::Args Args; + }; + + + + } - + + namespace iter_explorer { + + template + class DefaultCombinator; + } + /** - * Adapter for building.... - * TODO write type comment + * 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. 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" on-the-fly, without the need to + * allocate heap memory to store intermediary results, but also without + * using the stack and recursive programming. */ - template + template class _COM_ = iter_explorer::DefaultCombinator + > class IterExplorer -// : public lib::BoolCheckable > + : public IterStateWrapper { -// CON source_; -// mutable POS pos_; + + typedef typename SRC::value_type value_type; + typedef typename SRC::reference reference; + + public: -// typedef typename iter::TypeBinding::pointer pointer; -// typedef typename iter::TypeBinding::reference reference; -// typedef typename iter::TypeBinding::value_type value_type; + /** 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 (iterStateCore) + { } - protected: /* === xxx === */ + /** monad bind ("flat map") operator */ + template + IterExplorer<_COM_, _COM_> + operator >>= (FUN explorer) + { + typedef _COM_ Combinator; + + return IterExplorer( + Combinator(explorer) + .startWith( explorer(accessFirstElement())) + .followUp (accessRemainingElements())); + } - /** */ private: + + reference + accessFirstElement() + { + return this->operator* (); + } + + IterExplorer& + accessRemainingElements() + { + this->operator++ (); + return *this; + } }; + + + + + namespace iter_explorer { ///< predefined policies and configurations + + + /** + * a generic "Combinator strategy" for IterExplorer. + * This fallback solution just assumes that the source is a + * Lumiera Forward Iterator -- consequently we need to do heap + * allocations behind the scenes, as the size and structure of + * the expansion results is determined at runtime. + * @note the whole purpose of IterExplorer is to be more efficient + * then this fallback, thus requiring more specific Combinator + * strategies, able to exploit specific knowledge of the + * source iterator's implementation. + */ + template + class DefaultCombinator + { + typedef typename _Fun::Ret ResultIter; + + public: + typedef typename ResultIter::value_type value_type; + typedef typename ResultIter::reference reference; + typedef typename ResultIter::pointer pointer; + + + + DefaultCombinator(FUN explorer) + { + UNIMPLEMENTED ("representation of the sequence of partial results"); + } + + DefaultCombinator & + startWith (ResultIter firstExplorationResult) + { + UNIMPLEMENTED ("DefaultCombinator: yield first result"); + return *this; + } + + template + DefaultCombinator& + followUp (SRC followUpSourceElements) + { + UNIMPLEMENTED ("DefaultCombinator: follow up iteration"); + return *this; + } + + + /* === Iteration control API for IterStateWrapper== */ + + friend bool + checkPoint (DefaultCombinator const& sequence) + { + UNIMPLEMENTED ("how to determine exhausted state on the combined results"); + return false; + } + + friend reference + yield (DefaultCombinator const& sequence) + { + UNIMPLEMENTED ("how to yield a result from the combined iterator"); + } + + friend void + iterNext (DefaultCombinator & sequence) + { + UNIMPLEMENTED ("increment the source iterator and switch to the next partial result sequence if necessary"); + } + + }; + + + /** + * Helper template to bootstrap a chain of IterExplorers. + * This is a "state corer", 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 WrappedSequence + : public IT + { + public: + WrappedSequence() + : IT() + { } + + WrappedSequence(IT const& srcIter) + : IT(srcIter) + { } + + + /* === Iteration control API for IterStateWrapper == */ + + inline bool + checkPoint (WrappedSequence const& sequence) + { + return bool(sequence); + } + + inline typename IT::reference + yield (WrappedSequence const& sequence) + { + return *sequence; + } + + inline void + iterNext (WrappedSequence & sequence) + { + ++sequence; + } + }; + + }//(End) namespace iter_explorer : predefined policies and configurations + + + + + template + IterExplorer > + exploreIter (IT const& srcSeq) + { + return IterExplorer > (srcSeq); + } + + + + + diff --git a/src/lib/linked-elements.hpp b/src/lib/linked-elements.hpp index 9bb76b4df..c12342dc0 100644 --- a/src/lib/linked-elements.hpp +++ b/src/lib/linked-elements.hpp @@ -520,6 +520,13 @@ namespace lib { return !head_; } + private: + /** + * Iteration is just following the single linked list. + * We encapsulate this simple pointer into a dedicated marker type + * to ease the handling and mixing of iterators and const iterators. + * (Explanation: IterationState depends on our type parameters...) + */ struct IterationState { N* node; @@ -535,7 +542,8 @@ namespace lib { } }; - typedef IterStateWrapper iterator; + public: + typedef IterStateWrapper< N, IterationState> iterator; typedef IterStateWrapper const_iterator; diff --git a/tests/lib/iter-explorer-test.cpp b/tests/lib/iter-explorer-test.cpp index e29768c62..71e0f5ffc 100644 --- a/tests/lib/iter-explorer-test.cpp +++ b/tests/lib/iter-explorer-test.cpp @@ -38,20 +38,6 @@ namespace lib { - - namespace iter { - - template<> - struct TypeBinding - { - typedef uint value_type; - typedef uint const& reference; - typedef uint const* pointer; - }; - } - - - namespace test{ using ::Test; @@ -71,6 +57,10 @@ namespace test{ // uint NUM_ELMS = 10; + /** + * This iteration state type describes + * a sequence of numbers still to be delivered. + */ class State { uint p,e; @@ -103,7 +93,10 @@ namespace test{ - /** */ + /** + * A straight number sequence as basic test iterator. + * The tests will dress up this source sequence in various ways. + */ class NumberSequence : public IterStateWrapper { @@ -117,7 +110,7 @@ namespace test{ : IterStateWrapper (State(start,end)) { } }; - + inline NumberSequence seq (uint end) { @@ -135,7 +128,7 @@ namespace test{ /** Diagnostic helper: "squeeze out" the given iterator - * and join all yielded elements into a string + * and join all the elements yielded into a string */ template inline string @@ -150,7 +143,7 @@ namespace test{ return buff.str(); } - } // (END) impl test dummy container + } // (END) test helpers