You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
587 lines
19 KiB
587 lines
19 KiB
// 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
|
|
|