| // Boost.Range library |
| // |
| // Copyright Neil Groves 2010. Use, modification and |
| // distribution is subject to the Boost Software License, Version |
| // 1.0. (See accompanying file LICENSE_1_0.txt or copy at |
| // http://www.boost.org/LICENSE_1_0.txt) |
| // |
| // For more information, see http://www.boost.org/libs/range/ |
| // |
| #ifndef BOOST_RANGE_DETAIL_ANY_ITERATOR_HPP_INCLUDED |
| #define BOOST_RANGE_DETAIL_ANY_ITERATOR_HPP_INCLUDED |
| |
| #include <boost/cast.hpp> |
| #include <boost/utility.hpp> |
| #include <boost/mpl/and.hpp> |
| #include <boost/mpl/or.hpp> |
| #include <boost/mpl/not.hpp> |
| #include <boost/type_traits/is_const.hpp> |
| #include <boost/type_traits/is_reference.hpp> |
| #include <boost/type_traits/remove_reference.hpp> |
| #include <boost/range/detail/any_iterator_buffer.hpp> |
| #include <boost/range/detail/any_iterator_interface.hpp> |
| #include <boost/range/detail/any_iterator_wrapper.hpp> |
| |
| namespace boost |
| { |
| namespace range_detail |
| { |
| // metafunction to determine if T is a const reference |
| template<class T> |
| struct is_const_reference |
| { |
| typedef typename mpl::and_< |
| typename is_reference<T>::type, |
| typename is_const< |
| typename remove_reference<T>::type |
| >::type |
| >::type type; |
| }; |
| |
| // metafunction to determine if T is a mutable reference |
| template<class T> |
| struct is_mutable_reference |
| { |
| typedef typename mpl::and_< |
| typename is_reference<T>::type, |
| typename mpl::not_< |
| typename is_const< |
| typename remove_reference<T>::type |
| >::type |
| >::type |
| >::type type; |
| }; |
| |
| // metafunction to evaluate if a source 'reference' can be |
| // converted to a target 'reference' as a value. |
| // |
| // This is true, when the target reference type is actually |
| // not a reference, and the source reference is convertible |
| // to the target type. |
| template<class SourceReference, class TargetReference> |
| struct is_convertible_to_value_as_reference |
| { |
| typedef typename mpl::and_< |
| typename mpl::not_< |
| typename is_reference<TargetReference>::type |
| >::type |
| , typename is_convertible< |
| SourceReference |
| , TargetReference |
| >::type |
| >::type type; |
| }; |
| |
| template< |
| class Value |
| , class Traversal |
| , class Reference |
| , class Difference |
| , class Buffer = any_iterator_default_buffer |
| > |
| class any_iterator; |
| |
| // metafunction to determine if SomeIterator is an |
| // any_iterator. |
| // |
| // This is the general implementation which evaluates to false. |
| template<class SomeIterator> |
| struct is_any_iterator |
| : mpl::bool_<false> |
| { |
| }; |
| |
| // specialization of is_any_iterator to return true for |
| // any_iterator classes regardless of template parameters. |
| template< |
| class Value |
| , class Traversal |
| , class Reference |
| , class Difference |
| , class Buffer |
| > |
| struct is_any_iterator< |
| any_iterator< |
| Value |
| , Traversal |
| , Reference |
| , Difference |
| , Buffer |
| > |
| > |
| : mpl::bool_<true> |
| { |
| }; |
| } // namespace range_detail |
| |
| namespace detail |
| { |
| // Rationale: |
| // These are specialized since the iterator_facade versions lack |
| // the requisite typedefs to allow wrapping to determine the types |
| // if a user copy constructs from a postfix increment. |
| |
| template< |
| class Value |
| , class Traversal |
| , class Reference |
| , class Difference |
| , class Buffer |
| > |
| class postfix_increment_proxy< |
| range_detail::any_iterator< |
| Value |
| , Traversal |
| , Reference |
| , Difference |
| , Buffer |
| > |
| > |
| { |
| typedef range_detail::any_iterator< |
| Value |
| , Traversal |
| , Reference |
| , Difference |
| , Buffer |
| > any_iterator_type; |
| |
| public: |
| typedef Value value_type; |
| typedef typename std::iterator_traits<any_iterator_type>::iterator_category iterator_category; |
| typedef Difference difference_type; |
| typedef typename iterator_pointer<any_iterator_type>::type pointer; |
| typedef Reference reference; |
| |
| explicit postfix_increment_proxy(any_iterator_type const& x) |
| : stored_value(*x) |
| {} |
| |
| value_type& |
| operator*() const |
| { |
| return this->stored_value; |
| } |
| private: |
| mutable value_type stored_value; |
| }; |
| |
| template< |
| class Value |
| , class Traversal |
| , class Reference |
| , class Difference |
| , class Buffer |
| > |
| class writable_postfix_increment_proxy< |
| range_detail::any_iterator< |
| Value |
| , Traversal |
| , Reference |
| , Difference |
| , Buffer |
| > |
| > |
| { |
| typedef range_detail::any_iterator< |
| Value |
| , Traversal |
| , Reference |
| , Difference |
| , Buffer |
| > any_iterator_type; |
| public: |
| typedef Value value_type; |
| typedef typename std::iterator_traits<any_iterator_type>::iterator_category iterator_category; |
| typedef Difference difference_type; |
| typedef typename iterator_pointer<any_iterator_type>::type pointer; |
| typedef Reference reference; |
| |
| explicit writable_postfix_increment_proxy(any_iterator_type const& x) |
| : stored_value(*x) |
| , stored_iterator(x) |
| {} |
| |
| // Dereferencing must return a proxy so that both *r++ = o and |
| // value_type(*r++) can work. In this case, *r is the same as |
| // *r++, and the conversion operator below is used to ensure |
| // readability. |
| writable_postfix_increment_proxy const& |
| operator*() const |
| { |
| return *this; |
| } |
| |
| // Provides readability of *r++ |
| operator value_type&() const |
| { |
| return stored_value; |
| } |
| |
| // Provides writability of *r++ |
| template <class T> |
| T const& operator=(T const& x) const |
| { |
| *this->stored_iterator = x; |
| return x; |
| } |
| |
| // This overload just in case only non-const objects are writable |
| template <class T> |
| T& operator=(T& x) const |
| { |
| *this->stored_iterator = x; |
| return x; |
| } |
| |
| // Provides X(r++) |
| operator any_iterator_type const&() const |
| { |
| return stored_iterator; |
| } |
| |
| private: |
| mutable value_type stored_value; |
| any_iterator_type stored_iterator; |
| }; |
| |
| |
| } |
| |
| namespace range_detail |
| { |
| template< |
| class Value |
| , class Traversal |
| , class Reference |
| , class Difference |
| , class Buffer |
| > |
| class any_iterator |
| : public iterator_facade< |
| any_iterator< |
| Value |
| , Traversal |
| , Reference |
| , Difference |
| , Buffer |
| > |
| , Value |
| , Traversal |
| , Reference |
| , Difference |
| > |
| { |
| template< |
| class OtherValue |
| , class OtherTraversal |
| , class OtherReference |
| , class OtherDifference |
| , class OtherBuffer |
| > |
| friend class any_iterator; |
| |
| struct enabler {}; |
| struct disabler {}; |
| |
| typedef typename any_iterator_interface_type_generator< |
| Traversal |
| , Reference |
| , Difference |
| , Buffer |
| >::type abstract_base_type; |
| |
| typedef iterator_facade< |
| any_iterator< |
| Value |
| , Traversal |
| , Reference |
| , Difference |
| , Buffer |
| > |
| , Value |
| , Traversal |
| , Reference |
| , Difference |
| > base_type; |
| |
| typedef Buffer buffer_type; |
| |
| public: |
| typedef typename base_type::value_type value_type; |
| typedef typename base_type::reference reference; |
| typedef typename base_type::difference_type difference_type; |
| |
| // Default constructor |
| any_iterator() |
| : m_impl(0) {} |
| |
| // Simple copy construction without conversion |
| any_iterator(const any_iterator& other) |
| : base_type(other) |
| , m_impl(other.m_impl |
| ? other.m_impl->clone(m_buffer) |
| : 0) |
| { |
| } |
| |
| // Simple assignment operator without conversion |
| any_iterator& operator=(const any_iterator& other) |
| { |
| if (this != &other) |
| { |
| if (m_impl) |
| m_impl->~abstract_base_type(); |
| m_buffer.deallocate(); |
| m_impl = 0; |
| if (other.m_impl) |
| m_impl = other.m_impl->clone(m_buffer); |
| } |
| return *this; |
| } |
| |
| // Implicit conversion from another any_iterator where the |
| // conversion is from a non-const reference to a const reference |
| template< |
| class OtherValue |
| , class OtherTraversal |
| , class OtherReference |
| , class OtherDifference |
| > |
| any_iterator(const any_iterator< |
| OtherValue, |
| OtherTraversal, |
| OtherReference, |
| OtherDifference, |
| Buffer |
| >& other, |
| typename enable_if< |
| typename mpl::and_< |
| typename is_mutable_reference<OtherReference>::type, |
| typename is_const_reference<Reference>::type |
| >::type, |
| enabler |
| >::type* = 0 |
| ) |
| : m_impl(other.m_impl |
| ? other.m_impl->clone_const_ref(m_buffer) |
| : 0 |
| ) |
| { |
| } |
| |
| // Implicit conversion from another any_iterator where the |
| // reference types of the source and the target are references |
| // that are either both const, or both non-const. |
| template< |
| class OtherValue |
| , class OtherTraversal |
| , class OtherReference |
| , class OtherDifference |
| > |
| any_iterator(const any_iterator< |
| OtherValue |
| , OtherTraversal |
| , OtherReference |
| , OtherDifference |
| , Buffer |
| >& other, |
| typename enable_if< |
| typename mpl::or_< |
| typename mpl::and_< |
| typename is_mutable_reference<OtherReference>::type, |
| typename is_mutable_reference<Reference>::type |
| >::type, |
| typename mpl::and_< |
| typename is_const_reference<OtherReference>::type, |
| typename is_const_reference<Reference>::type |
| >::type |
| >::type, |
| enabler |
| >::type* = 0 |
| ) |
| : m_impl(other.m_impl |
| ? other.m_impl->clone(m_buffer) |
| : 0 |
| ) |
| { |
| } |
| |
| // Implicit conversion to an any_iterator that uses a value for |
| // the reference type. |
| template< |
| class OtherValue |
| , class OtherTraversal |
| , class OtherReference |
| , class OtherDifference |
| > |
| any_iterator(const any_iterator< |
| OtherValue |
| , OtherTraversal |
| , OtherReference |
| , OtherDifference |
| , Buffer |
| >& other, |
| typename enable_if< |
| typename is_convertible_to_value_as_reference< |
| OtherReference |
| , Reference |
| >::type, |
| enabler |
| >::type* = 0 |
| ) |
| : m_impl(other.m_impl |
| ? other.m_impl->clone_reference_as_value(m_buffer) |
| : 0 |
| ) |
| { |
| } |
| |
| any_iterator clone() const |
| { |
| any_iterator result; |
| if (m_impl) |
| result.m_impl = m_impl->clone(result.m_buffer); |
| return result; |
| } |
| |
| any_iterator< |
| Value |
| , Traversal |
| , typename abstract_base_type::const_reference |
| , Difference |
| , Buffer |
| > |
| clone_const_ref() const |
| { |
| typedef any_iterator< |
| Value |
| , Traversal |
| , typename abstract_base_type::const_reference |
| , Difference |
| , Buffer |
| > result_type; |
| |
| result_type result; |
| |
| if (m_impl) |
| result.m_impl = m_impl->clone_const_ref(result.m_buffer); |
| |
| return result; |
| } |
| |
| // implicit conversion and construction from type-erasure-compatible |
| // iterators |
| template<class WrappedIterator> |
| explicit any_iterator( |
| const WrappedIterator& wrapped_iterator, |
| typename disable_if< |
| typename is_any_iterator<WrappedIterator>::type |
| , disabler |
| >::type* = 0 |
| ) |
| { |
| typedef typename any_iterator_wrapper_type_generator< |
| WrappedIterator |
| , Traversal |
| , Reference |
| , Difference |
| , Buffer |
| >::type wrapper_type; |
| |
| void* ptr = m_buffer.allocate(sizeof(wrapper_type)); |
| m_impl = new(ptr) wrapper_type(wrapped_iterator); |
| } |
| |
| ~any_iterator() |
| { |
| // manually run the destructor, the deallocation is automatically |
| // handled by the any_iterator_small_buffer base class. |
| if (m_impl) |
| m_impl->~abstract_base_type(); |
| } |
| |
| private: |
| friend class ::boost::iterator_core_access; |
| |
| Reference dereference() const |
| { |
| BOOST_ASSERT( m_impl ); |
| return m_impl->dereference(); |
| } |
| |
| bool equal(const any_iterator& other) const |
| { |
| return (m_impl == other.m_impl) |
| || (m_impl && other.m_impl && m_impl->equal(*other.m_impl)); |
| } |
| |
| void increment() |
| { |
| BOOST_ASSERT( m_impl ); |
| m_impl->increment(); |
| } |
| |
| void decrement() |
| { |
| BOOST_ASSERT( m_impl ); |
| m_impl->decrement(); |
| } |
| |
| Difference distance_to(const any_iterator& other) const |
| { |
| return m_impl && other.m_impl |
| ? m_impl->distance_to(*other.m_impl) |
| : 0; |
| } |
| |
| void advance(Difference offset) |
| { |
| BOOST_ASSERT( m_impl ); |
| m_impl->advance(offset); |
| } |
| |
| any_iterator& swap(any_iterator& other) |
| { |
| BOOST_ASSERT( this != &other ); |
| // grab a temporary copy of the other iterator |
| any_iterator tmp(other); |
| |
| // deallocate the other iterator, taking care to obey the |
| // class-invariants in-case of exceptions later |
| if (other.m_impl) |
| { |
| other.m_impl->~abstract_base_type(); |
| other.m_buffer.deallocate(); |
| other.m_impl = 0; |
| } |
| |
| // If this is a non-null iterator then we need to put |
| // a clone of this iterators impementation into the other |
| // iterator. |
| // We can't just swap because of the small buffer optimization. |
| if (m_impl) |
| { |
| other.m_impl = m_impl->clone(other.m_buffer); |
| m_impl->~abstract_base_type(); |
| m_buffer.deallocate(); |
| m_impl = 0; |
| } |
| |
| // assign to this instance a clone of the temporarily held |
| // tmp which represents the input other parameter at the |
| // start of execution of this function. |
| if (tmp.m_impl) |
| m_impl = tmp.m_impl->clone(m_buffer); |
| |
| return *this; |
| } |
| |
| buffer_type m_buffer; |
| abstract_base_type* m_impl; |
| }; |
| |
| } // namespace range_detail |
| } // namespace boost |
| |
| #endif // include guard |