Brian Silverman | 598d029 | 2018-08-04 23:56:47 -0700 | [diff] [blame^] | 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 | |
| 10 | This 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 | |
| 12 | The 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 | |
| 20 | Notice that `rbegin()` and `rend()` member functions are not needed even though the container can support bidirectional iteration. |
| 21 | |
| 22 | The 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 | |
| 30 | Again 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 | |
| 36 | This 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 | |
| 38 | The 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 | |
| 49 | You 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 | |
| 57 | A 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 | |
| 169 | To 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 | |
| 176 | template< typename R > |
| 177 | struct reverse_range : |
| 178 | boost::iterator_range< |
| 179 | boost::reverse_iterator< |
| 180 | typename boost::range_iterator<R>::type> > |
| 181 | { |
| 182 | private: |
| 183 | typedef boost::iterator_range< |
| 184 | boost::reverse_iterator< |
| 185 | typename boost::range_iterator<R>::type> > base; |
| 186 | |
| 187 | public: |
| 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 | `` |
| 199 | namespace detail { |
| 200 | struct reverse_forwarder {}; |
| 201 | } |
| 202 | `` |
| 203 | |
| 204 | # Implement `operator|` |
| 205 | `` |
| 206 | template< class BidirectionalRng > |
| 207 | inline reverse_range<BidirectionalRng> |
| 208 | operator|( BidirectionalRng& r, detail::reverse_forwarder ) |
| 209 | { |
| 210 | return reverse_range<BidirectionalRng>( r ); |
| 211 | } |
| 212 | |
| 213 | template< class BidirectionalRng > |
| 214 | inline reverse_range<const BidirectionalRng> |
| 215 | operator|( 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 | `` |
| 223 | namespace |
| 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 | |
| 239 | template<typename Value> |
| 240 | class replace_value |
| 241 | { |
| 242 | public: |
| 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 | } |
| 255 | private: |
| 256 | Value m_from; |
| 257 | Value m_to; |
| 258 | }; |
| 259 | |
| 260 | template<typename Range> |
| 261 | class 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 | { |
| 267 | private: |
| 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 | |
| 274 | public: |
| 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. |
| 284 | The holder combines multiple parameters into one that can be passed as the right operand of `operator|()`. |
| 285 | `` |
| 286 | template<typename T> |
| 287 | class replace_holder : public boost::range_detail::holder2<T> |
| 288 | { |
| 289 | public: |
| 290 | replace_holder(const T& from, const T& to) |
| 291 | : boost::range_detail::holder2<T>(from, to) |
| 292 | { } |
| 293 | private: |
| 294 | void operator=(const replace_holder&); |
| 295 | }; |
| 296 | `` |
| 297 | |
| 298 | # Define an instance of the holder with the name of the adaptor |
| 299 | `` |
| 300 | static boost::range_detail::forwarder2<replace_holder> |
| 301 | replaced = boost::range_detail::forwarder2<replace_holder>(); |
| 302 | `` |
| 303 | |
| 304 | # Define `operator|` |
| 305 | `` |
| 306 | template<typename SinglePassRange> |
| 307 | inline replace_range<SinglePassRange> |
| 308 | operator|(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 | |
| 314 | template<typename SinglePassRange> |
| 315 | inline replace_range<const SinglePassRange> |
| 316 | operator|(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 | |