diff --git a/src/lib/iter-adapter-stl.hpp b/src/lib/iter-adapter-stl.hpp
index 632f63bd7..75ad75682 100644
--- a/src/lib/iter-adapter-stl.hpp
+++ b/src/lib/iter-adapter-stl.hpp
@@ -26,7 +26,7 @@
** repackaged as lumiera forward iterators. 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
@@ -195,7 +198,8 @@ namespace iter_stl {
typedef RangeIter Range;
typedef DistinctIter 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
inline typename _SeqT::DistinctVals
eachDistinct (SEQ& seq)
{
typedef typename _SeqT::Range Range;
- typedef typename _SeqT::DistinctVals DistinctValues;
+ typedef typename _SeqT::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
+ class IterSnapshot
+ : public lib::BoolCheckable >
+ {
+ typedef std::vector 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
+ IterSnapshot (IT const& src)
+ : buffer_()
+ , pos_(0)
+ {
+ for (IT copy(src); copy; ++copy)
+ buffer_.push_back(*copy);
+ }
+
+ /** take snapshot from STL iterator */
+ template
+ 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
diff --git a/tests/40components.tests b/tests/40components.tests
index 5911f945c..113d065f8 100644
--- a/tests/40components.tests
+++ b/tests/40components.tests
@@ -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 <() << 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 (NUM_ELMS));
iterateValues4Key (getTestMultiMap_int (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 Range;
+ typedef iter::IterSnapshot Snapshot;
+
+ VecI vec = getTestSeq_int (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
+ 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
-