/* ITER-ADAPTER-STL.hpp - helpers for building simple forward iterators Copyright (C) Lumiera.org 2010, Hermann Vosseler This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /** @file iter-adapter-stl.hpp ** Preconfigured adapters for some STL container standard usage situations. ** Especially, definitions for accessing views on common STL containers ** 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 ** considered low overhead. ** ** @see iter-adapter-stl-test.cpp ** @see iter-adapter.hpp ** @see iter-source.happ ** @see intertools.hpp ** */ #ifndef LIB_ITER_ADAPTER_STL_H #define LIB_ITER_ADAPTER_STL_H #include "lib/iter-adapter.hpp" namespace lib { namespace iter_stl { /** * Helper to filter repeated values * from a wrapped iterator (both STL or Lumiera) */ template class DistinctIter : public lib::BoolCheckable > { public: typedef typename IT::value_type value_type; typedef typename IT::reference reference; typedef typename IT::pointer pointer; private: IT i_; pointer prev_; void memorise() { if (i_) prev_ = &(*i_); } public: DistinctIter() : i_(), prev_() { } DistinctIter(IT const& i) : i_(i),prev_() { memorise(); } pointer operator->() const { return i_; } reference operator*() const { return *i_; } bool isValid() const { return i_; } DistinctIter& operator++() { do ++i_; while (i_ && prev_ && *prev_ == *i_ ); memorise(); return *this; } friend bool operator== (DistinctIter const& i1, DistinctIter const& i2) { return i1.i_ == i2.i_; } friend bool operator!= (DistinctIter const& i1, DistinctIter const& i2) { return i1.i_ != i2.i_; } }; /** * helper baseclass to simplify * defining customised wrapped STL iterators */ template struct WrappedStlIter : DEF { typedef typename DEF::Iter Iter; typedef typename DEF::reference reference; typedef typename DEF::pointer pointer; WrappedStlIter() : i_() { } WrappedStlIter(Iter const& i) : i_(i) { } pointer operator->() const { return DEF::get(i_); } reference operator*() const { return *(DEF::get(i_)); } WrappedStlIter& operator++() { ++i_; return *this; } friend bool operator== (WrappedStlIter const& i1, WrappedStlIter const& i2) { return i1.i_ == i2.i_; } friend bool operator!= (WrappedStlIter const& i1, WrappedStlIter const& i2) { return i1.i_ != i2.i_; } private: mutable Iter i_; }; /* -- customisations for building concrete wrappers -- */ /** * Wrapped-Iter-Policy: forwarding directly * with typing retained unaltered. */ template struct Wrapped_Identity { typedef IT Iter; typedef typename IT::value_type value_type; typedef typename IT::reference reference; typedef typename IT::pointer pointer; static Iter get (Iter& it) { return & (*it); } }; /** * Wrapped-Iter-Policy: picking the key part * of a pair iterator (map or multimap). */ template struct Wrapped_PickKey { typedef IT Iter; typedef typename IT::value_type::first_type value_type; typedef value_type & reference; typedef value_type * pointer; static pointer get (Iter& it) { return & (it->first); } }; /** * Wrapped-Iter-Policy: picking the key part * of a pair iterator (map or multimap). */ template struct Wrapped_PickVal { typedef IT Iter; typedef typename IT::value_type::second_type value_type; typedef value_type & reference; typedef value_type * pointer; static pointer get (Iter& it) { return & (it->second); } }; template struct Wrapped_PickConstVal { typedef IT Iter; typedef typename IT::value_type::second_type value_type; typedef value_type const& reference; typedef value_type const* pointer; static pointer get (Iter& it) { return & (it->second); } }; namespace { // traits and helpers... template struct _MapTypeSelector { typedef typename MAP::value_type::first_type Key; typedef typename MAP::value_type::second_type Val; typedef typename MAP::iterator Itr; }; template struct _MapTypeSelector { typedef typename MAP::value_type::first_type Key; typedef typename MAP::value_type::second_type const Val; typedef typename MAP::const_iterator Itr; }; /** helper to access the parts of the pair values correctly...*/ template struct _MapSubSelector { typedef WrappedStlIter< Wrapped_PickKey > PickKey; typedef WrappedStlIter< Wrapped_PickVal > PickVal; }; /** especially for const iterators we need to use \c const& and \c const* */ template struct _MapSubSelector { typedef WrappedStlIter< Wrapped_PickKey > PickKey; // Key is always const for maps typedef WrappedStlIter< Wrapped_PickConstVal > PickVal; }; template struct _MapT { typedef typename _MapTypeSelector::Key KeyType; typedef typename _MapTypeSelector::Val ValType; typedef typename _MapTypeSelector::Itr EntryIter; typedef typename EntryIter::reference DetectConst; typedef typename _MapSubSelector::PickKey PickKeyIter; typedef typename _MapSubSelector::PickVal PickValIter; typedef RangeIter KeyIter; typedef RangeIter ValIter; typedef DistinctIter DistinctKeys; }; template struct _MapIterT { typedef IT EntryIter; typedef typename EntryIter::value_type::first_type KeyType; typedef typename EntryIter::value_type::second_type ValType; typedef typename EntryIter::reference DetectConst; typedef typename _MapSubSelector::PickKey PickKeyIter; typedef typename _MapSubSelector::PickVal PickValIter; typedef RangeIter KeyIter; typedef RangeIter ValIter; typedef DistinctIter DistinctKeys; }; template struct _SeqT { typedef typename SEQ::iterator Iter; typedef RangeIter Range; typedef DistinctIter DistinctVals; }; template struct _SeqT { typedef typename SEQ::const_iterator Iter; typedef RangeIter Range; typedef DistinctIter DistinctVals; }; }//(End) traits/helpers /** @return Lumiera Forward Iterator * to yield each Element from a STL container */ template inline typename _SeqT::Range eachElm (CON& coll) { typedef typename _SeqT::Range Range; return Range (coll.begin(), coll.end()); } /** @return Lumiera Forward Iterator to yield * each key of a map/multimap */ template inline typename _MapT::KeyIter eachKey (MAP& map) { typedef typename _MapT::KeyIter Range; typedef typename _MapT::PickKeyIter PickKey; return Range (PickKey (map.begin()), PickKey (map.end())); } /** @return Lumiera Forward Iterator extracting the keys * from a given range of (key,value) pairs */ template inline typename _MapIterT::KeyIter eachKey (IT const& begin, IT const& end) { typedef typename _MapIterT::KeyIter Range; typedef typename _MapIterT::PickKeyIter PickKey; return Range (PickKey (begin), PickKey (end)); } /** @return Lumiera Forward Iterator to yield * each value within a map/multimap */ template inline typename _MapT::ValIter eachVal (MAP& map) { typedef typename _MapT::ValIter Range; typedef typename _MapT::PickValIter PickVal; return Range (PickVal (map.begin()), PickVal (map.end())); } /** @return Lumiera Forward Iterator extracting the values * from a given range of (key,value) pairs */ template inline typename _MapIterT::ValIter eachVal (IT const& begin, IT const& end) { typedef typename _MapIterT::ValIter Range; typedef typename _MapIterT::PickValIter PickVal; return Range (PickVal (begin), PickVal (end)); } /** 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; return DistinctValues (Range (seq.begin(), seq.end())); } /** @return Lumiera Forward Iterator to yield * the distinct keys from a multimap * @warning full scan of all keys, dropping repetitions */ template inline typename _MapT::DistinctKeys eachDistinctKey (MAP& map) { return typename _MapT::DistinctKeys (eachKey (map)); } /** @return Lumiera Forward Iterator to yield * the distinct keys from a multimap * @warning full scan of all keys, dropping repetitions */ template inline typename _MapT::ValIter eachValForKey (MMAP& multimap, KEY key) { typedef typename _MapT::EntryIter Pos; typedef typename _MapT::ValIter Range; typedef typename _MapT::PickValIter PickVal; std::pair valRange = multimap.equal_range (key); return Range (PickVal (valRange.first), PickVal (valRange.second)); } /** * 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