add an transforming iterator to the itertools

This commit is contained in:
Fischlurch 2009-11-13 03:26:20 +01:00
parent a86517bd4f
commit d0c905b5c9
3 changed files with 191 additions and 12 deletions

View file

@ -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 <tr1/functional>
@ -91,7 +99,7 @@ namespace lib {
template<class IT>
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<class CX>
friend bool operator== (IterTool<CX> const& it1, IterTool<CX> const& it2);
};
@ -229,8 +233,8 @@ namespace lib {
inline bool
operator== (IterTool<CX> const& it1, IterTool<CX> 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 IT, class VAL>
class TransformingCore
{
typedef typename IT::reference InType;
function<VAL(InType)> 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<typename FUN>
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 IT, class VAL>
class TransformIter
: public IterTool<TransformingCore<IT,VAL> >
{
typedef TransformingCore<IT,VAL> _Trafo;
typedef IterTool<_Trafo> _IteratorImpl;
public:
TransformIter ()
: _IteratorImpl(_Trafo())
{ }
template<typename FUN>
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<typename SIG>
struct _ProducedOutput
{
typedef typename FunctionSignature<function<SIG> >::Ret Type;
};
template<typename SIG>
struct _ProducedOutput<function<SIG> >
{
typedef typename FunctionSignature<function<SIG> >::Ret Type;
};
template<typename FUN>
struct _ProducedOutput<FUN*>
{
typedef typename FunctionSignature<function<FUN> >::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<class IT, typename FUN>
inline TransformIter<IT, typename _ProducedOutput<FUN>::Type>
transformIterator (IT const& src, FUN processingFunc)
{
typedef typename _ProducedOutput<FUN>::Type OutVal;
return TransformIter<IT,OutVal>(src,processingFunc);
}
} // namespace lib
#endif

View file

@ -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

View file

@ -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<Iter, int> idi (ii, idFunc);
TransformIter<Iter, int> 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<class IT>