• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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