diff --git a/src/lib/iter-adapter.hpp b/src/lib/iter-adapter.hpp index 1b8bbbc7b..1a6880963 100644 --- a/src/lib/iter-adapter.hpp +++ b/src/lib/iter-adapter.hpp @@ -42,20 +42,15 @@ #define LIB_ITER_ADAPTOR_H -//#include "include/logging.h" #include "lib/error.hpp" #include "lib/bool-checkable.hpp" -//#include "lib/util.hpp" -//#include -//#include #include namespace lib { -// using util::for_each; using boost::remove_pointer; @@ -80,20 +75,19 @@ namespace lib { : public lib::BoolCheckable > { const CON* source_; - POS pos_; - - /////////////////////////////////////////////////////////////////////////TODO: implement empty test - /////////////////////////////////////////////////////////////////////////TODO: implement comparisons + mutable POS pos_; public: - typedef typename POS::pointer pointer; //////////////////TODO: do we really need all those typedefs??? + typedef typename POS::pointer pointer; typedef typename POS::reference reference; typedef typename POS::value_type value_type; IterAdapter (const CON* src, const POS& startpos) : source_(src) , pos_(startpos) - { } + { + CON::iterValid(source_,pos_); + } IterAdapter () : source_(0) @@ -109,14 +103,14 @@ namespace lib { _maybe_throw(); return *pos_; } - + pointer operator->() const { _maybe_throw(); return pos_; } - + IterAdapter& operator++() { @@ -124,7 +118,7 @@ namespace lib { CON::iterNext (source_,pos_); return *this; } - + IterAdapter operator++(int) { @@ -140,24 +134,43 @@ namespace lib { return (source_ && CON::iterValid(source_,pos_)); } + bool + empty () const + { + return !isValid(); + } + + private: void _maybe_throw() const { if (!isValid()) - throw lumiera::error::Invalid ("Can't iterate further", + throw lumiera::error::Invalid ("Can't iterate further", lumiera::error::LUMIERA_ERROR_ITER_EXHAUST); } + + /// comparison is allowed to access impl iterator + template + friend bool operator== (IterAdapter const&, IterAdapter const&); }; - - - + /// Supporting equality comparisons... + template + bool operator== (IterAdapter const& il, IterAdapter const& ir) { return il.pos_ == ir.pos_; } + + template + bool operator!= (IterAdapter const& il, IterAdapter const& ir) { return !(il == ir); } + + + + + /** wrapper for an existing Iterator type, - * automatically dereferencing the former's output. + * automatically dereferencing the output of the former. * For this to work, the "source" iterator is expected * to be declared on \em pointers rather than on values. * @note bool checkable if and only if source is... @@ -170,7 +183,8 @@ namespace lib { public: typedef typename IT::value_type pointer; - typedef typename remove_pointer::type & reference; + typedef typename remove_pointer::type value_type; + typedef value_type& reference; PtrDerefIter (IT srcIter) @@ -185,20 +199,20 @@ namespace lib { { return *(*i_); } - + pointer operator->() const { return *i_; } - + PtrDerefIter& operator++() { ++i_; return *this; } - + PtrDerefIter operator++(int) { @@ -211,9 +225,25 @@ namespace lib { return bool(i_); } + bool + empty () const + { + return !isValid(); + } + + + /// comparison operator is allowed to access the underlying impl iterator + template + friend bool operator== (PtrDerefIter const&, PtrDerefIter const&); }; + /// Supporting equality comparisons... + template + bool operator== (PtrDerefIter const& il, PtrDerefIter const& ir) { return il.i_ == ir.i_; } + + template + bool operator!= (PtrDerefIter const& il, PtrDerefIter const& ir) { return !(il == ir); } } // namespace lib diff --git a/tests/lib/iter-adapter-test.cpp b/tests/lib/iter-adapter-test.cpp index ca9684d06..d7935dd33 100644 --- a/tests/lib/iter-adapter-test.cpp +++ b/tests/lib/iter-adapter-test.cpp @@ -25,12 +25,11 @@ #include "lib/test/run.hpp" #include "lib/util.hpp" -//#include "lib/scoped-ptrvect.hpp" #include "lib/iter-adapter.hpp" -//#include "testdummy.hpp" -#include -#include + #include +#include +#include @@ -38,9 +37,9 @@ namespace lib { namespace test{ using ::Test; -// using util::isnil; using boost::lexical_cast; using util::for_each; + using util::isnil; using std::vector; using std::cout; using std::endl; @@ -75,38 +74,57 @@ namespace test{ typedef IterAdapter<_Vec::iterator, TestContainer> iterator; typedef IterAdapter<_Vec::const_iterator, TestContainer> const_iterator; - typedef PtrDerefIter ref_iterator; - typedef PtrDerefIter const_ref_iter; + typedef PtrDerefIter ref_iterator; + typedef PtrDerefIter const_ref_iter; - iterator begin () { return iterator (this, numberz_.begin()); } + iterator begin () { return iterator (this, numberz_.begin()); } const_iterator begin () const { return const_iterator (this, numberz_.begin()); } - ref_iterator begin_ref () { return ref_iterator (begin()); } + ref_iterator begin_ref () { return ref_iterator (begin()); } const_ref_iter begin_ref () const { return const_ref_iter (begin()); } - iterator end () { return iterator(); } + iterator end () { return iterator(); } const_iterator end () const { return const_iterator(); } - - protected: + + + protected: /* ==== API for the IterAdapter ==== */ friend class IterAdapter<_Vec::iterator, TestContainer>; friend class IterAdapter<_Vec::const_iterator,TestContainer>; + /** Implementation of Iteration-logic: pull next element. + * Implicitly this includes a test for iteration end. + */ template static void iterNext (const TestContainer* src, ITER& pos) { if (iterValid(src,pos)) ++pos; + iterValid(src,pos); } + /** Implementation of Iteration-logic: detect iteration end. + * @note the problem here is that this implementation chooses + * to use two representations of "bottom" (end, invalid). + * The reason is, we want the default-constructed IterAdapter + * also be the "bottom" value. Thus, when we detect the + * iteration end by internal logic (\c numberz_.end() ), we + * immediately transform this into the official "bottom" + */ template static bool iterValid (const TestContainer* src, ITER& pos) { REQUIRE (src); - return pos != src->numberz_.end(); + if ((pos != ITER(0)) && (pos != src->numberz_.end())) + return true; + else + { + pos = ITER(0); + return false; + } } }; } @@ -125,7 +143,7 @@ namespace test{ virtual void run (Arg arg) { - if (0 < arg.size()) NUM_ELMS = lexical_cast (arg[0]); + if (0 < arg.size()) NUM_ELMS = lexical_cast (arg[0]); TestContainer testElms (NUM_ELMS); simpleUsage (testElms); @@ -167,13 +185,13 @@ namespace test{ ) { ASSERT (iter); -// ASSERT (iter != elms.end()); ////////////////////////////TODO: implement comparison + ASSERT (iter != elms.end()); ASSERT (**iter == i-1); // note: the previous run indeed modified // the element within the container. - // --(**iter); // doesn't compile, because it's const + // --(**iter); // doesn't compile, because it's const ///////////////////////////////////TODO: duh! it *does* compile. why? } i = 0; @@ -206,12 +224,12 @@ namespace test{ ASSERT (TestContainer::iterator() == elms.end()); ASSERT (!(TestContainer::iterator())); ASSERT (!(elms.end())); -// ASSERT (isnil (elms.end())); ////////////////////////////TODO: implement empty test + ASSERT (isnil (elms.end())); ASSERT (elms.begin()); -// ASSERT (!isnil (elms.begin())); ////////////////////////////TODO: implement empty test + ASSERT (!isnil (elms.begin())); } - + };