|
Boost.Range |
Utilities
Having an abstraction that encapsulates a pair of iterators is very useful. The
standard library uses std::pair in some circumstances, but that
class is cumbersome to use because we need to specify two template arguments,
and for all range algorithm purposes we must enforce the two template arguments
to be the same. Moreover, std::pair<iterator,iterator> is hardly
self-documenting whereas more domain specific class names are. Therefore these
two classes are provided:
The iterator_range class is templated on a Forward
Traversal Iterator and should be used whenever fairly general code is needed.
The sub_range class is templated on a Forward Range and it is less general,
but a bit easier to use since its template
argument is easier to specify. The biggest difference is, however, that a
sub_range can propagate constness because it knows what a
corresponding const_iterator is.
Both classes can be used as ranges since they implement the minimal interface
required for this to work automatically.
Class iterator_range
The intention of the iterator_range class is to encapsulate two
iterators so they fulfill the Forward Range concept. A few other
functions are also provided for convenience.
If the template argument is not a model of Forward Traversal Iterator, one can
still use a subset of the interface. In particular, size() requires
Random Access Iterators whereas empty() only requires Single
Pass Iterators.
Recall that many default constructed iterators
are singular and hence can only be assigned, but not compared or
incremented or anything. Likewise, if one creates a default constructed
iterator_range , then one have to be careful about not doing
anything besides copying.
Synopsis
namespace boost
{
template< class ForwardTraversalIterator >
class iterator_range
{
public: typedef ForwardTraversalIterator iterator;
typedef ForwardTraversalIterator const_iterator;
typedef iterator_difference<iterator>::type difference_type;
public: template< class ForwardTraversalIterator2 >
iterator_range( ForwardTraversalIterator2 Begin, ForwardTraversalIterator2 End );
template< class ForwardRange >
iterator_range( ForwardRange& r );
template< class ForwardRange >
iterator_range( const ForwardRange& r );
template< class ForwardRange >
iterator_range& operator=( ForwardRange& r );
template< class ForwardRange >
iterator_range& operator=( const ForwardRange& r );
public: iterator begin() const;
iterator end() const;
difference_type size() const;
bool empty() const;
public: operator unspecified_bool_type() const;
bool equal( const iterator_range& ) const;
reference front() const;
reference back() const;
iterator_range& advance_begin( difference_type n );
iterator_range& advance_end( difference_type n );
reference operator[]( difference_type at ) const;
value_type operator()( difference_type at ) const;
};
template< class ForwardTraversalIterator, class T, class Traits >
std::basic_ostream<T,Traits>&
operator<<( std::basic_ostream<T,Traits>& Os,
const iterator_range<ForwardTraversalIterator>& r );
template< class ForwardTraversalIterator, class ForwardTraversalIterator2 >
bool operator==( const iterator_range<ForwardTraversalIterator>& l,
const iterator_range<ForwardTraversalIterator2>& r );
template< class ForwardTraversalIterator, class ForwardRange >
bool operator==( const iterator_range<ForwardTraversalIterator>& l,
const ForwardRange& r );
template< class ForwardTraversalIterator, class ForwardRange >
bool operator==( const ForwardRange& l,
const iterator_range<ForwardTraversalIterator>& r );
template< class ForwardTraversalIterator, class ForwardTraversalIterator2 >
bool operator!=( const iterator_range<ForwardTraversalIterator>& l,
const iterator_range<ForwardTraversalIterator2>& r );
template< class ForwardTraversalIterator, class ForwardRange >
bool operator!=( const iterator_range<ForwardTraversalIterator>& l,
const ForwardRange& r );
template< class ForwardTraversalIterator, class ForwardRange >
bool operator!=( const ForwardRange& l,
const iterator_range<ForwardTraversalIterator>& r );
template< class ForwardTraversalIterator, class ForwardTraversalIterator2 >
bool operator<( const iterator_range<ForwardTraversalIterator>& l,
const iterator_range<ForwardTraversalIterator2>& r );
template< class ForwardTraversalIterator, class ForwardRange >
bool operator<( const iterator_range<ForwardTraversalIterator>& l,
const ForwardRange& r );
template< class ForwardTraversalIterator, class ForwardRange >
bool operator<( const ForwardRange& l,
const iterator_range<ForwardTraversalIterator>& r );
template< class ForwardTraversalIterator >
iterator_range< ForwardTraversalIterator >
make_iterator_range( ForwardTraversalIterator Begin,
ForwardTraversalIterator End );
template< class ForwardRange >
iterator_range< typename range_iterator<ForwardRange>::type >
make_iterator_range( ForwardRange& r );
template< class ForwardRange >
iterator_range< typename range_iterator<const ForwardRange>::type >
make_iterator_range( const ForwardRange& r );
template< class Range >
iterator_range< typename range_iterator<Range>::type >
make_iterator_range( Range& r,
typename range_difference<Range>::type advance_begin,
typename range_difference<Range>::type advance_end );
template< class Range >
iterator_range< typename range_iterator<const Range>::type >
make_iterator_range( const Range& r,
typename range_difference<Range>::type advance_begin,
typename range_difference<Range>::type advance_end );
template< class Sequence, class ForwardRange >
Sequence copy_range( const ForwardRange& r );
}
If an instance of
iterator_range is constructed by a client with two iterators, the
client must ensure that the two iterators delimit a valid closed-open range
[begin,end) .
It is worth noticing that the templated constructors and assignment operators
allow conversion from iterator_range<iterator> to
iterator_range<const_iterator> . Similarly, since the comparison
operators have two template arguments, we can compare ranges whenever the
iterators are comparable; for example when we are dealing with const and
non-const iterators from the same container.
Details member functions
operator unspecified_bool_type() const;
Returns !empty();
bool equal( iterator_range& r ) const;
Returns begin() == r.begin() && end() == r.end();
Details functions
bool operator==( const ForwardRange1& l, const ForwardRange2& r );
Returns size(l) != size(r) ? false : std::equal( begin(l), end(l), begin(r) );
bool operator!=( const ForwardRange1& l, const ForwardRange2& r );
Returns !( l == r );
bool operator<( const ForwardRange1& l, const ForwardRange2& r );
Returns std::lexicographical_compare( begin(l), end(l), begin(r), end(r) );
iterator_range make_iterator_range( Range& r,
typename range_difference<Range>::type advance_begin,
typename range_difference<Range>::type advance_end );
Effects:
iterator new_begin = begin( r ),
iterator new_end = end( r );
std::advance( new_begin, advance_begin );
std::advance( new_end, advance_end );
return make_iterator_range( new_begin, new_end );
Sequence copy_range( const ForwardRange& r );
Returns Sequence( begin(r), end(r) );
Class sub_range
The sub_range class inherits all its functionality
from the iterator_range class.
The sub_range class is often easier to use because
one must specify the Forward Range
template argument instead of an iterator. Moreover, the sub_range
class can propagate constness since it knows what a corresponding
const_iterator is.
Synopsis
namespace boost
{
template< class ForwardRange >
class sub_range : public iterator_range< typename range_iterator<ForwardRange>::type >
{
public:
typedef typename range_iterator<ForwardRange>::type iterator;
typedef typename range_iterator<const ForwardRange>::type const_iterator;
typedef typename iterator_difference<iterator>::type difference_type;
public: template< class ForwardTraversalIterator >
sub_range( ForwardTraversalIterator Begin, ForwardTraversalIterator End );
template< class ForwardRange2 >
sub_range( ForwardRange2& r );
template< class ForwardRange2 >
sub_range( const ForwardRange2& r );
template< class ForwardRange2 >
sub_range& operator=( ForwardRange2& r );
template< class ForwardRange2 >
sub_range& operator=( const ForwardRange2& r );
public: iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;
public: value_type& front();
const value_type& front() const;
value_type& back();
const value_type& back() const;
value_type& operator[]( difference_type at );
const value_type& operator[]( difference_type at ) const;
public:
};
}
The class should be trivial to use as seen below.
Imagine that we have an algorithm that searches for a sub-string in a string.
The
result is an iterator_range , that delimits the match. We need to
store the result
from this algorithm. Here is an example of how we can do it with and without
sub_range
std::string str("hello");
iterator_range<std::string::iterator> ir = find_first( str, as_literal("ll") );
sub_range<std::string> sub = find_first( str, as_literal("ll") );
© Copyright Thorsten Ottosen 2008.
Distributed under the Boost Software License, Version 1.0. (See
accompanying file LICENSE_1_0.txt or copy
at www.boost.org/LICENSE_1_0.txt)
|