helper: take snapshot of a given Lumiera or STL iterator

This commit is contained in:
Fischlurch 2010-04-02 05:42:06 +02:00
parent 81f87ba852
commit 939270063e
3 changed files with 249 additions and 23 deletions

View file

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

View file

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

View file

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