1[/ 2 Copyright 2010 Neil Groves 3 Distributed under the Boost Software License, Version 1.0. 4 (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5/] 6[section:utilities Utilities] 7 8Having 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: 9 10* Class `iterator_range` 11* Class `sub_range` 12* Function `combine` 13* Function `join` 14 15The `iterator_range` class is templated on an __forward_traversal_iterator__ and should be used whenever fairly general code is needed. The `sub_range` class is templated on an __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. 16 17Both classes can be used as ranges since they implement the __minimal_interface__ required for this to work automatically. 18 19[section:iterator_range Class `iterator_range`] 20 21The 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. 22 23If 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 Traversal Iterators whereas `empty()` only requires Single Pass Iterators. 24 25Recall that many default constructed iterators are [*/singular/] and hence can only be assigned, but not compared or incremented or anything. However, if one creates a default constructed `iterator_range`, then one can still call all its member functions. This design decision avoids the `iterator_range` imposing limitations upon ranges of iterators that are not singular. Any singularity limitation is simply propagated from the underlying iterator type. 26 27 28[h4 Synopsis] 29 30The core functionality is in the header file 31`<boost/range/iterator_range_core.hpp>` this includes all of the functionality 32except the `boost::hash_value` and `std::iostream` support. 33 34The `std::iostream` support is in the header `<boost/range/iterator_core.hpp>` 35while the `boost::hash_value` support is in 36`<boost/range/iterator_range_hash.hpp>` 37 38`` 39namespace boost 40{ 41 template< class ForwardTraversalIterator > 42 class iterator_range 43 { 44 public: // Forward Range types 45 typedef ForwardTraversalIterator iterator; 46 typedef ForwardTraversalIterator const_iterator; 47 typedef iterator_difference<iterator>::type difference_type; 48 49 public: // construction, assignment 50 template< class ForwardTraversalIterator2 > 51 iterator_range( ForwardTraversalIterator2 Begin, ForwardTraversalIterator2 End ); 52 53 template< class ForwardRange > 54 iterator_range( ForwardRange& r ); 55 56 template< class ForwardRange > 57 iterator_range( const ForwardRange& r ); 58 59 template< class ForwardRange > 60 iterator_range& operator=( ForwardRange& r ); 61 62 template< class ForwardRange > 63 iterator_range& operator=( const ForwardRange& r ); 64 65 public: // Forward Range functions 66 iterator begin() const; 67 iterator end() const; 68 69 public: // convenience 70 operator unspecified_bool_type() const; 71 bool equal( const iterator_range& ) const; 72 value_type& front() const; 73 void drop_front(); 74 void drop_front(difference_type n); 75 bool empty() const; 76 77 iterator_range& advance_begin(difference_type n); 78 iterator_range& advance_end(difference_type n); 79 80 // for Bidirectional: 81 value_type& back() const; 82 void drop_back(); 83 void drop_back(difference_type n); 84 // for Random Access only: 85 reference operator[]( difference_type at ) const; 86 value_type operator()( difference_type at ) const; 87 size_type size() const; 88 }; 89 90 // stream output 91 template< class ForwardTraversalIterator, class T, class Traits > 92 std::basic_ostream<T,Traits>& 93 operator<<( std::basic_ostream<T,Traits>& Os, 94 const iterator_range<ForwardTraversalIterator>& r ); 95 96 // comparison 97 template< class ForwardTraversalIterator, class ForwardTraversalIterator2 > 98 bool operator==( const iterator_range<ForwardTraversalIterator>& l, 99 const iterator_range<ForwardTraversalIterator2>& r ); 100 101 template< class ForwardTraversalIterator, class ForwardRange > 102 bool operator==( const iterator_range<ForwardTraversalIterator>& l, 103 const ForwardRange& r ); 104 105 template< class ForwardTraversalIterator, class ForwardRange > 106 bool operator==( const ForwardRange& l, 107 const iterator_range<ForwardTraversalIterator>& r ); 108 109 template< class ForwardTraversalIterator, class ForwardTraversalIterator2 > 110 bool operator!=( const iterator_range<ForwardTraversalIterator>& l, 111 const iterator_range<ForwardTraversalIterator2>& r ); 112 113 template< class ForwardTraversalIterator, class ForwardRange > 114 bool operator!=( const iterator_range<ForwardTraversalIterator>& l, 115 const ForwardRange& r ); 116 117 template< class ForwardTraversalIterator, class ForwardRange > 118 bool operator!=( const ForwardRange& l, 119 const iterator_range<ForwardTraversalIterator>& r ); 120 121 template< class ForwardTraversalIterator, class ForwardTraversalIterator2 > 122 bool operator<( const iterator_range<ForwardTraversalIterator>& l, 123 const iterator_range<ForwardTraversalIterator2>& r ); 124 125 template< class ForwardTraversalIterator, class ForwardRange > 126 bool operator<( const iterator_range<ForwardTraversalIterator>& l, 127 const ForwardRange& r ); 128 129 template< class ForwardTraversalIterator, class ForwardRange > 130 bool operator<( const ForwardRange& l, 131 const iterator_range<ForwardTraversalIterator>& r ); 132 133 // external construction 134 template< class ForwardTraversalIterator > 135 iterator_range< ForwardTraversalIterator > 136 make_iterator_range( ForwardTraversalIterator Begin, 137 ForwardTraversalIterator End ); 138 139 // Make an iterator_range [first, boost::next(first, n) ) 140 template< class ForwardTraversalIterator, class Integer > 141 iterator_range< ForwardTraversalIterator > 142 make_iterator_range_n( ForwardTraversalIterator first, Integer n ); 143 144 145 template< class ForwardRange > 146 iterator_range< typename range_iterator<ForwardRange>::type > 147 make_iterator_range( ForwardRange& r ); 148 149 template< class ForwardRange > 150 iterator_range< typename range_iterator<const ForwardRange>::type > 151 make_iterator_range( const ForwardRange& r ); 152 153 template< class Range > 154 iterator_range< typename range_iterator<Range>::type > 155 make_iterator_range( Range& r, 156 typename range_difference<Range>::type advance_begin, 157 typename range_difference<Range>::type advance_end ); 158 159 template< class Range > 160 iterator_range< typename range_iterator<const Range>::type > 161 make_iterator_range( const Range& r, 162 typename range_difference<const Range>::type advance_begin, 163 typename range_difference<const Range>::type advance_end ); 164 165 // convenience 166 template< class Sequence, class ForwardRange > 167 Sequence copy_range( const ForwardRange& r ); 168 169} // namespace 'boost' 170`` 171 172If 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). 173 174It 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. 175 176[h4 Details member functions] 177 178`operator unspecified_bool_type() const;` 179 180[:['[*Returns]] `!empty();`] 181 182`bool equal( iterator_range& r ) const;` 183 184[:['[*Returns]] `begin() == r.begin() && end() == r.end();`] 185 186[h4 Details functions] 187 188`bool operator==( const ForwardRange1& l, const ForwardRange2& r );` 189 190[:['[*Returns]] `size(l) != size(r) ? false : std::equal( begin(l), end(l), begin(r) );`] 191 192`bool operator!=( const ForwardRange1& l, const ForwardRange2& r );` 193 194[:['[*Returns]] `!( l == r );`] 195 196`bool operator<( const ForwardRange1& l, const ForwardRange2& r );` 197 198[:['[*Returns]] `std::lexicographical_compare( begin(l), end(l), begin(r), end(r) );`] 199 200`` 201iterator_range make_iterator_range( Range& r, 202 typename range_difference<Range>::type advance_begin, 203 typename range_difference<Range>::type advance_end ); 204`` 205 206[:['[*Effects:]]] 207 208`` 209 iterator new_begin = begin( r ), 210 iterator new_end = end( r ); 211 std::advance( new_begin, advance_begin ); 212 std::advance( new_end, advance_end ); 213 return make_iterator_range( new_begin, new_end ); 214`` 215 216`Sequence copy_range( const ForwardRange& r );` 217 218[:['[*Returns]] `Sequence( begin(r), end(r) );`] 219 220[endsect] 221 222[section:sub_range Class `sub_range`] 223 224The `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. 225 226[h4 Synopsis] 227 228`` 229namespace boost 230{ 231 template< class ForwardRange > 232 class sub_range : public iterator_range< typename range_iterator<ForwardRange>::type > 233 { 234 public: 235 typedef typename range_value<ForwardRange>::type value_type; 236 typedef typename range_iterator<ForwardRange>::type iterator; 237 typedef typename range_iterator<const ForwardRange>::type const_iterator; 238 typedef typename range_difference<ForwardRange>::type difference_type; 239 typedef typename range_size<ForwardRange>::type size_type; 240 typedef typename range_reference<ForwardRange>::type reference; 241 typedef typename range_reference<const ForwardRange>::type const_reference; 242 243 public: // construction, assignment 244 sub_range(); 245 246 template< class ForwardTraversalIterator > 247 sub_range( ForwardTraversalIterator Begin, ForwardTraversalIterator End ); 248 249 template< class ForwardRange2 > 250 sub_range( ForwardRange2& r ); 251 252 template< class ForwardRange2 > 253 sub_range( const Range2& r ); 254 255 template< class ForwardRange2 > 256 sub_range& operator=( ForwardRange2& r ); 257 258 template< class ForwardRange2 > 259 sub_range& operator=( const ForwardRange2& r ); 260 261 // iterator accessors 262 const_iterator begin() const; 263 iterator begin(); 264 const_iterator end() const; 265 iterator end(); 266 267 reference front(); 268 const_reference front() const; 269 270 sub_range& advance_begin(difference_type n); 271 sub_range& advance_end(difference_type n); 272 273 // If traversal >= bidirectional: 274 reference back(); 275 const_reference back(); 276 277 // If traversal >= random-access: 278 reference operator[](difference_type n); 279 const_reference operator[](difference_type n) const; 280 281 public: 282 // rest of interface inherited from iterator_range 283 }; 284 285} // namespace 'boost' 286`` 287 288The 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` 289 290`` 291std::string str("hello"); 292iterator_range<std::string::iterator> ir = find_first( str, "ll" ); 293sub_range<std::string> sub = find_first( str, "ll" ); 294`` 295 296[endsect] 297 298[section:combine Function combine] 299 300The `combine` function is used to make one range from multiple ranges. The 301`combine` function returns a `combined_range` which is an `iterator_range` of 302a `zip_iterator` from the Boost.Iterator library. 303 304[h4 Synopsis] 305 306`` 307namespace boost 308{ 309 namespace range 310 { 311 312template<typename IterTuple> 313class combined_range 314 : public iterator_range<zip_iterator<IterTuple> > 315{ 316public: 317 combined_range(IterTuple first, IterTuple last); 318}; 319 320template<typename... Ranges> 321auto combine(Ranges&&... rngs) -> 322 combined_range<decltype(boost::make_tuple(boost::begin(rngs)...))> 323 324 } // namespace range 325} // namespace boost 326`` 327 328* [*Precondition:] For each type `r` in `Ranges`, `r` is a model of 329__single_pass_range__ or better. 330* [*Return Type:] `combined_range<tuple<typename range_iterator<Ranges>::type...> >` 331* [*Returned Range Category:] The minimum of the range category of every range 332`r` in `Ranges`. 333 334[h4 Example] 335 336`` 337#include <boost/range/combine.hpp> 338#include <boost/foreach.hpp> 339#include <iostream> 340#include <vector> 341#include <list> 342 343int main(int, const char*[]) 344{ 345 std::vector<int> v; 346 std::list<char> l; 347 for (int i = 0; i < 5; ++i) 348 { 349 v.push_back(i); 350 l.push_back(static_cast<char>(i) + 'a'); 351 } 352 353 int ti; 354 char tc; 355 BOOST_FOREACH(boost::tie(ti, tc), boost::combine(v, l)) 356 { 357 std::cout << '(' << ti << ',' << tc << ')' << '\n'; 358 } 359 360 return 0; 361} 362`` 363 364This produces the output: 365`` 366(0,a) 367(1,b) 368(2,c) 369(3,d) 370(4,e) 371`` 372 373[endsect] 374 375[section:join Function join] 376 377The intention of the `join` function is to join two ranges into one longer range. 378 379The resultant range will have the lowest common traversal of the two ranges supplied as parameters. 380 381Note that the joined range incurs a performance cost due to the need to check if the end of a range has been reached internally during traversal. 382 383[h4 Synopsis] 384 385`` 386template<typename SinglePassRange1, typename SinglePassRange2> 387joined_range<const SinglePassRange1, const SinglePassRange2> 388join(const SinglePassRange1& rng1, const SinglePassRange2& rng2) 389 390template<typename SinglePassRange1, typename SinglePassRange2> 391joined_range<SinglePassRange1, SinglePassRange2> 392join(SinglePassRange1& rng1, SinglePassRange2& rng2); 393`` 394 395For the const version: 396 397* [*Precondition:] The `range_value<SinglePassRange2>::type` must be convertible to `range_value<SinglePassRange1>::type`. The `range_reference<const SinglePassRange2>::type` must be convertible to `range_reference<const SinglePassRange1>::type`. 398* [*Range Category:] Both `rng1` and `rng2` must be a model of __single_pass_range__ or better. 399* [*Range Return Type:] `joined_range<const SinglePassRange1, const SinglePassRange2>` which is a model of the lesser of the two range concepts passed. 400* [*Returned Range Category:] The minimum of the range category of `rng1` and `rng2`. 401 402For the mutable version: 403 404* [*Precondition:] The `range_value<SinglePassRange2>::type` must be convertible to `range_value<SinglePassRange1>::type`. The `range_reference<SinglePassRange2>::type` must be convertible to `range_reference<SinglePassRange1>::type`. 405* [*Range Category:] Both `rng1` and `rng2` must be a model of __single_pass_range__ or better. 406* [*Range Return Type:] `joined_range<SinglePassRange1, SinglePassRange2>` which is a model of the lesser of the two range concepts passed. 407* [*Returned Range Category:] The minimum of the range category of `rng1` and `rng2`. 408 409[h4 Example] 410 411The expression `join(irange(0,5), irange(5,10))` would evaluate to a range representing an integer range `[0,10)` 412 413 414[endsect] 415 416[endsect] 417 418