add an transforming iterator to the itertools
This commit is contained in:
parent
a86517bd4f
commit
d0c905b5c9
3 changed files with 191 additions and 12 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Reference in a new issue