]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 |