diff --git a/src/lib/iter-adapter.hpp b/src/lib/iter-adapter.hpp index 4de2c994a..6280e60f8 100644 --- a/src/lib/iter-adapter.hpp +++ b/src/lib/iter-adapter.hpp @@ -77,11 +77,44 @@ #include "lib/error.hpp" #include "lib/bool-checkable.hpp" +#include + namespace lib { + namespace { + /** + * Helper for creating nested typedefs + * within the iterator adaptor, similar to what the STL does. + */ + template + struct IterTraits + { + typedef typename TY::pointer pointer; + typedef typename TY::reference reference; + typedef typename TY::value_type value_type; + }; + + template + struct IterTraits + { + typedef TY value_type; + typedef TY& reference; + typedef TY* pointer; + }; + + template + struct IterTraits + { + typedef TY value_type; + typedef const TY& reference; + typedef const TY* pointer; + }; + + } + /** * Adapter for building an implementation of the lumiera forward iterator concept. @@ -107,9 +140,9 @@ namespace lib { mutable POS pos_; public: - typedef typename POS::pointer pointer; - typedef typename POS::reference reference; - typedef typename POS::value_type value_type; + typedef typename IterTraits::pointer pointer; + typedef typename IterTraits::reference reference; + typedef typename IterTraits::value_type value_type; IterAdapter (const CON* src, const POS& startpos) : source_(src) @@ -243,9 +276,9 @@ namespace lib { IT e_; public: - typedef typename IT::pointer pointer; - typedef typename IT::reference reference; - typedef typename IT::value_type value_type; + typedef typename IterTraits::pointer pointer; + typedef typename IterTraits::reference reference; + typedef typename IterTraits::value_type value_type; RangeIter (IT const& start, IT const& end) : p_(start) @@ -287,6 +320,7 @@ namespace lib { RangeIter& operator++() { + _maybe_throw(); ++p_; return *this; } @@ -294,6 +328,7 @@ namespace lib { RangeIter operator++(int) { + _maybe_throw(); return RangeIter (p_++,e_); } @@ -361,6 +396,42 @@ namespace lib { } + /** + * Helper for type rewritings: + * get the element type for an iterator like entity + */ + template + struct IterType; + + template class Iter, class TY, class CON> + struct IterType > + { + typedef CON Container; + typedef TY ElemType; + + typedef typename RemovePtr::Type ValueType; + + template + struct SimilarIter + { + typedef Iter Type; + }; + }; + + template + struct IterType > + : IterType + { + template + struct SimilarIter ///< rebind to rewritten Iterator wrapped into RangeIter + { + typedef typename IterType::template SimilarIter::Type WrappedIter; + typedef RangeIter Type; + }; + }; + + + /** * wrapper for an existing Iterator type, * automatically dereferencing the output of the former. @@ -372,26 +443,56 @@ namespace lib { class PtrDerefIter : public lib::BoolCheckable > { - IT i_; + IT i_; ///< nested source iterator + public: - typedef typename IT::value_type pointer; + typedef typename IT::value_type pointer; typedef typename RemovePtr::Type value_type; - typedef value_type& reference; + typedef value_type& reference; + + // the purpose of the following typedefs is to ease building a correct "const iterator" + + typedef typename boost::remove_const::type ValueTypeBase; // value_type without const + + typedef typename IterType::template SimilarIter< ValueTypeBase* * >::Type WrappedIterType; + typedef typename IterType::template SimilarIter::Type WrappedConstIterType; + + typedef PtrDerefIter IterType; + typedef PtrDerefIter ConstIterType; + + /** PtrDerefIter is always created + * by wrapping an existing iterator. + */ PtrDerefIter (IT srcIter) : i_(srcIter) { } - /** allow copy initialisation also - * when the base iter types are convertible */ - template - PtrDerefIter (I2 const& oIter) - : i_(reinterpret_cast (oIter.getBase())) /////////////////////////////TODO: properly guard this dangerous conversion by a traits template; the idea is to allow this conversion only for the initialisation of a "const iterator" from its sister type + /** allow copy initialisation also when + * the wrapped iterator is based on some variation of a pointer. + * Especially, this includes initialisation of the "const variant" + * from the "normal variant" of PtrDerefIter. Actually, we need to convert + * in this case by brute force, because indeed (const TY *)* is not assignable + * from (TY *)* -- just we know that our intention is to dereference both levels + * of pointers, and then the resulting conversion is correct. + * @note in case IT == WrappedIterType, this is just a redefinition of the + * default copy ctor. In all other cases, this is an additional + * ctor besides the default copy ctor */ + PtrDerefIter (PtrDerefIter const& oIter) + : i_(reinterpret_cast (oIter.getBase())) { } + PtrDerefIter& + operator= (PtrDerefIter const& ref) + { + i_ = reinterpret_cast (ref.getBase()); + } + + + /* === lumiera forward iterator concept === */ @@ -450,28 +551,5 @@ namespace lib { bool operator!= (PtrDerefIter const& il, PtrDerefIter const& ir) { return !(il == ir); } - - /** - * Helper for type rewritings: - * get the element type for an iterator like entity - */ - template - struct IterType; - - template class Iter, class TY, class CON> - struct IterType > - { - typedef CON Container; - typedef TY ElemType; - - typedef typename RemovePtr::Type Type; - - template - struct SimilarIter - { - typedef Iter Type; - }; - }; - } // namespace lib #endif diff --git a/src/lib/scoped-ptrvect.hpp b/src/lib/scoped-ptrvect.hpp index e10704679..eff0a2b0d 100644 --- a/src/lib/scoped-ptrvect.hpp +++ b/src/lib/scoped-ptrvect.hpp @@ -48,7 +48,6 @@ #include "include/logging.h" #include "lib/iter-adapter.hpp" #include "lib/error.hpp" -#include "lib/util.hpp" #include #include @@ -56,14 +55,13 @@ namespace lib { - using util::for_each; - /** - * Simple vector based collection of pointers, noncopyable and managing - * lifecycle of the pointed-to objects. Implemented by a vector of - * bare pointers (private inheritance) + * Simple vector based collection of pointers, + * managing lifecycle of the pointed-to objects. + * Implemented as a non-copyable object, based on a + * vector of bare pointers (private inheritance) */ template class ScopedPtrVect @@ -72,11 +70,12 @@ namespace lib { { typedef std::vector _Vec; typedef typename _Vec::iterator VIter; -// typedef typename _Vec::const_iterator VcIter; - typedef typename IterType::template SimilarIter::Type VcIter; typedef RangeIter RIter; - typedef RangeIter RcIter; + typedef PtrDerefIter IterType; + + typedef typename IterType::ConstIterType ConstIterType; + typedef typename IterType::WrappedConstIterType RcIter; public: @@ -84,8 +83,6 @@ namespace lib { typedef T & reference; typedef T const& const_reference; - typedef typename IterType::Type Tupe; - ScopedPtrVect () @@ -154,8 +151,8 @@ namespace lib { return *get(i); } - typedef PtrDerefIter iterator; - typedef PtrDerefIter const_iterator; + typedef IterType iterator; + typedef ConstIterType const_iterator; iterator begin() { return iterator (allPtrs()); } const_iterator begin() const { return const_iterator (allPtrs()); } diff --git a/tests/lib/scoped-ptrvect-test.cpp b/tests/lib/scoped-ptrvect-test.cpp index d8d051727..ed414aee2 100644 --- a/tests/lib/scoped-ptrvect-test.cpp +++ b/tests/lib/scoped-ptrvect-test.cpp @@ -23,31 +23,27 @@ #include "lib/test/run.hpp" +#include "lib/test/test-helper.hpp" #include "lib/util.hpp" #include "lib/scoped-ptrvect.hpp" #include "testdummy.hpp" -//////////////////////////////////////////////TODO test code -#include "lib/test/test-helper.hpp" -using lib::test::showSizeof; -#include -using std::cout; -using std::endl; -//////////////////////////////////////////////TODO test code namespace lib { namespace test{ using ::Test; using util::isnil; + using lumiera::error::LUMIERA_ERROR_ITER_EXHAUST; + typedef ScopedPtrVect VectD; /******************************************************************** * @test ScopedPtrVect manages the lifecycle of a number of objects. - * @todo cover the const iterator and implement detaching of objects + * @todo implement detaching of objects */ class ScopedPtrVect_test : public Test { @@ -118,12 +114,10 @@ namespace test{ ++check; ++ii; } + + + // Test the const iterator check = 0; - -///////////////////////////////////////////////////////////////////TODO test code - cout << showSizeof () << endl; -///////////////////////////////////////////////////////////////////TODO test code - VectD::const_iterator cii = holder.begin(); while (cii) { @@ -131,6 +125,20 @@ namespace test{ ++check; ++cii; } + + + // Verify correct behaviour of iteration end + ASSERT (! (holder.end())); + ASSERT (isnil (holder.end())); + + VERIFY_ERROR (ITER_EXHAUST, *holder.end() ); + VERIFY_ERROR (ITER_EXHAUST, ++holder.end() ); + + ASSERT (ii == holder.end()); + ASSERT (cii == holder.end()); + VERIFY_ERROR (ITER_EXHAUST, ++ii ); + VERIFY_ERROR (ITER_EXHAUST, ++cii ); + } ASSERT (0==checksum); }