extending.qbk 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  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. [section:method_1 Method 1: provide member functions and nested types]
  8. 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].
  9. 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.
  10. [table
  11. [[Member function] [Related concept ]]
  12. [[`begin()` ] [__single_pass_range__]]
  13. [[`end()` ] [__single_pass_range__]]
  14. ]
  15. Notice that `rbegin()` and `rend()` member functions are not needed even though the container can support bidirectional iteration.
  16. The required member types are:
  17. [table
  18. [[Member type ] [Related concept ]]
  19. [[`iterator` ] [__single_pass_range__]]
  20. [[`const_iterator`] [__single_pass_range__]]
  21. ]
  22. Again one should notice that member types `reverse_iterator` and `const_reverse_iterator` are not needed.
  23. [endsect]
  24. [section:method_2 Method 2: provide free-standing functions and specialize metafunctions]
  25. 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].
  26. 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.
  27. [table
  28. [[Function ] [Related concept ]]
  29. [[`range_begin(x)`] [__single_pass_range__]]
  30. [[`range_end(x)` ] [__single_pass_range__]]
  31. [[`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.]]
  32. ]
  33. `range_begin()` and `range_end()` must be overloaded for both `const` and `mutable` reference arguments.
  34. You must also specialize two metafunctions for your type `X`:
  35. [table
  36. [[Metafunction ] [Related concept ]]
  37. [[`boost::range_mutable_iterator`] [__single_pass_range__]]
  38. [[`boost::range_const_iterator`] [__single_pass_range__]]
  39. ]
  40. A complete example is given here:
  41. ``
  42. #include <boost/range.hpp>
  43. #include <iterator> // for std::iterator_traits, std::distance()
  44. namespace Foo
  45. {
  46. //
  47. // Our sample UDT. A 'Pair'
  48. // will work as a range when the stored
  49. // elements are iterators.
  50. //
  51. template< class T >
  52. struct Pair
  53. {
  54. T first, last;
  55. };
  56. } // namespace 'Foo'
  57. namespace boost
  58. {
  59. //
  60. // Specialize metafunctions. We must include the range.hpp header.
  61. // We must open the 'boost' namespace.
  62. //
  63. template< class T >
  64. struct range_mutable_iterator< Foo::Pair<T> >
  65. {
  66. typedef T type;
  67. };
  68. template< class T >
  69. struct range_const_iterator< Foo::Pair<T> >
  70. {
  71. //
  72. // Remark: this is defined similar to 'range_iterator'
  73. // because the 'Pair' type does not distinguish
  74. // between an iterator and a const_iterator.
  75. //
  76. typedef T type;
  77. };
  78. } // namespace 'boost'
  79. namespace Foo
  80. {
  81. //
  82. // The required functions. These should be defined in
  83. // the same namespace as 'Pair', in this case
  84. // in namespace 'Foo'.
  85. //
  86. template< class T >
  87. inline T range_begin( Pair<T>& x )
  88. {
  89. return x.first;
  90. }
  91. template< class T >
  92. inline T range_begin( const Pair<T>& x )
  93. {
  94. return x.first;
  95. }
  96. template< class T >
  97. inline T range_end( Pair<T>& x )
  98. {
  99. return x.last;
  100. }
  101. template< class T >
  102. inline T range_end( const Pair<T>& x )
  103. {
  104. return x.last;
  105. }
  106. } // namespace 'Foo'
  107. #include <vector>
  108. int main(int argc, const char* argv[])
  109. {
  110. typedef std::vector<int>::iterator iter;
  111. std::vector<int> vec;
  112. Foo::Pair<iter> pair = { vec.begin(), vec.end() };
  113. const Foo::Pair<iter>& cpair = pair;
  114. //
  115. // Notice that we call 'begin' etc with qualification.
  116. //
  117. iter i = boost::begin( pair );
  118. iter e = boost::end( pair );
  119. i = boost::begin( cpair );
  120. e = boost::end( cpair );
  121. boost::range_difference< Foo::Pair<iter> >::type s = boost::size( pair );
  122. s = boost::size( cpair );
  123. boost::range_reverse_iterator< const Foo::Pair<iter> >::type
  124. ri = boost::rbegin( cpair ),
  125. re = boost::rend( cpair );
  126. return 0;
  127. }
  128. ``
  129. [endsect]
  130. [section:method_3 Method 3: provide range adaptor implementations]
  131. [section:method_3_1 Method 3.1: Implement a Range Adaptor without arguments]
  132. To implement a Range Adaptor without arguments (e.g. reversed) you need to:
  133. # Provide a range for your return type, for example:
  134. ``
  135. #include <boost/range/iterator_range.hpp>
  136. #include <boost/iterator/reverse_iterator.hpp>
  137. template< typename R >
  138. struct reverse_range :
  139. boost::iterator_range<
  140. boost::reverse_iterator<
  141. typename boost::range_iterator<R>::type> >
  142. {
  143. private:
  144. typedef boost::iterator_range<
  145. boost::reverse_iterator<
  146. typename boost::range_iterator<R>::type> > base;
  147. public:
  148. typedef boost::reverse_iterator<
  149. typename boost::range_iterator<R>::type > iterator;
  150. reverse_range(R& r)
  151. : base(iterator(boost::end(r)), iterator(boost::begin(r)))
  152. { }
  153. };
  154. ``
  155. # Provide a tag to uniquely identify your adaptor in the `operator|` function overload set
  156. ``
  157. namespace detail {
  158. struct reverse_forwarder {};
  159. }
  160. ``
  161. # Implement `operator|`
  162. ``
  163. template< class BidirectionalRng >
  164. inline reverse_range<BidirectionalRng>
  165. operator|( BidirectionalRng& r, detail::reverse_forwarder )
  166. {
  167. return reverse_range<BidirectionalRng>( r );
  168. }
  169. template< class BidirectionalRng >
  170. inline reverse_range<const BidirectionalRng>
  171. operator|( const BidirectionalRng& r, detail::reverse_forwarder )
  172. {
  173. return reverse_range<const BidirectionalRng>( r );
  174. }
  175. ``
  176. # Declare the adaptor itself (it is a variable of the tag type).
  177. ``
  178. namespace
  179. {
  180. const detail::reverse_forwarder reversed = detail::reverse_forwarder();
  181. }
  182. ``
  183. [endsect]
  184. [section:method_3_2 Method 3.2: Implement a Range Adaptor with arguments]
  185. # Provide a range for your return type, for example:
  186. ``
  187. #include <boost/range/adaptor/argument_fwd.hpp>
  188. #include <boost/range/iterator_range.hpp>
  189. #include <boost/iterator/transform_iterator.hpp>
  190. template<typename Value>
  191. class replace_value
  192. {
  193. public:
  194. typedef const Value& result_type;
  195. typedef const Value& argument_type;
  196. replace_value(const Value& from, const Value& to)
  197. : m_from(from), m_to(to)
  198. {
  199. }
  200. const Value& operator()(const Value& x) const
  201. {
  202. return (x == m_from) ? m_to : x;
  203. }
  204. private:
  205. Value m_from;
  206. Value m_to;
  207. };
  208. template<typename Range>
  209. class replace_range
  210. : public boost::iterator_range<
  211. boost::transform_iterator<
  212. replace_value<typename boost::range_value<Range>::type>,
  213. typename boost::range_iterator<Range>::type> >
  214. {
  215. private:
  216. typedef typename boost::range_value<Range>::type value_type;
  217. typedef typename boost::range_iterator<Range>::type iterator_base;
  218. typedef replace_value<value_type> Fn;
  219. typedef boost::transform_iterator<Fn, iterator_base> replaced_iterator;
  220. typedef boost::iterator_range<replaced_iterator> base_t;
  221. public:
  222. replace_range(Range& rng, value_type from, value_type to)
  223. : base_t(replaced_iterator(boost::begin(rng), Fn(from,to)),
  224. replaced_iterator(boost::end(rng), Fn(from,to)))
  225. {
  226. }
  227. };
  228. ``
  229. # Implement a holder class to hold the arguments required to construct the RangeAdaptor.
  230. The holder combines multiple parameters into one that can be passed as the right operand of `operator|()`.
  231. ``
  232. template<typename T>
  233. class replace_holder : public boost::range_detail::holder2<T>
  234. {
  235. public:
  236. replace_holder(const T& from, const T& to)
  237. : boost::range_detail::holder2<T>(from, to)
  238. { }
  239. private:
  240. void operator=(const replace_holder&);
  241. };
  242. ``
  243. # Define an instance of the holder with the name of the adaptor
  244. ``
  245. static boost::range_detail::forwarder2<replace_holder>
  246. replaced = boost::range_detail::forwarder2<replace_holder>();
  247. ``
  248. # Define `operator|`
  249. ``
  250. template<typename SinglePassRange>
  251. inline replace_range<SinglePassRange>
  252. operator|(SinglePassRange& rng,
  253. const replace_holder<typename boost::range_value<SinglePassRange>::type>& f)
  254. {
  255. return replace_range<SinglePassRange>(rng, f.val1, f.val2);
  256. }
  257. template<typename SinglePassRange>
  258. inline replace_range<const SinglePassRange>
  259. operator|(const SinglePassRange& rng,
  260. const replace_holder<typename boost::range_value<SinglePassRange>::type>& f)
  261. {
  262. return replace_range<const SinglePassRange>(rng, f.val1, f.val2);
  263. }
  264. ``
  265. [endsect]
  266. [endsect]
  267. [endsect]