2009-07-11 19:23:20 +02:00
/*
ITER - ADAPTOR . hpp - helpers for building simple forward iterators
Copyright ( C ) Lumiera . org
2009 , Hermann Vosseler < Ichthyostega @ web . de >
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 0213 9 , USA .
*/
2009-07-13 01:25:24 +02:00
/** @file iter-adapter.hpp
2009-07-11 19:23:20 +02:00
* * Helper template ( s ) for creating < b > lumiera forward iterators < / b > .
2009-07-15 07:26:49 +02:00
* * Usually , these templates will be created and provided by a custom
* * container type and accessed by the client through a typedef name
* * " iterator " ( similar to the usage within the STL ) . For more advanced
* * usage , the providing container might want to subclass these iterators ,
* * e . g . to provide an additional , specialised API .
* *
* * Depending on the concrete situation , there are several flavours
* * - the IterAdapter retains an active callback connection to the
* * controlling container , thus allowing arbitrary complex behaviour .
* * - the RangeIter allows just to expose a range of elements defined
* * by a STL - like pair of " start " and " end " iterators
* * - often , objects are managed internally by pointers , while allowing
* * the clients to use direct references ; to support this usage scenario ,
* * PtrDerefIter wraps an existing iterator , while dereferencing any value
* * automatically on access .
* *
* *
* * \ par Lumiera forward iterator concept
* *
* * Similar to the STL , instead of using a common " Iterator " base class ,
* * instead we define a common set of functions and behaviour which can
* * be expected from any such iterator . These rules are similar to STL ' s
* * " forward iterator " , with the addition of an bool check to detect
* * iteration end . The latter s inspired by the \ c hasNext ( ) function
* * found in many current languages supporting iterators . In a similar
* * vein ( inspired from functional programming ) , we deliberately don ' t
* * support the various extended iterator concepts from STL and boost
* * ( random access iterators , output iterators and the like ) . According
* * to this concept , < i > an iterator is a promise for pulling values , < / i >
* * and nothing beyond that .
* *
* * - Any Lumiera forward iterator can be in a " exhausted " ( invalid ) state ,
* * which can be checked by the bool conversion . Especially , any instance
* * created by the default ctor is always fixed to that state . This
* * state is final and can ' t be reset , meaning that any iterator is
* * a disposable one - way - off object .
* * - iterators are copyable and comparable
* * - when an iterator is \ em not in the exhausted state , it may be
* * \ em dereferenced to yield the " current " value .
* * - moreover , iterators may be incremented until exhaustion .
2009-07-11 19:23:20 +02:00
* *
* * @ todo WIP WIP WIP
* * @ todo see Ticket # 182
* *
* * @ see scoped - ptrvect . hpp
*/
# ifndef LIB_ITER_ADAPTOR_H
# define LIB_ITER_ADAPTOR_H
2009-07-13 01:16:30 +02:00
# include "lib/error.hpp"
# include "lib/bool-checkable.hpp"
2009-07-11 19:23:20 +02:00
namespace lib {
/**
2009-07-13 01:25:24 +02:00
* Adapter for building an implementation of the lumiera forward iterator concept .
* The " current position " is represented as an opaque element ( usually an nested iterator ) ,
2009-07-15 07:26:49 +02:00
* with callbacks to the controlling container instance for managing this position .
* This allows to influence and customise the iteration process to a large extent .
2009-07-13 01:25:24 +02:00
* Basically such an IterAdapter behaves like the similar concept from STL , but
* - it is not just a disguised pointer ( meaning , it ' s more expensive )
2009-07-13 01:16:30 +02:00
* - it checks validity on every operation and may throw
* - it has a distinct back - link to the source container
* - the source container needs to implement iterStart ( ) and iterInc ( )
2009-07-13 01:25:24 +02:00
* - we need friendship to access the callbacks on the container
2009-07-13 01:16:30 +02:00
* - the end - of - iteration can be detected by bool check
*
* @ see scoped - ptrvect . hpp usage example
* @ see iter - adaptor - test . cpp
2009-07-11 19:23:20 +02:00
*/
2009-07-13 01:16:30 +02:00
template < class POS , class CON >
class IterAdapter
: public lib : : BoolCheckable < IterAdapter < POS , CON > >
2009-07-11 19:23:20 +02:00
{
2009-07-13 01:16:30 +02:00
const CON * source_ ;
2009-07-14 06:29:04 +02:00
mutable POS pos_ ;
2009-07-13 01:16:30 +02:00
public :
2009-07-14 06:29:04 +02:00
typedef typename POS : : pointer pointer ;
2009-07-13 01:16:30 +02:00
typedef typename POS : : reference reference ;
typedef typename POS : : value_type value_type ;
IterAdapter ( const CON * src , const POS & startpos )
: source_ ( src )
, pos_ ( startpos )
2009-07-14 06:29:04 +02:00
{
2009-07-15 07:26:49 +02:00
checkPos ( ) ;
2009-07-14 06:29:04 +02:00
}
2009-07-13 01:16:30 +02:00
IterAdapter ( )
: source_ ( 0 )
, pos_ ( 0 )
{ }
/* === lumiera forward iterator concept === */
reference
operator * ( ) const
{
_maybe_throw ( ) ;
return * pos_ ;
}
2009-07-14 06:29:04 +02:00
2009-07-13 01:16:30 +02:00
pointer
operator - > ( ) const
{
_maybe_throw ( ) ;
return pos_ ;
}
2009-07-14 06:29:04 +02:00
2009-07-13 01:16:30 +02:00
IterAdapter &
operator + + ( )
{
_maybe_throw ( ) ;
2009-07-15 07:26:49 +02:00
iterate ( ) ;
2009-07-13 01:16:30 +02:00
return * this ;
}
2009-07-14 06:29:04 +02:00
2009-07-13 01:16:30 +02:00
IterAdapter
operator + + ( int )
{
_maybe_throw ( ) ;
IterAdapter oldPos ( * this ) ;
2009-07-15 07:26:49 +02:00
iterate ( ) ;
2009-07-13 01:16:30 +02:00
return oldPos ;
}
bool
isValid ( ) const
{
2009-07-15 07:26:49 +02:00
return checkPos ( ) ;
2009-07-13 01:16:30 +02:00
}
2009-07-14 06:29:04 +02:00
bool
empty ( ) const
{
return ! isValid ( ) ;
}
2009-07-15 07:26:49 +02:00
protected : /* === iteration control interface === */
/** ask the controlling container if this position is valid.
* @ note this function is called before any operation ,
* thus the container may adjust the position value ,
* for example setting it to a " stop iteration " mark .
*/
bool
checkPos ( ) const
{
return source_ & & CON : : hasNext ( source_ , pos_ ) ;
}
/** ask the controlling container to yield the next position.
* The call is dispatched only if the current position is valid ;
* any new position returned is again validated , so to detect
* the iteration end as soon as possible .
*/
bool
iterate ( )
{
if ( ! checkPos ( ) ) return false ;
CON : : iterNext ( source_ , pos_ ) ;
return checkPos ( ) ;
}
2009-07-13 01:16:30 +02:00
private :
void
_maybe_throw ( ) const
{
if ( ! isValid ( ) )
2009-07-14 06:29:04 +02:00
throw lumiera : : error : : Invalid ( " Can't iterate further " ,
2009-07-13 01:16:30 +02:00
lumiera : : error : : LUMIERA_ERROR_ITER_EXHAUST ) ;
}
2009-07-14 06:29:04 +02:00
/// comparison is allowed to access impl iterator
template < class P1 , class P2 , class CX >
friend bool operator = = ( IterAdapter < P1 , CX > const & , IterAdapter < P2 , CX > const & ) ;
2009-07-11 19:23:20 +02:00
} ;
2009-07-14 06:29:04 +02:00
/// Supporting equality comparisons...
template < class P1 , class P2 , class CON >
bool operator = = ( IterAdapter < P1 , CON > const & il , IterAdapter < P2 , CON > const & ir ) { return il . pos_ = = ir . pos_ ; }
template < class P1 , class P2 , class CON >
bool operator ! = ( IterAdapter < P1 , CON > const & il , IterAdapter < P2 , CON > const & ir ) { return ! ( il = = ir ) ; }
2009-07-13 01:16:30 +02:00
2009-07-15 07:26:49 +02:00
/**
* Accessing a STL element range through a Lumiera forward iterator ,
* An instance of this iterator adapter is completely self - contained
* and allows to iterate once over the range of elements , until
* \ c pos = = end . Thus , a custom container may expose a range of
* elements of an embedded STL container , without controlling
* the details of the iteration ( as is possible using the
* more generic IterAdapter ) .
*/
template < class IT >
class RangeIter
: public lib : : BoolCheckable < RangeIter < IT > >
{
IT p_ ;
IT e_ ;
public :
typedef typename IT : : pointer pointer ;
typedef typename IT : : reference reference ;
typedef typename IT : : value_type value_type ;
RangeIter ( IT const & start , IT const & end )
: p_ ( start )
, e_ ( end )
{ }
RangeIter ( )
: p_ ( 0 )
, e_ ( 0 )
{ }
2009-07-17 04:13:14 +02:00
/** allow copy,
* when the underlying iterators
* are compatible or convertible */
template < class I2 >
RangeIter ( I2 const & oIter )
: p_ ( oIter . getPos ( ) )
, e_ ( oIter . getEnd ( ) )
{ }
2009-07-15 07:26:49 +02:00
/* === lumiera forward iterator concept === */
reference
operator * ( ) const
{
_maybe_throw ( ) ;
return * p_ ;
}
pointer
operator - > ( ) const
{
_maybe_throw ( ) ;
return & ( * p_ ) ;
}
RangeIter &
operator + + ( )
{
+ + p_ ;
return * this ;
}
RangeIter
operator + + ( int )
{
return RangeIter ( p_ + + , e_ ) ;
}
bool
isValid ( ) const
{
return ( p_ ! = IT ( 0 ) ) & & ( p_ ! = e_ ) ;
}
bool
empty ( ) const
{
return ! isValid ( ) ;
}
2009-07-17 04:13:14 +02:00
/** access wrapped STL iterator */
const IT & getPos ( ) const { return p_ ; }
const IT & getEnd ( ) const { return e_ ; }
2009-07-15 07:26:49 +02:00
private :
void
_maybe_throw ( ) const
{
if ( ! isValid ( ) )
throw lumiera : : error : : Invalid ( " Can't iterate further " ,
lumiera : : error : : LUMIERA_ERROR_ITER_EXHAUST ) ;
}
} ;
/// Supporting equality comparisons...
template < class I1 , class I2 >
2009-07-17 04:13:14 +02:00
bool operator = = ( RangeIter < I1 > const & il , RangeIter < I2 > const & ir ) { return ( ! il & & ! ir ) | | ( il . getPos ( ) = = ir . getPos ( ) ) ; }
2009-07-15 07:26:49 +02:00
template < class I1 , class I2 >
bool operator ! = ( RangeIter < I1 > const & il , RangeIter < I2 > const & ir ) { return ! ( il = = ir ) ; }
namespace {
/** helper to remove pointer,
* while retaining const */
template < typename T >
struct RemovePtr { typedef T Type ; } ;
template < typename T >
struct RemovePtr < T * > { typedef T Type ; } ;
template < typename T >
struct RemovePtr < const T * > { typedef const T Type ; } ;
template < typename T >
struct RemovePtr < T * const > { typedef const T Type ; } ;
template < typename T >
struct RemovePtr < const T * const > { typedef const T Type ; } ;
}
/**
* wrapper for an existing Iterator type ,
* 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 . . .
2009-07-11 19:23:20 +02:00
*/
2009-07-13 01:16:30 +02:00
template < class IT >
2009-07-11 19:23:20 +02:00
class PtrDerefIter
2009-07-13 01:16:30 +02:00
: public lib : : BoolCheckable < PtrDerefIter < IT > >
2009-07-11 19:23:20 +02:00
{
2009-07-13 01:16:30 +02:00
IT i_ ;
public :
typedef typename IT : : value_type pointer ;
2009-07-15 07:26:49 +02:00
typedef typename RemovePtr < pointer > : : Type value_type ;
2009-07-14 06:29:04 +02:00
typedef value_type & reference ;
2009-07-13 01:16:30 +02:00
PtrDerefIter ( IT srcIter )
: i_ ( srcIter )
{ }
2009-07-17 04:13:14 +02:00
/** allow copy initialisation also
* when the base iter types are convertible */
template < class I2 >
PtrDerefIter ( I2 const & oIter )
: i_ ( reinterpret_cast < IT const & > ( 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
{ }
2009-07-13 01:16:30 +02:00
/* === lumiera forward iterator concept === */
reference
operator * ( ) const
{
return * ( * i_ ) ;
}
2009-07-14 06:29:04 +02:00
2009-07-13 01:16:30 +02:00
pointer
operator - > ( ) const
{
return * i_ ;
}
2009-07-14 06:29:04 +02:00
2009-07-13 01:16:30 +02:00
PtrDerefIter &
operator + + ( )
{
+ + i_ ;
return * this ;
}
2009-07-14 06:29:04 +02:00
2009-07-13 01:16:30 +02:00
PtrDerefIter
operator + + ( int )
{
return PtrDerefIter ( i_ + + ) ;
}
bool
isValid ( ) const
{
return bool ( i_ ) ;
}
2009-07-14 06:29:04 +02:00
bool
empty ( ) const
{
return ! isValid ( ) ;
}
2009-07-17 04:13:14 +02:00
/** access the wrapped implementation iterator */
IT const &
getBase ( ) const
{
return i_ ;
}
2009-07-11 19:23:20 +02:00
} ;
2009-07-14 06:29:04 +02:00
/// Supporting equality comparisons...
template < class I1 , class I2 >
2009-07-17 04:13:14 +02:00
bool operator = = ( PtrDerefIter < I1 > const & il , PtrDerefIter < I2 > const & ir ) { return il . getBase ( ) = = ir . getBase ( ) ; }
2009-07-14 06:29:04 +02:00
template < class I1 , class I2 >
bool operator ! = ( PtrDerefIter < I1 > const & il , PtrDerefIter < I2 > const & ir ) { return ! ( il = = ir ) ; }
2009-07-11 19:23:20 +02:00
2009-07-17 04:13:14 +02:00
/**
* Helper for type rewritings :
* get the element type for an iterator like entity
*/
template < class TY >
struct IterType ;
template < template < class , class > class Iter , class TY , class CON >
struct IterType < Iter < TY , CON > >
{
typedef CON Container ;
typedef TY ElemType ;
typedef typename RemovePtr < TY > : : Type Type ;
template < class T2 >
struct SimilarIter
{
typedef Iter < T2 , CON > Type ;
} ;
} ;
2009-07-11 19:23:20 +02:00
} // namespace lib
# endif