simple number range iterator
very similar to boost::irange, but without heavyweight boost includes, and moreover based on our Lumiera Forward Iterator concept Such a inline-range construct makes writing simple tests easy
This commit is contained in:
parent
3fef76e1d7
commit
8a33048cc7
3 changed files with 160 additions and 3 deletions
|
|
@ -519,6 +519,125 @@ namespace lib {
|
|||
|
||||
|
||||
|
||||
/**
|
||||
* Enumerate all "numbers" within a range.
|
||||
* This allows to build pipelines based on all
|
||||
* numbers "for `i` from `1...N`". This range is _half open_,
|
||||
* i.e. the start is inclusive and the end point is exclusive.
|
||||
* @remarks basically this is `boost::irange` without any boost `#include`
|
||||
* @tparam INT a number like type, which can be incremented and compared.
|
||||
*/
|
||||
template<typename INT>
|
||||
class NumIter
|
||||
: public lib::BoolCheckable<NumIter<INT>>
|
||||
{
|
||||
INT i_;
|
||||
INT e_;
|
||||
|
||||
public:
|
||||
typedef const INT* pointer;
|
||||
typedef const INT& reference;
|
||||
typedef const INT value_type;
|
||||
|
||||
NumIter (INT start, INT end)
|
||||
: i_(start)
|
||||
, e_(end)
|
||||
{ }
|
||||
|
||||
template<typename X>
|
||||
NumIter (X&& start, X&& end)
|
||||
: i_(std::forward<X>(start))
|
||||
, e_(std::forward<X>(end))
|
||||
{ }
|
||||
|
||||
NumIter ()
|
||||
: i_()
|
||||
, e_()
|
||||
{ }
|
||||
|
||||
// standard copy operations acceptable
|
||||
|
||||
|
||||
|
||||
/* === lumiera forward iterator concept === */
|
||||
|
||||
reference
|
||||
operator*() const
|
||||
{
|
||||
_maybe_throw();
|
||||
return i_;
|
||||
}
|
||||
|
||||
pointer
|
||||
operator->() const
|
||||
{
|
||||
_maybe_throw();
|
||||
return &i_;
|
||||
}
|
||||
|
||||
NumIter&
|
||||
operator++()
|
||||
{
|
||||
_maybe_throw();
|
||||
++i_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool
|
||||
isValid () const
|
||||
{
|
||||
return (i_!= INT()) && (i_ != e_);
|
||||
}
|
||||
|
||||
bool
|
||||
empty () const
|
||||
{
|
||||
return not isValid();
|
||||
}
|
||||
|
||||
|
||||
/** access wrapped index elements */
|
||||
const INT& getPos() const { return i_; }
|
||||
const INT& getEnd() const { return e_; }
|
||||
|
||||
|
||||
ENABLE_USE_IN_STD_RANGE_FOR_LOOPS (NumIter);
|
||||
|
||||
|
||||
private:
|
||||
void
|
||||
_maybe_throw() const
|
||||
{
|
||||
if (!isValid())
|
||||
_throwIterExhausted();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// Supporting equality comparisons...
|
||||
template<class I1, class I2>
|
||||
bool operator== (NumIter<I1> const& il, NumIter<I2> const& ir) { return (!il && !ir) || (il.getPos() == ir.getPos()); }
|
||||
|
||||
template<class I1, class I2>
|
||||
bool operator!= (NumIter<I1> const& il, NumIter<I2> const& ir) { return !(il == ir); }
|
||||
|
||||
|
||||
|
||||
/** convenience function to iterate "each number" */
|
||||
template<typename INT>
|
||||
inline NumIter<INT>
|
||||
eachNum (INT start, INT end)
|
||||
{
|
||||
return NumIter<INT> (start, end);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Helper for type rewritings:
|
||||
* get the element type for an iterator like entity
|
||||
|
|
|
|||
|
|
@ -170,8 +170,11 @@ END
|
|||
|
||||
|
||||
TEST "Lumiera Iterator Concept" IterAdapter_test 20 <<END
|
||||
out: ::20::19::18::17::16::15::14::13::12::11::10::9::8::7::6::5::4::3::2::1
|
||||
out: ::0::1::2::3::4::5::6::7::8::9::10::11::12::13::14::15::16::17::18::19
|
||||
out-lit: ::20::19::18::17::16::15::14::13::12::11::10::9::8::7::6::5::4::3::2::1
|
||||
out-lit: ::20::19::18::17::16::15::14::13::12::11::10::9::8::7::6::5::4::3::2::1
|
||||
out-lit: ++21++22++23++24++25++26++27++28++29++30++31++32++33++34++35++36++37++38++39
|
||||
out-lit: ::0::1::2::3::4::5::6::7::8::9::10::11::12::13::14::15::16::17::18::19
|
||||
out-lit: ::0::1::2::3::4::5::6::7::8::9::10::11::12::13::14::15::16::17::18::19
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
|
||||
#include "lib/test/run.hpp"
|
||||
#include "lib/test/test-helper.hpp"
|
||||
#include "lib/util.hpp"
|
||||
#include "lib/util-foreach.hpp"
|
||||
#include "lib/format-cout.hpp"
|
||||
|
|
@ -39,6 +40,7 @@ namespace lib {
|
|||
namespace test{
|
||||
|
||||
using ::Test;
|
||||
using lumiera::error::LUMIERA_ERROR_ITER_EXHAUST;
|
||||
using boost::lexical_cast;
|
||||
using util::for_each;
|
||||
using util::isnil;
|
||||
|
|
@ -189,7 +191,8 @@ namespace test{
|
|||
|
||||
useSimpleWrappedContainer ();
|
||||
|
||||
wrapIterRange ();
|
||||
enumerate();
|
||||
wrapIterRange();
|
||||
TestContainer testElms (NUM_ELMS);
|
||||
simpleUsage (testElms);
|
||||
|
||||
|
|
@ -199,6 +202,38 @@ namespace test{
|
|||
}
|
||||
|
||||
|
||||
/** @test enumerate all number within a range */
|
||||
void
|
||||
enumerate()
|
||||
{
|
||||
long sum=0;
|
||||
const int N = NUM_ELMS;
|
||||
auto i = eachNum(1, N);
|
||||
while (i)
|
||||
{
|
||||
sum += *i;
|
||||
++i;
|
||||
}
|
||||
|
||||
CHECK (sum == (N-1)*N / 2);
|
||||
|
||||
CHECK (!i);
|
||||
VERIFY_ERROR (ITER_EXHAUST, *i );
|
||||
VERIFY_ERROR (ITER_EXHAUST, ++i );
|
||||
|
||||
i = eachNum (N, 2*N);
|
||||
CHECK (i);
|
||||
CHECK (N == *i);
|
||||
++i;
|
||||
CHECK (N+1 == *i);
|
||||
for ( ; i; ++i)
|
||||
cout << "++" << *i;
|
||||
cout << endl;
|
||||
|
||||
CHECK (!i);
|
||||
}
|
||||
|
||||
|
||||
/** @test usage scenario, where we allow the client to
|
||||
* access a range of elements given by STL iterators,
|
||||
* without any specific iteration behaviour.
|
||||
|
|
|
|||
Loading…
Reference in a new issue