diff --git a/src/lib/itertools.hpp b/src/lib/itertools.hpp index 2e730634f..b6fa7fb47 100644 --- a/src/lib/itertools.hpp +++ b/src/lib/itertools.hpp @@ -38,7 +38,7 @@ ** (IterTool) exposes the operations necessary to comply to the ** Forward Iterator Concept. ** - ** \par Filtering Iterator + ** \par filtering Iterator ** The FilterIter template can be used to build a filter into a pipeline, ** as it forwards only those elements from its source iterator, which pass ** the predicate evaluation. Anything acceptable as ctor parameter for a @@ -46,8 +46,15 @@ ** signature must be sensible. Please note, that -- depending on the ** predicate -- already the ctor or even a simple \c bool test might ** pull and exhaust the source iterator completely, in an attempt - ** to find the first element passing the predicate test. - ** + ** to find the first element passing the predicate test. + ** + ** \par processing Iterator + ** the TransformIter template can be used as processing (or transforming) + ** step within the pipeline. It is created with a functor, which, when + ** pulling elements, is invoked for each element pulled from the + ** source iterator. The signature of the functor must match the + ** desired value (output) type. + ** ** @todo WIP WIP WIP ** @todo see Ticket #347 ** @@ -63,6 +70,7 @@ #include "lib/bool-checkable.hpp" #include "lib/iter-adapter.hpp" +#include "lib/meta/function.hpp" #include "lib/util.hpp" #include @@ -91,7 +99,7 @@ namespace lib { template struct IdentityCore { - mutable IT source_; + IT source_; IdentityCore (IT const& orig) : source_(orig) @@ -218,10 +226,6 @@ namespace lib { return !isValid(); } - - /// comparison is allowed to access the feed pipe from core - template - friend bool operator== (IterTool const& it1, IterTool const& it2); }; @@ -229,8 +233,8 @@ namespace lib { inline bool operator== (IterTool const& it1, IterTool const& it2) { - return it1.isValid() == it2.isValid() - && it1.core_.pipe() == it2.core_.pipe() + return (!it1 && !it2 ) + || ( it1 && it2 && (*it1) == (*it2) ) ; } @@ -322,5 +326,145 @@ namespace lib { + + + + + /** + * Implementation of custom processing logic. + * This core stores a function object instance + * to treat each source element pulled. + */ + template + class TransformingCore + { + typedef typename IT::reference InType; + + function trafo_; + + IT source_; + VAL treated_; + + void + processItem () + { + if (source_) + treated_ = trafo_(*source_); + } + + VAL* + yieldResult () const + { + if (source_) + return &unConst(this)->treated_; // accessing processed value doesn't count as "mutation" of *this + else + return 0; // signalling exhausted source + } + + + public: + TransformingCore () ///< deactivated core + : trafo_() + , source_() + , treated_() + { } + + template + TransformingCore (IT const& orig, FUN processor) + : trafo_(processor) // induces a signature check + , source_(orig) + { + processItem(); + } + + VAL * + pipe () const + { + return yieldResult(); + } + + void + advance () + { + ++source_; + processItem(); + } + + bool + evaluate () const + { + return bool(source_); + } + + typedef VAL* pointer; + typedef VAL& reference; + typedef VAL value_type; + }; + + + /** + * Iterator tool treating pulled data by a custom transformation (function) + */ + template + class TransformIter + : public IterTool > + { + typedef TransformingCore _Trafo; + typedef IterTool<_Trafo> _IteratorImpl; + + public: + TransformIter () + : _IteratorImpl(_Trafo()) + { } + + template + TransformIter (IT const& src, FUN trafoFunc) + : _IteratorImpl(_Trafo(src,trafoFunc)) + { } + + }; + + + + namespace { // Helper to pick up the produced value type automatically + + using lumiera::typelist::FunctionSignature; + + template + struct _ProducedOutput + { + typedef typename FunctionSignature >::Ret Type; + }; + + template + struct _ProducedOutput > + { + typedef typename FunctionSignature >::Ret Type; + }; + + template + struct _ProducedOutput + { + typedef typename FunctionSignature >::Ret Type; + }; + } + + + /** Build a TransformIter: convenience free function shortcut, + * picking up the involved types automatically. + * @param processingFunc to be invoked for each source element + * @return Iterator processing the source feed + */ + template + inline TransformIter::Type> + transformIterator (IT const& src, FUN processingFunc) + { + typedef typename _ProducedOutput::Type OutVal; + return TransformIter(src,processingFunc); + } + + + + } // namespace lib #endif diff --git a/tests/40components.tests b/tests/40components.tests index adc44631e..bcdfa0f3c 100644 --- a/tests/40components.tests +++ b/tests/40components.tests @@ -334,6 +334,9 @@ out: ::19::17::15::13::11::9::7::5::3::1 out: ::17::16::15::14::13::12::11::10::9::8::7::6::5::4::3::2::1 out: ::16::14::12::10::8::6::4::2 out: ::17::15::13::11::9::7::5::3::1 +out: ::10::9::8::7::6::5::4::3::2::1 +out: ::-10::-9::-8::-7::-6::-5::-4::-3::-2::-1 +out: ::12::11::10::9::8::7::6::5::4::3 END diff --git a/tests/lib/itertools-test.cpp b/tests/lib/itertools-test.cpp index baa74bc11..8599f080f 100644 --- a/tests/lib/itertools-test.cpp +++ b/tests/lib/itertools-test.cpp @@ -78,7 +78,7 @@ namespace test{ /******************************************************************************* * @test build combined and filtering iterators with the help of lib::IterTool. - * Check correct behaviour of the resulting iterator and + * Check correct behaviour of the resulting iterators and * verify they fulfil the Lumiera Forward Iterator concept * * @todo implement more iterator tools.... see Ticket #347 @@ -104,6 +104,8 @@ namespace test{ Iter ii (source.begin()); ++++++ii; buildFilterIterator (ii); + + buildTransformingIterator (source.begin()); } @@ -120,8 +122,8 @@ namespace test{ static bool takeAll (int) { return true; } - static bool takeEve (int i) { return 0 == i % 2; } static bool takeOdd (int i) { return 0 != i % 2; } + static bool takeEve (int i) { return 0 == i % 2; } void buildFilterIterator (Iter const& ii) @@ -145,6 +147,36 @@ namespace test{ + static ulong addTwo (int i) { return i+2; } + static int negate (int i) { return -i; } + static int idFunc (int i) { return i; } + + void + buildTransformingIterator (Iter const& ii) + { + pullOut (transformIterator(ii, idFunc)); + pullOut (transformIterator(ii, negate)); + pullOut (transformIterator(ii, addTwo)); // note: changing output type to unsigned + + TransformIter idi (ii, idFunc); + TransformIter neg (ii, negate); + verifyComparisons (idi); + verifyComparisons (neg); + + ASSERT (idi); + ASSERT (neg); + for ( ;idi&&neg; + ++idi,++neg) + ASSERT (idi != neg); + + ASSERT (!idi && !neg); + ASSERT (idi == neg); + } + + + + + /** @test verify equality handling and NIL detection * for the given iterator/wrapper handed in */ template