From 8db54131999afa2ed7ac4be4c42e3e879609c062 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 4 Jun 2012 02:35:00 +0200 Subject: [PATCH] implemented chained-iterators ...using the IterExplorer building blocks --- src/lib/iter-explorer.hpp | 161 ++++++++++++++++++++++++++++--- tests/lib/iter-explorer-test.cpp | 22 ++--- 2 files changed, 157 insertions(+), 26 deletions(-) diff --git a/src/lib/iter-explorer.hpp b/src/lib/iter-explorer.hpp index a9a939419..1df055788 100644 --- a/src/lib/iter-explorer.hpp +++ b/src/lib/iter-explorer.hpp @@ -66,9 +66,13 @@ //#include "lib/bool-checkable.hpp" #include "lib/meta/function.hpp" #include "lib/iter-adapter.hpp" +#include "lib/iter-stack.hpp" +#include "lib/meta/trait.hpp" #include "lib/util.hpp" //#include +#include +#include namespace lib { @@ -239,7 +243,7 @@ namespace lib { return this->operator* (); } - IterExplorer& + IterExplorer const& accessRemainingElements() { this->operator++ (); @@ -253,6 +257,8 @@ namespace lib { namespace iter_explorer { ///< predefined policies and configurations using util::unConst; + using boost::enable_if; + using boost::disable_if; /** * Building block: evaluating source elements. @@ -286,6 +292,7 @@ namespace lib { struct UnalteredPassThrough { IT operator() (IT elm) const { return elm; } + bool operator! () const { return false; } ///< identity function is always valid }; @@ -336,7 +343,7 @@ namespace lib { } void - setSourceSequence (SRC & followUpSourceElements) + setSourceSequence (SRC const& followUpSourceElements) { REQUIRE (explorer_); srcSeq_ = followUpSourceElements; @@ -407,26 +414,94 @@ namespace lib { } void - followUp (SRC & followUpSourceElements) + followUp (SRC const& followUpSourceElements) { this->setSourceSequence (followUpSourceElements); } }; - /** - * Special configuration for combining / flattening the results - * of a sequence of iterators - */ - template - class ChainedIters + + template + struct _is_iterator_of_iterators { - /////////////TODO unimplemented + typedef typename IT::value_type IteratorElementType; + + enum{ value = meta::can_IterForEach::value }; + }; + + + template + class ChainedIteratorImpl + : public CombinedIteratorEvaluation + { }; + + + /** + * 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 ChainedIters; + + template + class ChainedIters >::type + > + : public IterStateWrapper + > + { + 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 ChainedIters >::type + > + : public IterStateWrapper, SEQ> + > + { + public: + typedef IterStack IteratorIterator; + + ChainedIters(IteratorIterator const& iteratorOfIterators) + { + this->stateCore().setSourceSequence (iteratorOfIterators); + } + + /** empty result sequence by default */ + ChainedIters() { } }; /** * Helper template to bootstrap a chain of IterExplorers. - * This is a "state corer", which basically just wraps a given + * 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. @@ -474,16 +549,74 @@ namespace lib { template - IterExplorer > + inline IterExplorer > exploreIter (IT const& srcSeq) { return IterExplorer > (srcSeq); } - - + template + inline iter_explorer::ChainedIters + iterChain(IT const& seq) + { + typename iter_explorer::ChainedIters::IteratorIterator sequenceOfIterators; + + sequenceOfIterators.push (seq); + return iter_explorer::ChainedIters(sequenceOfIterators); + } + + template + inline iter_explorer::ChainedIters + iterChain(IT const& seq1, IT const& seq2) + { + typename iter_explorer::ChainedIters::IteratorIterator sequenceOfIterators; + + sequenceOfIterators.push (seq2); + sequenceOfIterators.push (seq1); + return iter_explorer::ChainedIters(sequenceOfIterators); + } + + template + inline iter_explorer::ChainedIters + iterChain(IT const& seq1, IT const& seq2, IT const& seq3) + { + typename iter_explorer::ChainedIters::IteratorIterator sequenceOfIterators; + + sequenceOfIterators.push (seq3); + sequenceOfIterators.push (seq2); + sequenceOfIterators.push (seq1); + return iter_explorer::ChainedIters(sequenceOfIterators); + } + + template + inline iter_explorer::ChainedIters + iterChain(IT const& seq1, IT const& seq2, IT const& seq3, IT const& seq4) + { + typename iter_explorer::ChainedIters::IteratorIterator sequenceOfIterators; + + sequenceOfIterators.push (seq4); + sequenceOfIterators.push (seq3); + sequenceOfIterators.push (seq2); + sequenceOfIterators.push (seq1); + return iter_explorer::ChainedIters(sequenceOfIterators); + } + + template + inline iter_explorer::ChainedIters + iterChain(IT const& seq1, IT const& seq2, IT const& seq3, IT const& seq4, IT const& seq5) + { + typename iter_explorer::ChainedIters::IteratorIterator sequenceOfIterators; + + sequenceOfIterators.push (seq5); + sequenceOfIterators.push (seq4); + sequenceOfIterators.push (seq3); + sequenceOfIterators.push (seq2); + sequenceOfIterators.push (seq1); + return iter_explorer::ChainedIters(sequenceOfIterators); + } + diff --git a/tests/lib/iter-explorer-test.cpp b/tests/lib/iter-explorer-test.cpp index 070fbbeca..02db3beeb 100644 --- a/tests/lib/iter-explorer-test.cpp +++ b/tests/lib/iter-explorer-test.cpp @@ -52,6 +52,7 @@ namespace test{ using std::endl; using std::string; using lib::LinkedElements; + using lib::iter_explorer::ChainedIters; using lumiera::error::LUMIERA_ERROR_ITER_EXHAUST; @@ -206,7 +207,6 @@ namespace test{ verifyStateAdapter(); verifyMonadOperator (); - UNIMPLEMENTED ("IterExplorer Monad"); verifyChainedIterators(); verifyRawChainedIterators(); @@ -249,20 +249,19 @@ namespace test{ - /** @test a simple and practical helper built on top of IterExplorer. + /** @test a convenient helper built using IterExplorer building blocks. * The resulting iterator \em combines and \em flattens a sequence * of source iterators, resulting in a simple sequence accessible - * again as iterator. Here we verify the convenience / default - * implementation; it uses a STL container behind the scenes - * to keep track of all the added source iterators + * as iterator again. Here we verify the convenience / default + * implementation; it uses a STL container (actually std:deque) + * behind the scenes to keep track of all added source iterators. */ void verifyChainedIterators () { -#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #892 typedef ChainedIters Chain; - Chain ci = iter::chain (seq(5),seq(7),seq(9)); + Chain ci = iterChain (seq(5),seq(7),seq(9)); CHECK (!isnil (ci)); pullOut (ci); @@ -271,11 +270,11 @@ namespace test{ VERIFY_ERROR (ITER_EXHAUST, ++ci ); CHECK (isnil(Chain())); - CHECK (iter::chain (NIL_Sequence)); + CHECK (!iterChain (NIL_Sequence)); - // Iterator chaining "flattens" one level of indirection + // Iterator chaining "flattens" one level of packaging NumberSequence s9 = seq(9); - ci = iter::chain (s9); + ci = iterChain (s9); for ( ; s9 && ci; ++s9, ++ci ) CHECK (*s9 == *ci); @@ -288,7 +287,7 @@ namespace test{ // per-instance state (like e.g. NumberSequence used for this test), // then the created chain is independent from the source iterators. s9 = seq(9); - ci = iter::chain (s9); + ci = iterChain (s9); CHECK (0 == *s9); CHECK (0 == *ci); @@ -297,7 +296,6 @@ namespace test{ CHECK (0 == *s9); pullOut (s9); CHECK (isnil(s9)); -#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #892 }