]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Boost.Range library |
2 | // | |
3 | // Copyright Neil Groves 2010. Use, modification and | |
4 | // distribution is subject to the Boost Software License, Version | |
5 | // 1.0. (See accompanying file LICENSE_1_0.txt or copy at | |
6 | // http://www.boost.org/LICENSE_1_0.txt) | |
7 | // | |
8 | // For more information, see http://www.boost.org/libs/range/ | |
9 | // | |
10 | #ifndef BOOST_RANGE_DETAIL_ANY_ITERATOR_HPP_INCLUDED | |
11 | #define BOOST_RANGE_DETAIL_ANY_ITERATOR_HPP_INCLUDED | |
12 | ||
13 | #include <boost/mpl/and.hpp> | |
14 | #include <boost/mpl/or.hpp> | |
15 | #include <boost/mpl/not.hpp> | |
16 | #include <boost/iterator/iterator_facade.hpp> | |
17 | #include <boost/type_traits/is_const.hpp> | |
18 | #include <boost/type_traits/is_reference.hpp> | |
19 | #include <boost/type_traits/remove_reference.hpp> | |
20 | #include <boost/range/detail/any_iterator_buffer.hpp> | |
21 | #include <boost/range/detail/any_iterator_interface.hpp> | |
22 | #include <boost/range/detail/any_iterator_wrapper.hpp> | |
23 | #include <boost/utility/enable_if.hpp> | |
24 | ||
25 | namespace boost | |
26 | { | |
27 | namespace range_detail | |
28 | { | |
29 | // metafunction to determine if T is a const reference | |
30 | template<class T> | |
31 | struct is_const_reference | |
32 | { | |
33 | typedef typename mpl::and_< | |
34 | typename is_reference<T>::type, | |
35 | typename is_const< | |
36 | typename remove_reference<T>::type | |
37 | >::type | |
38 | >::type type; | |
39 | }; | |
40 | ||
41 | // metafunction to determine if T is a mutable reference | |
42 | template<class T> | |
43 | struct is_mutable_reference | |
44 | { | |
45 | typedef typename mpl::and_< | |
46 | typename is_reference<T>::type, | |
47 | typename mpl::not_< | |
48 | typename is_const< | |
49 | typename remove_reference<T>::type | |
50 | >::type | |
51 | >::type | |
52 | >::type type; | |
53 | }; | |
54 | ||
55 | // metafunction to evaluate if a source 'reference' can be | |
56 | // converted to a target 'reference' as a value. | |
57 | // | |
58 | // This is true, when the target reference type is actually | |
59 | // not a reference, and the source reference is convertible | |
60 | // to the target type. | |
61 | template<class SourceReference, class TargetReference> | |
62 | struct is_convertible_to_value_as_reference | |
63 | { | |
64 | typedef typename mpl::and_< | |
65 | typename mpl::not_< | |
66 | typename is_reference<TargetReference>::type | |
67 | >::type | |
68 | , typename is_convertible< | |
69 | SourceReference | |
70 | , TargetReference | |
71 | >::type | |
72 | >::type type; | |
73 | }; | |
74 | ||
75 | template< | |
76 | class Value | |
77 | , class Traversal | |
78 | , class Reference | |
79 | , class Difference | |
80 | , class Buffer = any_iterator_default_buffer | |
81 | > | |
82 | class any_iterator; | |
83 | ||
84 | // metafunction to determine if SomeIterator is an | |
85 | // any_iterator. | |
86 | // | |
87 | // This is the general implementation which evaluates to false. | |
88 | template<class SomeIterator> | |
89 | struct is_any_iterator | |
90 | : mpl::bool_<false> | |
91 | { | |
92 | }; | |
93 | ||
94 | // specialization of is_any_iterator to return true for | |
95 | // any_iterator classes regardless of template parameters. | |
96 | template< | |
97 | class Value | |
98 | , class Traversal | |
99 | , class Reference | |
100 | , class Difference | |
101 | , class Buffer | |
102 | > | |
103 | struct is_any_iterator< | |
104 | any_iterator< | |
105 | Value | |
106 | , Traversal | |
107 | , Reference | |
108 | , Difference | |
109 | , Buffer | |
110 | > | |
111 | > | |
112 | : mpl::bool_<true> | |
113 | { | |
114 | }; | |
115 | } // namespace range_detail | |
116 | ||
117 | namespace iterators | |
118 | { | |
119 | namespace detail | |
120 | { | |
121 | // Rationale: | |
122 | // These are specialized since the iterator_facade versions lack | |
123 | // the requisite typedefs to allow wrapping to determine the types | |
124 | // if a user copy constructs from a postfix increment. | |
125 | ||
126 | template< | |
127 | class Value | |
128 | , class Traversal | |
129 | , class Reference | |
130 | , class Difference | |
131 | , class Buffer | |
132 | > | |
133 | class postfix_increment_proxy< | |
134 | range_detail::any_iterator< | |
135 | Value | |
136 | , Traversal | |
137 | , Reference | |
138 | , Difference | |
139 | , Buffer | |
140 | > | |
141 | > | |
142 | { | |
143 | typedef range_detail::any_iterator< | |
144 | Value | |
145 | , Traversal | |
146 | , Reference | |
147 | , Difference | |
148 | , Buffer | |
149 | > any_iterator_type; | |
150 | ||
151 | public: | |
152 | typedef Value value_type; | |
153 | typedef typename std::iterator_traits<any_iterator_type>::iterator_category iterator_category; | |
154 | typedef Difference difference_type; | |
155 | typedef typename iterator_pointer<any_iterator_type>::type pointer; | |
156 | typedef Reference reference; | |
157 | ||
158 | explicit postfix_increment_proxy(any_iterator_type const& x) | |
159 | : stored_value(*x) | |
160 | {} | |
161 | ||
162 | value_type& | |
163 | operator*() const | |
164 | { | |
165 | return this->stored_value; | |
166 | } | |
167 | private: | |
168 | mutable value_type stored_value; | |
169 | }; | |
170 | ||
171 | template< | |
172 | class Value | |
173 | , class Traversal | |
174 | , class Reference | |
175 | , class Difference | |
176 | , class Buffer | |
177 | > | |
178 | class writable_postfix_increment_proxy< | |
179 | range_detail::any_iterator< | |
180 | Value | |
181 | , Traversal | |
182 | , Reference | |
183 | , Difference | |
184 | , Buffer | |
185 | > | |
186 | > | |
187 | { | |
188 | typedef range_detail::any_iterator< | |
189 | Value | |
190 | , Traversal | |
191 | , Reference | |
192 | , Difference | |
193 | , Buffer | |
194 | > any_iterator_type; | |
195 | public: | |
196 | typedef Value value_type; | |
197 | typedef typename std::iterator_traits<any_iterator_type>::iterator_category iterator_category; | |
198 | typedef Difference difference_type; | |
199 | typedef typename iterator_pointer<any_iterator_type>::type pointer; | |
200 | typedef Reference reference; | |
201 | ||
202 | explicit writable_postfix_increment_proxy(any_iterator_type const& x) | |
203 | : stored_value(*x) | |
204 | , stored_iterator(x) | |
205 | {} | |
206 | ||
207 | // Dereferencing must return a proxy so that both *r++ = o and | |
208 | // value_type(*r++) can work. In this case, *r is the same as | |
209 | // *r++, and the conversion operator below is used to ensure | |
210 | // readability. | |
211 | writable_postfix_increment_proxy const& | |
212 | operator*() const | |
213 | { | |
214 | return *this; | |
215 | } | |
216 | ||
217 | // Provides readability of *r++ | |
218 | operator value_type&() const | |
219 | { | |
220 | return stored_value; | |
221 | } | |
222 | ||
223 | // Provides writability of *r++ | |
224 | template <class T> | |
225 | T const& operator=(T const& x) const | |
226 | { | |
227 | *this->stored_iterator = x; | |
228 | return x; | |
229 | } | |
230 | ||
231 | // This overload just in case only non-const objects are writable | |
232 | template <class T> | |
233 | T& operator=(T& x) const | |
234 | { | |
235 | *this->stored_iterator = x; | |
236 | return x; | |
237 | } | |
238 | ||
239 | // Provides X(r++) | |
240 | operator any_iterator_type const&() const | |
241 | { | |
242 | return stored_iterator; | |
243 | } | |
244 | ||
245 | private: | |
246 | mutable value_type stored_value; | |
247 | any_iterator_type stored_iterator; | |
248 | }; | |
249 | ||
250 | } //namespace detail | |
251 | } //namespace iterators | |
252 | ||
253 | namespace range_detail | |
254 | { | |
255 | template< | |
256 | class Value | |
257 | , class Traversal | |
258 | , class Reference | |
259 | , class Difference | |
260 | , class Buffer | |
261 | > | |
262 | class any_iterator | |
263 | : public iterator_facade< | |
264 | any_iterator< | |
265 | Value | |
266 | , Traversal | |
267 | , Reference | |
268 | , Difference | |
269 | , Buffer | |
270 | > | |
271 | , Value | |
272 | , Traversal | |
273 | , Reference | |
274 | , Difference | |
275 | > | |
276 | { | |
277 | template< | |
278 | class OtherValue | |
279 | , class OtherTraversal | |
280 | , class OtherReference | |
281 | , class OtherDifference | |
282 | , class OtherBuffer | |
283 | > | |
284 | friend class any_iterator; | |
285 | ||
286 | struct enabler {}; | |
287 | struct disabler {}; | |
288 | ||
289 | typedef typename any_iterator_interface_type_generator< | |
290 | Traversal | |
291 | , Reference | |
292 | , Difference | |
293 | , Buffer | |
294 | >::type abstract_base_type; | |
295 | ||
296 | typedef iterator_facade< | |
297 | any_iterator< | |
298 | Value | |
299 | , Traversal | |
300 | , Reference | |
301 | , Difference | |
302 | , Buffer | |
303 | > | |
304 | , Value | |
305 | , Traversal | |
306 | , Reference | |
307 | , Difference | |
308 | > base_type; | |
309 | ||
310 | typedef Buffer buffer_type; | |
311 | ||
312 | public: | |
313 | typedef typename base_type::value_type value_type; | |
314 | typedef typename base_type::reference reference; | |
315 | typedef typename base_type::difference_type difference_type; | |
316 | ||
317 | // Default constructor | |
318 | any_iterator() | |
319 | : m_impl(0) {} | |
320 | ||
321 | // Simple copy construction without conversion | |
322 | any_iterator(const any_iterator& other) | |
323 | : base_type(other) | |
324 | , m_impl(other.m_impl | |
325 | ? other.m_impl->clone(m_buffer) | |
326 | : 0) | |
327 | { | |
328 | } | |
329 | ||
330 | // Simple assignment operator without conversion | |
331 | any_iterator& operator=(const any_iterator& other) | |
332 | { | |
333 | if (this != &other) | |
334 | { | |
335 | if (m_impl) | |
336 | m_impl->~abstract_base_type(); | |
337 | m_buffer.deallocate(); | |
338 | m_impl = 0; | |
339 | if (other.m_impl) | |
340 | m_impl = other.m_impl->clone(m_buffer); | |
341 | } | |
342 | return *this; | |
343 | } | |
344 | ||
345 | // Implicit conversion from another any_iterator where the | |
346 | // conversion is from a non-const reference to a const reference | |
347 | template< | |
348 | class OtherValue | |
349 | , class OtherTraversal | |
350 | , class OtherReference | |
351 | , class OtherDifference | |
352 | > | |
353 | any_iterator(const any_iterator< | |
354 | OtherValue, | |
355 | OtherTraversal, | |
356 | OtherReference, | |
357 | OtherDifference, | |
358 | Buffer | |
359 | >& other, | |
360 | typename ::boost::enable_if< | |
361 | typename mpl::and_< | |
362 | typename is_mutable_reference<OtherReference>::type, | |
363 | typename is_const_reference<Reference>::type | |
364 | >::type, | |
365 | enabler | |
366 | >::type* = 0 | |
367 | ) | |
368 | : m_impl(other.m_impl | |
369 | ? other.m_impl->clone_const_ref(m_buffer) | |
370 | : 0 | |
371 | ) | |
372 | { | |
373 | } | |
374 | ||
375 | // Implicit conversion from another any_iterator where the | |
376 | // reference types of the source and the target are references | |
377 | // that are either both const, or both non-const. | |
378 | template< | |
379 | class OtherValue | |
380 | , class OtherTraversal | |
381 | , class OtherReference | |
382 | , class OtherDifference | |
383 | > | |
384 | any_iterator(const any_iterator< | |
385 | OtherValue | |
386 | , OtherTraversal | |
387 | , OtherReference | |
388 | , OtherDifference | |
389 | , Buffer | |
390 | >& other, | |
391 | typename ::boost::enable_if< | |
392 | typename mpl::or_< | |
393 | typename mpl::and_< | |
394 | typename is_mutable_reference<OtherReference>::type, | |
395 | typename is_mutable_reference<Reference>::type | |
396 | >::type, | |
397 | typename mpl::and_< | |
398 | typename is_const_reference<OtherReference>::type, | |
399 | typename is_const_reference<Reference>::type | |
400 | >::type | |
401 | >::type, | |
402 | enabler | |
403 | >::type* = 0 | |
404 | ) | |
405 | : m_impl(other.m_impl | |
406 | ? other.m_impl->clone(m_buffer) | |
407 | : 0 | |
408 | ) | |
409 | { | |
410 | } | |
411 | ||
412 | // Implicit conversion to an any_iterator that uses a value for | |
413 | // the reference type. | |
414 | template< | |
415 | class OtherValue | |
416 | , class OtherTraversal | |
417 | , class OtherReference | |
418 | , class OtherDifference | |
419 | > | |
420 | any_iterator(const any_iterator< | |
421 | OtherValue | |
422 | , OtherTraversal | |
423 | , OtherReference | |
424 | , OtherDifference | |
425 | , Buffer | |
426 | >& other, | |
427 | typename ::boost::enable_if< | |
428 | typename is_convertible_to_value_as_reference< | |
429 | OtherReference | |
430 | , Reference | |
431 | >::type, | |
432 | enabler | |
433 | >::type* = 0 | |
434 | ) | |
435 | : m_impl(other.m_impl | |
436 | ? other.m_impl->clone_reference_as_value(m_buffer) | |
437 | : 0 | |
438 | ) | |
439 | { | |
440 | } | |
441 | ||
442 | any_iterator clone() const | |
443 | { | |
444 | any_iterator result; | |
445 | if (m_impl) | |
446 | result.m_impl = m_impl->clone(result.m_buffer); | |
447 | return result; | |
448 | } | |
449 | ||
450 | any_iterator< | |
451 | Value | |
452 | , Traversal | |
453 | , typename abstract_base_type::const_reference | |
454 | , Difference | |
455 | , Buffer | |
456 | > | |
457 | clone_const_ref() const | |
458 | { | |
459 | typedef any_iterator< | |
460 | Value | |
461 | , Traversal | |
462 | , typename abstract_base_type::const_reference | |
463 | , Difference | |
464 | , Buffer | |
465 | > result_type; | |
466 | ||
467 | result_type result; | |
468 | ||
469 | if (m_impl) | |
470 | result.m_impl = m_impl->clone_const_ref(result.m_buffer); | |
471 | ||
472 | return result; | |
473 | } | |
474 | ||
475 | // implicit conversion and construction from type-erasure-compatible | |
476 | // iterators | |
477 | template<class WrappedIterator> | |
478 | explicit any_iterator( | |
479 | const WrappedIterator& wrapped_iterator, | |
480 | typename disable_if< | |
481 | typename is_any_iterator<WrappedIterator>::type | |
482 | , disabler | |
483 | >::type* = 0 | |
484 | ) | |
485 | { | |
486 | typedef typename any_iterator_wrapper_type_generator< | |
487 | WrappedIterator | |
488 | , Traversal | |
489 | , Reference | |
490 | , Difference | |
491 | , Buffer | |
492 | >::type wrapper_type; | |
493 | ||
494 | void* ptr = m_buffer.allocate(sizeof(wrapper_type)); | |
495 | m_impl = new(ptr) wrapper_type(wrapped_iterator); | |
496 | } | |
497 | ||
498 | ~any_iterator() | |
499 | { | |
500 | // manually run the destructor, the deallocation is automatically | |
501 | // handled by the any_iterator_small_buffer base class. | |
502 | if (m_impl) | |
503 | m_impl->~abstract_base_type(); | |
504 | } | |
505 | ||
506 | private: | |
507 | friend class ::boost::iterator_core_access; | |
508 | ||
509 | Reference dereference() const | |
510 | { | |
511 | BOOST_ASSERT( m_impl ); | |
512 | return m_impl->dereference(); | |
513 | } | |
514 | ||
515 | bool equal(const any_iterator& other) const | |
516 | { | |
517 | return (m_impl == other.m_impl) | |
518 | || (m_impl && other.m_impl && m_impl->equal(*other.m_impl)); | |
519 | } | |
520 | ||
521 | void increment() | |
522 | { | |
523 | BOOST_ASSERT( m_impl ); | |
524 | m_impl->increment(); | |
525 | } | |
526 | ||
527 | void decrement() | |
528 | { | |
529 | BOOST_ASSERT( m_impl ); | |
530 | m_impl->decrement(); | |
531 | } | |
532 | ||
533 | Difference distance_to(const any_iterator& other) const | |
534 | { | |
535 | return m_impl && other.m_impl | |
536 | ? m_impl->distance_to(*other.m_impl) | |
537 | : 0; | |
538 | } | |
539 | ||
540 | void advance(Difference offset) | |
541 | { | |
542 | BOOST_ASSERT( m_impl ); | |
543 | m_impl->advance(offset); | |
544 | } | |
545 | ||
546 | any_iterator& swap(any_iterator& other) | |
547 | { | |
548 | BOOST_ASSERT( this != &other ); | |
549 | // grab a temporary copy of the other iterator | |
550 | any_iterator tmp(other); | |
551 | ||
552 | // deallocate the other iterator, taking care to obey the | |
553 | // class-invariants in-case of exceptions later | |
554 | if (other.m_impl) | |
555 | { | |
556 | other.m_impl->~abstract_base_type(); | |
557 | other.m_buffer.deallocate(); | |
558 | other.m_impl = 0; | |
559 | } | |
560 | ||
561 | // If this is a non-null iterator then we need to put | |
562 | // a clone of this iterators implementation into the other | |
563 | // iterator. | |
564 | // We can't just swap because of the small buffer optimization. | |
565 | if (m_impl) | |
566 | { | |
567 | other.m_impl = m_impl->clone(other.m_buffer); | |
568 | m_impl->~abstract_base_type(); | |
569 | m_buffer.deallocate(); | |
570 | m_impl = 0; | |
571 | } | |
572 | ||
573 | // assign to this instance a clone of the temporarily held | |
574 | // tmp which represents the input other parameter at the | |
575 | // start of execution of this function. | |
576 | if (tmp.m_impl) | |
577 | m_impl = tmp.m_impl->clone(m_buffer); | |
578 | ||
579 | return *this; | |
580 | } | |
581 | ||
582 | buffer_type m_buffer; | |
583 | abstract_base_type* m_impl; | |
584 | }; | |
585 | ||
586 | } // namespace range_detail | |
587 | } // namespace boost | |
588 | ||
589 | #endif // include guard |