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:
Fischlurch 2016-02-04 22:01:48 +01:00
parent 3fef76e1d7
commit 8a33048cc7
3 changed files with 160 additions and 3 deletions

View file

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

View file

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

View file

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