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:extending Extending the library] 7 8[section:method_1 Method 1: provide member functions and nested types] 9 10This procedure assumes that you have control over the types that should be made conformant to a Range concept. If not, see [link range.reference.extending.method_2 method 2]. 11 12The primary templates in this library are implemented such that standard containers will work automatically and so will __boost_array__. Below is given an overview of which member functions and member types a class must specify to be useable as a certain Range concept. 13 14[table 15 [[Member function] [Related concept ]] 16 [[`begin()` ] [__single_pass_range__]] 17 [[`end()` ] [__single_pass_range__]] 18] 19 20Notice that `rbegin()` and `rend()` member functions are not needed even though the container can support bidirectional iteration. 21 22The required member types are: 23 24[table 25 [[Member type ] [Related concept ]] 26 [[`iterator` ] [__single_pass_range__]] 27 [[`const_iterator`] [__single_pass_range__]] 28] 29 30Again one should notice that member types `reverse_iterator` and `const_reverse_iterator` are not needed. 31 32[endsect] 33 34[section:method_2 Method 2: provide free-standing functions and specialize metafunctions] 35 36This procedure assumes that you cannot (or do not wish to) change the types that should be made conformant to a Range concept. If this is not true, see [link range.reference.extending.method_1 method 1]. 37 38The primary templates in this library are implemented such that certain functions are found via argument-dependent-lookup (ADL). Below is given an overview of which free-standing functions a class must specify to be useable as a certain Range concept. Let `x` be a variable (`const` or `mutable`) of the class in question. 39 40[table 41 [[Function ] [Related concept ]] 42 [[`range_begin(x)`] [__single_pass_range__]] 43 [[`range_end(x)` ] [__single_pass_range__]] 44 [[`range_calculate_size(x)`] [ Optional. This can be used to specify a mechanism for constant-time computation of the size of a range. The default behaviour is to return `boost::end(x) - boost::begin(x)` for random access ranges, and to return `x.size()` for ranges with lesser traversal capability. This behaviour can be changed by implementing `range_calculate_size` in a manner that will be found via ADL. The ability to calculate size in O(1) is often possible even with ranges with traversal categories less than random access.]] 45] 46 47`range_begin()` and `range_end()` must be overloaded for both `const` and `mutable` reference arguments. 48 49You must also specialize two metafunctions for your type `X`: 50 51[table 52 [[Metafunction ] [Related concept ]] 53 [[`boost::range_mutable_iterator`] [__single_pass_range__]] 54 [[`boost::range_const_iterator`] [__single_pass_range__]] 55] 56 57A complete example is given here: 58 59`` 60 #include <boost/range.hpp> 61 #include <iterator> // for std::iterator_traits, std::distance() 62 63 namespace Foo 64 { 65 // 66 // Our sample UDT. A 'Pair' 67 // will work as a range when the stored 68 // elements are iterators. 69 // 70 template< class T > 71 struct Pair 72 { 73 T first, last; 74 }; 75 76 } // namespace 'Foo' 77 78 namespace boost 79 { 80 // 81 // Specialize metafunctions. We must include the range.hpp header. 82 // We must open the 'boost' namespace. 83 // 84 85 template< class T > 86 struct range_mutable_iterator< Foo::Pair<T> > 87 { 88 typedef T type; 89 }; 90 91 template< class T > 92 struct range_const_iterator< Foo::Pair<T> > 93 { 94 // 95 // Remark: this is defined similar to 'range_iterator' 96 // because the 'Pair' type does not distinguish 97 // between an iterator and a const_iterator. 98 // 99 typedef T type; 100 }; 101 102 } // namespace 'boost' 103 104 namespace Foo 105 { 106 // 107 // The required functions. These should be defined in 108 // the same namespace as 'Pair', in this case 109 // in namespace 'Foo'. 110 // 111 112 template< class T > 113 inline T range_begin( Pair<T>& x ) 114 { 115 return x.first; 116 } 117 118 template< class T > 119 inline T range_begin( const Pair<T>& x ) 120 { 121 return x.first; 122 } 123 124 template< class T > 125 inline T range_end( Pair<T>& x ) 126 { 127 return x.last; 128 } 129 130 template< class T > 131 inline T range_end( const Pair<T>& x ) 132 { 133 return x.last; 134 } 135 136 } // namespace 'Foo' 137 138 #include <vector> 139 140 int main(int argc, const char* argv[]) 141 { 142 typedef std::vector<int>::iterator iter; 143 std::vector<int> vec; 144 Foo::Pair<iter> pair = { vec.begin(), vec.end() }; 145 const Foo::Pair<iter>& cpair = pair; 146 // 147 // Notice that we call 'begin' etc with qualification. 148 // 149 iter i = boost::begin( pair ); 150 iter e = boost::end( pair ); 151 i = boost::begin( cpair ); 152 e = boost::end( cpair ); 153 boost::range_difference< Foo::Pair<iter> >::type s = boost::size( pair ); 154 s = boost::size( cpair ); 155 boost::range_reverse_iterator< const Foo::Pair<iter> >::type 156 ri = boost::rbegin( cpair ), 157 re = boost::rend( cpair ); 158 159 return 0; 160 } 161`` 162 163[endsect] 164 165[section:method_3 Method 3: provide range adaptor implementations] 166 167[section:method_3_1 Method 3.1: Implement a Range Adaptor without arguments] 168 169To implement a Range Adaptor without arguments (e.g. reversed) you need to: 170 171# Provide a range for your return type, for example: 172`` 173#include <boost/range/iterator_range.hpp> 174#include <boost/iterator/reverse_iterator.hpp> 175 176template< typename R > 177struct reverse_range : 178 boost::iterator_range< 179 boost::reverse_iterator< 180 typename boost::range_iterator<R>::type> > 181{ 182private: 183 typedef boost::iterator_range< 184 boost::reverse_iterator< 185 typename boost::range_iterator<R>::type> > base; 186 187public: 188 typedef boost::reverse_iterator< 189 typename boost::range_iterator<R>::type > iterator; 190 191 reverse_range(R& r) 192 : base(iterator(boost::end(r)), iterator(boost::begin(r))) 193 { } 194}; 195`` 196 197# Provide a tag to uniquely identify your adaptor in the `operator|` function overload set 198`` 199namespace detail { 200 struct reverse_forwarder {}; 201} 202`` 203 204# Implement `operator|` 205`` 206template< class BidirectionalRng > 207inline reverse_range<BidirectionalRng> 208operator|( BidirectionalRng& r, detail::reverse_forwarder ) 209{ 210 return reverse_range<BidirectionalRng>( r ); 211} 212 213template< class BidirectionalRng > 214inline reverse_range<const BidirectionalRng> 215operator|( const BidirectionalRng& r, detail::reverse_forwarder ) 216{ 217 return reverse_range<const BidirectionalRng>( r ); 218} 219`` 220 221# Declare the adaptor itself (it is a variable of the tag type). 222`` 223namespace 224{ 225 const detail::reverse_forwarder reversed = detail::reverse_forwarder(); 226} 227`` 228 229[endsect] 230 231[section:method_3_2 Method 3.2: Implement a Range Adaptor with arguments] 232 233# Provide a range for your return type, for example: 234`` 235#include <boost/range/adaptor/argument_fwd.hpp> 236#include <boost/range/iterator_range.hpp> 237#include <boost/iterator/transform_iterator.hpp> 238 239template<typename Value> 240class replace_value 241{ 242public: 243 typedef const Value& result_type; 244 typedef const Value& argument_type; 245 246 replace_value(const Value& from, const Value& to) 247 : m_from(from), m_to(to) 248 { 249 } 250 251 const Value& operator()(const Value& x) const 252 { 253 return (x == m_from) ? m_to : x; 254 } 255private: 256 Value m_from; 257 Value m_to; 258}; 259 260template<typename Range> 261class replace_range 262: public boost::iterator_range< 263 boost::transform_iterator< 264 replace_value<typename boost::range_value<Range>::type>, 265 typename boost::range_iterator<Range>::type> > 266{ 267private: 268 typedef typename boost::range_value<Range>::type value_type; 269 typedef typename boost::range_iterator<Range>::type iterator_base; 270 typedef replace_value<value_type> Fn; 271 typedef boost::transform_iterator<Fn, iterator_base> replaced_iterator; 272 typedef boost::iterator_range<replaced_iterator> base_t; 273 274public: 275 replace_range(Range& rng, value_type from, value_type to) 276 : base_t(replaced_iterator(boost::begin(rng), Fn(from,to)), 277 replaced_iterator(boost::end(rng), Fn(from,to))) 278 { 279 } 280 }; 281`` 282 283# Implement a holder class to hold the arguments required to construct the RangeAdaptor. 284The holder combines multiple parameters into one that can be passed as the right operand of `operator|()`. 285`` 286template<typename T> 287class replace_holder : public boost::range_detail::holder2<T> 288{ 289public: 290 replace_holder(const T& from, const T& to) 291 : boost::range_detail::holder2<T>(from, to) 292 { } 293private: 294 void operator=(const replace_holder&); 295}; 296`` 297 298# Define an instance of the holder with the name of the adaptor 299`` 300static boost::range_detail::forwarder2<replace_holder> 301replaced = boost::range_detail::forwarder2<replace_holder>(); 302`` 303 304# Define `operator|` 305`` 306template<typename SinglePassRange> 307inline replace_range<SinglePassRange> 308operator|(SinglePassRange& rng, 309 const replace_holder<typename boost::range_value<SinglePassRange>::type>& f) 310{ 311 return replace_range<SinglePassRange>(rng, f.val1, f.val2); 312} 313 314template<typename SinglePassRange> 315inline replace_range<const SinglePassRange> 316operator|(const SinglePassRange& rng, 317 const replace_holder<typename boost::range_value<SinglePassRange>::type>& f) 318{ 319 return replace_range<const SinglePassRange>(rng, f.val1, f.val2); 320} 321`` 322 323[endsect] 324 325[endsect] 326 327[endsect] 328 329