helper: take snapshot of a given Lumiera or STL iterator
This commit is contained in:
parent
81f87ba852
commit
939270063e
3 changed files with 249 additions and 23 deletions
|
|
@ -26,7 +26,7 @@
|
|||
** repackaged as <b>lumiera forward iterators</b>. Mostly the purpose
|
||||
** is ease of use, we don't create an abstraction barrier or try to
|
||||
** hide implementation details. (see iter-source.hpp for such an
|
||||
** abstraction facility). As a benefit, these adapters can be
|
||||
** abstraction facility). As a benefit, these adapters can be
|
||||
** considered low overhead.
|
||||
**
|
||||
** @see iter-adapter-stl-test.cpp
|
||||
|
|
@ -50,7 +50,7 @@ namespace lib {
|
|||
namespace iter_stl {
|
||||
|
||||
|
||||
/**
|
||||
/**
|
||||
* helper baseclass to simplify
|
||||
* defining customised wrapped STL iterators
|
||||
*/
|
||||
|
|
@ -117,6 +117,9 @@ namespace iter_stl {
|
|||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
namespace { // traits and helpers...
|
||||
|
||||
template<class MAP>
|
||||
|
|
@ -195,7 +198,8 @@ namespace iter_stl {
|
|||
typedef RangeIter<Iter> Range;
|
||||
typedef DistinctIter<Range> DistinctVals;
|
||||
};
|
||||
}
|
||||
|
||||
}//(End) traits/helpers
|
||||
|
||||
|
||||
|
||||
|
|
@ -230,13 +234,13 @@ namespace iter_stl {
|
|||
|
||||
/** build a Lumiera Forward Iterator to suppress
|
||||
* any repetitions in the given sequence.
|
||||
*/
|
||||
*/
|
||||
template<class SEQ>
|
||||
inline typename _SeqT<SEQ>::DistinctVals
|
||||
eachDistinct (SEQ& seq)
|
||||
{
|
||||
typedef typename _SeqT<SEQ>::Range Range;
|
||||
typedef typename _SeqT<SEQ>::DistinctVals DistinctValues;
|
||||
typedef typename _SeqT<SEQ>::DistinctVals DistinctValues;
|
||||
|
||||
return DistinctValues (Range (seq.begin(), seq.end()));
|
||||
}
|
||||
|
|
@ -272,5 +276,126 @@ namespace iter_stl {
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* materialised iterator contents.
|
||||
* At construction, the given source iterator
|
||||
* is immediately discharged into an internal buffer (vector).
|
||||
* This captured value sequence can be retrieved once as
|
||||
* Lumiera Forward Iterator
|
||||
*/
|
||||
template<typename VAL>
|
||||
class IterSnapshot
|
||||
: public lib::BoolCheckable<IterSnapshot<VAL> >
|
||||
{
|
||||
typedef std::vector<VAL> Sequence;
|
||||
|
||||
mutable
|
||||
Sequence buffer_;
|
||||
size_t pos_;
|
||||
|
||||
|
||||
public:
|
||||
/** create empty snapshot */
|
||||
IterSnapshot()
|
||||
: buffer_()
|
||||
, pos_(0)
|
||||
{ }
|
||||
|
||||
/** take snapshot by discharging a copy
|
||||
* of the given Lumiera Forward iterator
|
||||
* @warning depending on the implementation
|
||||
* backing the source iterator, this
|
||||
* might or might not yield side-effects.
|
||||
*/
|
||||
template<class IT>
|
||||
IterSnapshot (IT const& src)
|
||||
: buffer_()
|
||||
, pos_(0)
|
||||
{
|
||||
for (IT copy(src); copy; ++copy)
|
||||
buffer_.push_back(*copy);
|
||||
}
|
||||
|
||||
/** take snapshot from STL iterator */
|
||||
template<class IT>
|
||||
IterSnapshot (IT const& begin, IT const& end)
|
||||
: buffer_()
|
||||
, pos_(0)
|
||||
{
|
||||
for (IT p(begin); p!=end; ++p)
|
||||
buffer_.push_back(*p);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* === lumiera forward iterator concept === */
|
||||
|
||||
typedef VAL* pointer;
|
||||
typedef VAL& reference;
|
||||
typedef VAL value_type;
|
||||
|
||||
reference
|
||||
operator*() const
|
||||
{
|
||||
_maybe_throw();
|
||||
return buffer_[pos_];
|
||||
}
|
||||
|
||||
pointer
|
||||
operator->() const
|
||||
{
|
||||
_maybe_throw();
|
||||
return &buffer_[pos_];
|
||||
}
|
||||
|
||||
IterSnapshot&
|
||||
operator++()
|
||||
{
|
||||
_maybe_throw();
|
||||
++pos_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool
|
||||
isValid () const
|
||||
{
|
||||
return pos_ < buffer_.size();
|
||||
}
|
||||
|
||||
bool
|
||||
empty () const
|
||||
{
|
||||
return !isValid();
|
||||
}
|
||||
|
||||
|
||||
/** equality is based both on the actual contents of the snapshots
|
||||
* and the current iterator position */
|
||||
friend bool
|
||||
operator== (IterSnapshot const& snap1, IterSnapshot const& snap2)
|
||||
{
|
||||
return snap1.buffer_ == snap2.buffer_
|
||||
&& snap1.pos_ == snap2.pos_ ;
|
||||
}
|
||||
|
||||
friend bool
|
||||
operator!= (IterSnapshot const& snap1, IterSnapshot const& snap2)
|
||||
{
|
||||
return ! (snap1 == snap2);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
void
|
||||
_maybe_throw() const
|
||||
{
|
||||
if (!isValid())
|
||||
_throwIterExhausted();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}} // namespace lib::iter_stl
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -345,7 +345,33 @@ out: ::0::1::2::3::4::5::6::7::8::9::10::11::12::13::14::15::16::17::18::19
|
|||
END
|
||||
|
||||
|
||||
PLANNED "Lumiera Iterator Adapter for STL" IterAdapterSTL_test <<END
|
||||
TEST "Lumiera Iterator Adapter for STL" IterAdapterSTL_test <<END
|
||||
out: -----filter-distinct-values---.+vector
|
||||
out: iter::eachDistinct$
|
||||
out: iter::eachDistinct::1$
|
||||
out: iter::eachDistinct::1::2::3::1
|
||||
out: -----iterateMapKeyVal---.+map
|
||||
out: iter::eachKey::0::1::2::3::4::5::6::7::8::9
|
||||
out: iter::eachVal::0::2::4::6::8::10::12::14::16::18
|
||||
out: iter::eachDistinctKey::0::1::2::3::4::5::6::7::8::9
|
||||
out: -----iterateMapKeyVal---.+unordered_map
|
||||
out: iter::eachKey::0::1::2::3::4::5::6::7::8::9
|
||||
out: iter::eachVal::0::2::4::6::8::10::12::14::16::18
|
||||
out: iter::eachDistinctKey::0::1::2::3::4::5::6::7::8::9
|
||||
out: -----iterateMapKeyVal---.+multimap
|
||||
out: iter::eachKey::0::0::0::0::0::0::0::0::0::0::1::1::1::1::1::1::1::1::1::2::2::2::2::2::2::2::2::3::3::3::3::3::3::3::4::4::4::4::4::4::5::5::5::5::5::6::6::6::6::7::7::7::8::8::9
|
||||
out: iter::eachVal::10::9::8::7::6::5::4::3::2::1::9::8::7::6::5::4::3::2::1::8::7::6::5::4::3::2::1::7::6::5::4::3::2::1::6::5::4::3::2::1::5::4::3::2::1::4::3::2::1::3::2::1::2::1::1
|
||||
out: iter::eachDistinctKey::0::1::2::3::4::5::6::7::8::9
|
||||
out: -----iterateMapKeyVal---.+unordered_multimap
|
||||
out: iter::eachKey::0::0::0::0::0::0::0::0::0::0::1::1::1::1::1::1::1::1::1::2::2::2::2::2::2::2::2::3::3::3::3::3::3::3::4::4::4::4::4::4::5::5::5::5::5::6::6::6::6::7::7::7::8::8::9
|
||||
out: iter::eachVal::9::8::7::6::5::4::3::2::1::10::9::1::2::3::4::5::6::7::8::8::5::6::4::3::2::1::7::6::5::4::3::2::1::7::5::4::3::2::1::6::4::3::2::1::5::3::1::2::4::3::1::2::2::1::1
|
||||
out: iter::eachDistinctKey::0::1::2::3::4::5::6::7::8::9
|
||||
out: -----iterateValues4Key---.+multimap
|
||||
out: iter::eachValForKey::10::9::8::7::6::5::4::3::2::1
|
||||
out: -----iterateValues4Key---.+unordered_multimap
|
||||
out: iter::eachValForKey::9::8::7::6::5::4::3::2::1::10
|
||||
out: snapshot-0-1-2-3-4-5-6-7-8-9
|
||||
out: snapshot-22-44
|
||||
END
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@
|
|||
#include "lib/test/test-helper.hpp"
|
||||
#include "lib/test/test-coll.hpp"
|
||||
#include "lib/util.hpp"
|
||||
//#include "lib/util-foreach.hpp"
|
||||
|
||||
#include "lib/iter-adapter-stl.hpp"
|
||||
|
||||
|
|
@ -41,22 +40,13 @@ namespace test{
|
|||
|
||||
using ::Test;
|
||||
using boost::lexical_cast;
|
||||
// using util::for_each;
|
||||
// using util::isnil;
|
||||
// using std::vector;
|
||||
using util::isnil;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
namespace iter = lib::iter_stl;
|
||||
|
||||
|
||||
namespace { // provide STL containers with test data
|
||||
|
||||
uint NUM_ELMS = 10;
|
||||
|
||||
} // (END) test data
|
||||
|
||||
|
||||
/** test an iterator: create it by calling a constructor function
|
||||
* and then pull out all contents and print them to STDOUT */
|
||||
#define TEST_ITER(_CTOR_, _ARG_) \
|
||||
|
|
@ -69,6 +59,11 @@ namespace test{
|
|||
cout << "-----"<<STRINGIFY(_F_NAME_)<<"---" << showType<_F_TYPE_>() << endl;
|
||||
|
||||
|
||||
namespace {
|
||||
uint NUM_ELMS = 10;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -76,11 +71,14 @@ namespace test{
|
|||
|
||||
|
||||
/************************************************************************
|
||||
* @test provide test STL containers to verify some of the adapters
|
||||
* to expose typical container usage patterns as lumiera iterators.
|
||||
* - keys and values of a map
|
||||
* @test verify some of the adapters to expose typical container
|
||||
* usage patterns as Lumiera Forward Iterators.
|
||||
* - distinct values from a sequence
|
||||
* - keys and values of a map / multimap
|
||||
* - distinct keys from a multimap
|
||||
* - multimap values associated with a given key
|
||||
*
|
||||
* - snapshot of an iterator, to be retrieved as iterator
|
||||
*
|
||||
* @see RangeIter
|
||||
* @see iter-adapter.hpp
|
||||
* @see iter-adapter-stl.hpp
|
||||
|
|
@ -103,6 +101,8 @@ namespace test{
|
|||
|
||||
iterateValues4Key (getTestMultiMap_int<MMapII> (NUM_ELMS));
|
||||
iterateValues4Key (getTestMultiMap_int<HMMapII> (NUM_ELMS));
|
||||
|
||||
checkIteratorSnapshot();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -127,7 +127,7 @@ namespace test{
|
|||
TEST_ITER (iter::eachValForKey, (mumap, 0));
|
||||
|
||||
// non-existing key should yield empty iterator
|
||||
CHECK (! iter::eachValForKey (mumap, NUM_ELMS));
|
||||
CHECK (! iter::eachValForKey (mumap, NUM_ELMS));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -157,10 +157,85 @@ namespace test{
|
|||
vec.push_back (1);
|
||||
TEST_ITER(iter::eachDistinct, (vec));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
checkIteratorSnapshot()
|
||||
{
|
||||
typedef VecI::iterator Iter;
|
||||
typedef RangeIter<Iter> Range;
|
||||
typedef iter::IterSnapshot<int> Snapshot;
|
||||
|
||||
VecI vec = getTestSeq_int<VecI> (NUM_ELMS);
|
||||
Snapshot capture1 (vec.begin(), vec.end());
|
||||
|
||||
Range range_of_all (vec.begin(), vec.end());
|
||||
Snapshot capture2 (range_of_all);
|
||||
CHECK (range_of_all); // snapshot doesn't affect given source iterator pos
|
||||
CHECK (capture2);
|
||||
|
||||
CHECK (vec.begin() == range_of_all.getPos());
|
||||
CHECK (vec.end() == range_of_all.getEnd());
|
||||
CHECK (!isnil (vec));
|
||||
|
||||
// concurrent or intermittent modification
|
||||
vec.clear();
|
||||
CHECK (isnil (vec));
|
||||
CHECK (vec.end() != range_of_all.getEnd()); // range_of_all is now corrupted
|
||||
|
||||
CHECK (capture1); // ...but the snapshots remain unaffected
|
||||
CHECK (capture2);
|
||||
CHECK (capture1 == capture2); // can compare snapshots, based on actual contents
|
||||
|
||||
vec.push_back(22);
|
||||
vec.push_back(44);
|
||||
Snapshot capture3 (vec.begin(), vec.end()); // take another snapshot from current contents
|
||||
CHECK (capture3);
|
||||
CHECK (capture3 != capture1);
|
||||
CHECK (capture3 != capture2);
|
||||
|
||||
|
||||
uint sum_should_be = (NUM_ELMS-1)*NUM_ELMS/2;
|
||||
|
||||
CHECK (sum_should_be == sumAll (capture1));
|
||||
CHECK (!capture1); // this one is exhausted now
|
||||
CHECK ( capture2); // ...but the others are really independent
|
||||
CHECK ( capture3);
|
||||
CHECK (capture1 != capture2); // comparison includes the current position
|
||||
|
||||
CHECK (sum_should_be == sumAll (capture2));
|
||||
CHECK (!capture1);
|
||||
CHECK (!capture2);
|
||||
CHECK ( capture3);
|
||||
CHECK (capture1 == capture2); // now again equal (both exhausted and equal contents)
|
||||
|
||||
CHECK (22+44 == sumAll (capture3));
|
||||
CHECK (!capture1);
|
||||
CHECK (!capture2);
|
||||
CHECK (!capture3);
|
||||
CHECK (capture1 == capture2);
|
||||
CHECK (capture3 != capture1); // all exhausted, but the difference in contents remains
|
||||
CHECK (capture3 != capture2);
|
||||
}
|
||||
|
||||
template<class IT>
|
||||
uint
|
||||
sumAll (IT& it)
|
||||
{
|
||||
uint sum(0);
|
||||
cout << "snapshot";
|
||||
while (it)
|
||||
{
|
||||
cout << "-" << *it;
|
||||
sum += *it;
|
||||
++it;
|
||||
}
|
||||
cout << endl;
|
||||
return sum;
|
||||
}
|
||||
};
|
||||
|
||||
LAUNCHER (IterAdapterSTL_test, "unit common");
|
||||
|
||||
|
||||
}} // namespace lib::test
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue