// 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 |