williamr@2: // (C) Copyright David Abrahams 2002. williamr@2: // (C) Copyright Jeremy Siek 2002. williamr@2: // (C) Copyright Thomas Witt 2002. williamr@2: // Distributed under the Boost Software License, Version 1.0. (See williamr@2: // accompanying file LICENSE_1_0.txt or copy at williamr@2: // http://www.boost.org/LICENSE_1_0.txt) williamr@2: #ifndef BOOST_ITERATOR_FACADE_23022003THW_HPP williamr@2: #define BOOST_ITERATOR_FACADE_23022003THW_HPP williamr@2: williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: williamr@2: #include williamr@2: #include williamr@2: williamr@2: #include williamr@2: #include williamr@2: williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: #include williamr@2: williamr@2: #include // this goes last williamr@2: williamr@2: namespace boost williamr@2: { williamr@2: // This forward declaration is required for the friend declaration williamr@2: // in iterator_core_access williamr@2: template class iterator_facade; williamr@2: williamr@2: namespace detail williamr@2: { williamr@2: // A binary metafunction class that always returns bool. VC6 williamr@2: // ICEs on mpl::always, probably because of the default williamr@2: // parameters. williamr@2: struct always_bool2 williamr@2: { williamr@2: template williamr@2: struct apply williamr@2: { williamr@2: typedef bool type; williamr@2: }; williamr@2: }; williamr@2: williamr@2: // williamr@2: // enable if for use in operator implementation. williamr@2: // williamr@2: template < williamr@2: class Facade1 williamr@2: , class Facade2 williamr@2: , class Return williamr@2: > williamr@2: struct enable_if_interoperable williamr@2: #if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) williamr@2: { williamr@2: typedef typename mpl::if_< williamr@2: mpl::or_< williamr@2: is_convertible williamr@2: , is_convertible williamr@2: > williamr@2: , Return williamr@2: , int[3] williamr@2: >::type type; williamr@2: }; williamr@2: #else williamr@2: : ::boost::iterators::enable_if< williamr@2: mpl::or_< williamr@2: is_convertible williamr@2: , is_convertible williamr@2: > williamr@2: , Return williamr@2: > williamr@2: {}; williamr@2: #endif williamr@2: williamr@2: // williamr@2: // Generates associated types for an iterator_facade with the williamr@2: // given parameters. williamr@2: // williamr@2: template < williamr@2: class ValueParam williamr@2: , class CategoryOrTraversal williamr@2: , class Reference williamr@2: , class Difference williamr@2: > williamr@2: struct iterator_facade_types williamr@2: { williamr@2: typedef typename facade_iterator_category< williamr@2: CategoryOrTraversal, ValueParam, Reference williamr@2: >::type iterator_category; williamr@2: williamr@2: typedef typename remove_const::type value_type; williamr@2: williamr@2: typedef typename mpl::eval_if< williamr@2: detail::iterator_writability_disabled williamr@2: , add_pointer williamr@2: , add_pointer williamr@2: >::type pointer; williamr@2: williamr@2: # if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) \ williamr@2: && (BOOST_WORKAROUND(_STLPORT_VERSION, BOOST_TESTED_AT(0x452)) \ williamr@2: || BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, BOOST_TESTED_AT(310))) \ williamr@2: || BOOST_WORKAROUND(BOOST_RWSTD_VER, BOOST_TESTED_AT(0x20101)) \ williamr@2: || BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, <= 310) williamr@2: williamr@2: // To interoperate with some broken library/compiler williamr@2: // combinations, user-defined iterators must be derived from williamr@2: // std::iterator. It is possible to implement a standard williamr@2: // library for broken compilers without this limitation. williamr@2: # define BOOST_ITERATOR_FACADE_NEEDS_ITERATOR_BASE 1 williamr@2: williamr@2: typedef williamr@2: iterator williamr@2: base; williamr@2: # endif williamr@2: }; williamr@2: williamr@2: // iterators whose dereference operators reference the same value williamr@2: // for all iterators into the same sequence (like many input williamr@2: // iterators) need help with their postfix ++: the referenced williamr@2: // value must be read and stored away before the increment occurs williamr@2: // so that *a++ yields the originally referenced element and not williamr@2: // the next one. williamr@2: template williamr@2: class postfix_increment_proxy williamr@2: { williamr@2: typedef typename iterator_value::type value_type; williamr@2: public: williamr@2: explicit postfix_increment_proxy(Iterator const& x) williamr@2: : stored_value(*x) williamr@2: {} williamr@2: williamr@2: // Returning a mutable reference allows nonsense like williamr@2: // (*r++).mutate(), but it imposes fewer assumptions about the williamr@2: // behavior of the value_type. In particular, recall taht williamr@2: // (*r).mutate() is legal if operator* returns by value. williamr@2: value_type& williamr@2: operator*() const williamr@2: { williamr@2: return this->stored_value; williamr@2: } williamr@2: private: williamr@2: mutable value_type stored_value; williamr@2: }; williamr@2: williamr@2: // williamr@2: // In general, we can't determine that such an iterator isn't williamr@2: // writable -- we also need to store a copy of the old iterator so williamr@2: // that it can be written into. williamr@2: template williamr@2: class writable_postfix_increment_proxy williamr@2: { williamr@2: typedef typename iterator_value::type value_type; williamr@2: public: williamr@2: explicit writable_postfix_increment_proxy(Iterator const& x) williamr@2: : stored_value(*x) williamr@2: , stored_iterator(x) williamr@2: {} williamr@2: williamr@2: // Dereferencing must return a proxy so that both *r++ = o and williamr@2: // value_type(*r++) can work. In this case, *r is the same as williamr@2: // *r++, and the conversion operator below is used to ensure williamr@2: // readability. williamr@2: writable_postfix_increment_proxy const& williamr@2: operator*() const williamr@2: { williamr@2: return *this; williamr@2: } williamr@2: williamr@2: // Provides readability of *r++ williamr@2: operator value_type&() const williamr@2: { williamr@2: return stored_value; williamr@2: } williamr@2: williamr@2: // Provides writability of *r++ williamr@2: template williamr@2: T const& operator=(T const& x) const williamr@2: { williamr@2: *this->stored_iterator = x; williamr@2: return x; williamr@2: } williamr@2: williamr@2: // This overload just in case only non-const objects are writable williamr@2: template williamr@2: T& operator=(T& x) const williamr@2: { williamr@2: *this->stored_iterator = x; williamr@2: return x; williamr@2: } williamr@2: williamr@2: // Provides X(r++) williamr@2: operator Iterator const&() const williamr@2: { williamr@2: return stored_iterator; williamr@2: } williamr@2: williamr@2: private: williamr@2: mutable value_type stored_value; williamr@2: Iterator stored_iterator; williamr@2: }; williamr@2: williamr@2: # ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION williamr@2: williamr@2: template williamr@2: struct is_non_proxy_reference_impl williamr@2: { williamr@2: static Reference r; williamr@2: williamr@2: template williamr@2: static typename mpl::if_< williamr@2: is_convertible< williamr@2: R const volatile* williamr@2: , Value const volatile* williamr@2: > williamr@2: , char[1] williamr@2: , char[2] williamr@2: >::type& helper(R const&); williamr@2: williamr@2: BOOST_STATIC_CONSTANT(bool, value = sizeof(helper(r)) == 1); williamr@2: }; williamr@2: williamr@2: template williamr@2: struct is_non_proxy_reference williamr@2: : mpl::bool_< williamr@2: is_non_proxy_reference_impl::value williamr@2: > williamr@2: {}; williamr@2: # else williamr@2: template williamr@2: struct is_non_proxy_reference williamr@2: : is_convertible< williamr@2: typename remove_reference::type williamr@2: const volatile* williamr@2: , Value const volatile* williamr@2: > williamr@2: {}; williamr@2: # endif williamr@2: williamr@2: // A metafunction to choose the result type of postfix ++ williamr@2: // williamr@2: // Because the C++98 input iterator requirements say that *r++ has williamr@2: // type T (value_type), implementations of some standard williamr@2: // algorithms like lexicographical_compare may use constructions williamr@2: // like: williamr@2: // williamr@2: // *r++ < *s++ williamr@2: // williamr@2: // If *r++ returns a proxy (as required if r is writable but not williamr@2: // multipass), this sort of expression will fail unless the proxy williamr@2: // supports the operator<. Since there are any number of such williamr@2: // operations, we're not going to try to support them. Therefore, williamr@2: // even if r++ returns a proxy, *r++ will only return a proxy if williamr@2: // *r also returns a proxy. williamr@2: template williamr@2: struct postfix_increment_result williamr@2: : mpl::eval_if< williamr@2: mpl::and_< williamr@2: // A proxy is only needed for readable iterators williamr@2: is_convertible williamr@2: williamr@2: // No multipass iterator can have values that disappear williamr@2: // before positions can be re-visited williamr@2: , mpl::not_< williamr@2: is_convertible< williamr@2: typename iterator_category_to_traversal::type williamr@2: , forward_traversal_tag williamr@2: > williamr@2: > williamr@2: > williamr@2: , mpl::if_< williamr@2: is_non_proxy_reference williamr@2: , postfix_increment_proxy williamr@2: , writable_postfix_increment_proxy williamr@2: > williamr@2: , mpl::identity williamr@2: > williamr@2: {}; williamr@2: williamr@2: // operator->() needs special support for input iterators to strictly meet the williamr@2: // standard's requirements. If *i is not a reference type, we must still williamr@2: // produce a lvalue to which a pointer can be formed. We do that by williamr@2: // returning an instantiation of this special proxy class template. williamr@2: template williamr@2: struct operator_arrow_proxy williamr@2: { williamr@2: operator_arrow_proxy(T const* px) : m_value(*px) {} williamr@2: T* operator->() const { return &m_value; } williamr@2: // This function is needed for MWCW and BCC, which won't call operator-> williamr@2: // again automatically per 13.3.1.2 para 8 williamr@2: operator T*() const { return &m_value; } williamr@2: mutable T m_value; williamr@2: }; williamr@2: williamr@2: // A metafunction that gets the result type for operator->. Also williamr@2: // has a static function make() which builds the result from a williamr@2: // Reference williamr@2: template williamr@2: struct operator_arrow_result williamr@2: { williamr@2: // CWPro8.3 won't accept "operator_arrow_result::type", and we williamr@2: // need that type below, so metafunction forwarding would be a williamr@2: // losing proposition here. williamr@2: typedef typename mpl::if_< williamr@2: is_reference williamr@2: , Pointer williamr@2: , operator_arrow_proxy williamr@2: >::type type; williamr@2: williamr@2: static type make(Reference x) williamr@2: { williamr@2: return implicit_cast(&x); williamr@2: } williamr@2: }; williamr@2: williamr@2: # if BOOST_WORKAROUND(BOOST_MSVC, < 1300) williamr@2: // Deal with ETI williamr@2: template<> williamr@2: struct operator_arrow_result williamr@2: { williamr@2: typedef int type; williamr@2: }; williamr@2: # endif williamr@2: williamr@2: // A proxy return type for operator[], needed to deal with williamr@2: // iterators that may invalidate referents upon destruction. williamr@2: // Consider the temporary iterator in *(a + n) williamr@2: template williamr@2: class operator_brackets_proxy williamr@2: { williamr@2: // Iterator is actually an iterator_facade, so we do not have to williamr@2: // go through iterator_traits to access the traits. williamr@2: typedef typename Iterator::reference reference; williamr@2: typedef typename Iterator::value_type value_type; williamr@2: williamr@2: public: williamr@2: operator_brackets_proxy(Iterator const& iter) williamr@2: : m_iter(iter) williamr@2: {} williamr@2: williamr@2: operator reference() const williamr@2: { williamr@2: return *m_iter; williamr@2: } williamr@2: williamr@2: operator_brackets_proxy& operator=(value_type const& val) williamr@2: { williamr@2: *m_iter = val; williamr@2: return *this; williamr@2: } williamr@2: williamr@2: private: williamr@2: Iterator m_iter; williamr@2: }; williamr@2: williamr@2: // A metafunction that determines whether operator[] must return a williamr@2: // proxy, or whether it can simply return a copy of the value_type. williamr@2: template williamr@2: struct use_operator_brackets_proxy williamr@2: : mpl::not_< williamr@2: mpl::and_< williamr@2: // Really we want an is_copy_constructible trait here, williamr@2: // but is_POD will have to suffice in the meantime. williamr@2: boost::is_POD williamr@2: , iterator_writability_disabled williamr@2: > williamr@2: > williamr@2: {}; williamr@2: williamr@2: template williamr@2: struct operator_brackets_result williamr@2: { williamr@2: typedef typename mpl::if_< williamr@2: use_operator_brackets_proxy williamr@2: , operator_brackets_proxy williamr@2: , Value williamr@2: >::type type; williamr@2: }; williamr@2: williamr@2: template williamr@2: operator_brackets_proxy make_operator_brackets_result(Iterator const& iter, mpl::true_) williamr@2: { williamr@2: return operator_brackets_proxy(iter); williamr@2: } williamr@2: williamr@2: template williamr@2: typename Iterator::value_type make_operator_brackets_result(Iterator const& iter, mpl::false_) williamr@2: { williamr@2: return *iter; williamr@2: } williamr@2: williamr@2: struct choose_difference_type williamr@2: { williamr@2: template williamr@2: struct apply williamr@2: : williamr@2: # ifdef BOOST_NO_ONE_WAY_ITERATOR_INTEROP williamr@2: iterator_difference williamr@2: # elif BOOST_WORKAROUND(BOOST_MSVC, < 1300) williamr@2: mpl::if_< williamr@2: is_convertible williamr@2: , typename I1::difference_type williamr@2: , typename I2::difference_type williamr@2: > williamr@2: # else williamr@2: mpl::eval_if< williamr@2: is_convertible williamr@2: , iterator_difference williamr@2: , iterator_difference williamr@2: > williamr@2: # endif williamr@2: {}; williamr@2: williamr@2: }; williamr@2: } // namespace detail williamr@2: williamr@2: williamr@2: // Macros which describe the declarations of binary operators williamr@2: # ifdef BOOST_NO_STRICT_ITERATOR_INTEROPERABILITY williamr@2: # define BOOST_ITERATOR_FACADE_INTEROP_HEAD(prefix, op, result_type) \ williamr@2: template < \ williamr@2: class Derived1, class V1, class TC1, class R1, class D1 \ williamr@2: , class Derived2, class V2, class TC2, class R2, class D2 \ williamr@2: > \ williamr@2: prefix typename mpl::apply2::type \ williamr@2: operator op( \ williamr@2: iterator_facade const& lhs \ williamr@2: , iterator_facade const& rhs) williamr@2: # else williamr@2: # define BOOST_ITERATOR_FACADE_INTEROP_HEAD(prefix, op, result_type) \ williamr@2: template < \ williamr@2: class Derived1, class V1, class TC1, class R1, class D1 \ williamr@2: , class Derived2, class V2, class TC2, class R2, class D2 \ williamr@2: > \ williamr@2: prefix typename detail::enable_if_interoperable< \ williamr@2: Derived1, Derived2 \ williamr@2: , typename mpl::apply2::type \ williamr@2: >::type \ williamr@2: operator op( \ williamr@2: iterator_facade const& lhs \ williamr@2: , iterator_facade const& rhs) williamr@2: # endif williamr@2: williamr@2: # define BOOST_ITERATOR_FACADE_PLUS_HEAD(prefix,args) \ williamr@2: template \ williamr@2: prefix Derived operator+ args williamr@2: williamr@2: // williamr@2: // Helper class for granting access to the iterator core interface. williamr@2: // williamr@2: // The simple core interface is used by iterator_facade. The core williamr@2: // interface of a user/library defined iterator type should not be made public williamr@2: // so that it does not clutter the public interface. Instead iterator_core_access williamr@2: // should be made friend so that iterator_facade can access the core williamr@2: // interface through iterator_core_access. williamr@2: // williamr@2: class iterator_core_access williamr@2: { williamr@2: # if defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) \ williamr@2: || BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x551)) williamr@2: // Tasteless as this may seem, making all members public allows member templates williamr@2: // to work in the absence of member template friends. williamr@2: public: williamr@2: # else williamr@2: williamr@2: template friend class iterator_facade; williamr@2: williamr@2: # define BOOST_ITERATOR_FACADE_RELATION(op) \ williamr@2: BOOST_ITERATOR_FACADE_INTEROP_HEAD(friend,op, detail::always_bool2); williamr@2: williamr@2: BOOST_ITERATOR_FACADE_RELATION(==) williamr@2: BOOST_ITERATOR_FACADE_RELATION(!=) williamr@2: williamr@2: BOOST_ITERATOR_FACADE_RELATION(<) williamr@2: BOOST_ITERATOR_FACADE_RELATION(>) williamr@2: BOOST_ITERATOR_FACADE_RELATION(<=) williamr@2: BOOST_ITERATOR_FACADE_RELATION(>=) williamr@2: # undef BOOST_ITERATOR_FACADE_RELATION williamr@2: williamr@2: BOOST_ITERATOR_FACADE_INTEROP_HEAD( williamr@2: friend, -, detail::choose_difference_type) williamr@2: ; williamr@2: williamr@2: BOOST_ITERATOR_FACADE_PLUS_HEAD( williamr@2: friend inline williamr@2: , (iterator_facade const& williamr@2: , typename Derived::difference_type) williamr@2: ) williamr@2: ; williamr@2: williamr@2: BOOST_ITERATOR_FACADE_PLUS_HEAD( williamr@2: friend inline williamr@2: , (typename Derived::difference_type williamr@2: , iterator_facade const&) williamr@2: ) williamr@2: ; williamr@2: williamr@2: # endif williamr@2: williamr@2: template williamr@2: static typename Facade::reference dereference(Facade const& f) williamr@2: { williamr@2: return f.dereference(); williamr@2: } williamr@2: williamr@2: template williamr@2: static void increment(Facade& f) williamr@2: { williamr@2: f.increment(); williamr@2: } williamr@2: williamr@2: template williamr@2: static void decrement(Facade& f) williamr@2: { williamr@2: f.decrement(); williamr@2: } williamr@2: williamr@2: template williamr@2: static bool equal(Facade1 const& f1, Facade2 const& f2, mpl::true_) williamr@2: { williamr@2: return f1.equal(f2); williamr@2: } williamr@2: williamr@2: template williamr@2: static bool equal(Facade1 const& f1, Facade2 const& f2, mpl::false_) williamr@2: { williamr@2: return f2.equal(f1); williamr@2: } williamr@2: williamr@2: template williamr@2: static void advance(Facade& f, typename Facade::difference_type n) williamr@2: { williamr@2: f.advance(n); williamr@2: } williamr@2: williamr@2: template williamr@2: static typename Facade1::difference_type distance_from( williamr@2: Facade1 const& f1, Facade2 const& f2, mpl::true_) williamr@2: { williamr@2: return -f1.distance_to(f2); williamr@2: } williamr@2: williamr@2: template williamr@2: static typename Facade2::difference_type distance_from( williamr@2: Facade1 const& f1, Facade2 const& f2, mpl::false_) williamr@2: { williamr@2: return f2.distance_to(f1); williamr@2: } williamr@2: williamr@2: // williamr@2: // Curiously Recurring Template interface. williamr@2: // williamr@2: template williamr@2: static I& derived(iterator_facade& facade) williamr@2: { williamr@2: return *static_cast(&facade); williamr@2: } williamr@2: williamr@2: template williamr@2: static I const& derived(iterator_facade const& facade) williamr@2: { williamr@2: return *static_cast(&facade); williamr@2: } williamr@2: williamr@2: private: williamr@2: // objects of this class are useless williamr@2: iterator_core_access(); //undefined williamr@2: }; williamr@2: williamr@2: // williamr@2: // iterator_facade - use as a public base class for defining new williamr@2: // standard-conforming iterators. williamr@2: // williamr@2: template < williamr@2: class Derived // The derived iterator type being constructed williamr@2: , class Value williamr@2: , class CategoryOrTraversal williamr@2: , class Reference = Value& williamr@2: , class Difference = std::ptrdiff_t williamr@2: > williamr@2: class iterator_facade williamr@2: # ifdef BOOST_ITERATOR_FACADE_NEEDS_ITERATOR_BASE williamr@2: : public detail::iterator_facade_types< williamr@2: Value, CategoryOrTraversal, Reference, Difference williamr@2: >::base williamr@2: # undef BOOST_ITERATOR_FACADE_NEEDS_ITERATOR_BASE williamr@2: # endif williamr@2: { williamr@2: private: williamr@2: // williamr@2: // Curiously Recurring Template interface. williamr@2: // williamr@2: Derived& derived() williamr@2: { williamr@2: return *static_cast(this); williamr@2: } williamr@2: williamr@2: Derived const& derived() const williamr@2: { williamr@2: return *static_cast(this); williamr@2: } williamr@2: williamr@2: typedef detail::iterator_facade_types< williamr@2: Value, CategoryOrTraversal, Reference, Difference williamr@2: > associated_types; williamr@2: williamr@2: protected: williamr@2: // For use by derived classes williamr@2: typedef iterator_facade iterator_facade_; williamr@2: williamr@2: public: williamr@2: williamr@2: typedef typename associated_types::value_type value_type; williamr@2: typedef Reference reference; williamr@2: typedef Difference difference_type; williamr@2: typedef typename associated_types::pointer pointer; williamr@2: typedef typename associated_types::iterator_category iterator_category; williamr@2: williamr@2: reference operator*() const williamr@2: { williamr@2: return iterator_core_access::dereference(this->derived()); williamr@2: } williamr@2: williamr@2: typename detail::operator_arrow_result< williamr@2: value_type williamr@2: , reference williamr@2: , pointer williamr@2: >::type williamr@2: operator->() const williamr@2: { williamr@2: return detail::operator_arrow_result< williamr@2: value_type williamr@2: , reference williamr@2: , pointer williamr@2: >::make(*this->derived()); williamr@2: } williamr@2: williamr@2: typename detail::operator_brackets_result::type williamr@2: operator[](difference_type n) const williamr@2: { williamr@2: typedef detail::use_operator_brackets_proxy use_proxy; williamr@2: williamr@2: return detail::make_operator_brackets_result( williamr@2: this->derived() + n williamr@2: , use_proxy() williamr@2: ); williamr@2: } williamr@2: williamr@2: Derived& operator++() williamr@2: { williamr@2: iterator_core_access::increment(this->derived()); williamr@2: return this->derived(); williamr@2: } williamr@2: williamr@2: # if BOOST_WORKAROUND(BOOST_MSVC, < 1300) williamr@2: typename detail::postfix_increment_result::type williamr@2: operator++(int) williamr@2: { williamr@2: typename detail::postfix_increment_result::type williamr@2: tmp(this->derived()); williamr@2: ++*this; williamr@2: return tmp; williamr@2: } williamr@2: # endif williamr@2: williamr@2: Derived& operator--() williamr@2: { williamr@2: iterator_core_access::decrement(this->derived()); williamr@2: return this->derived(); williamr@2: } williamr@2: williamr@2: Derived operator--(int) williamr@2: { williamr@2: Derived tmp(this->derived()); williamr@2: --*this; williamr@2: return tmp; williamr@2: } williamr@2: williamr@2: Derived& operator+=(difference_type n) williamr@2: { williamr@2: iterator_core_access::advance(this->derived(), n); williamr@2: return this->derived(); williamr@2: } williamr@2: williamr@2: Derived& operator-=(difference_type n) williamr@2: { williamr@2: iterator_core_access::advance(this->derived(), -n); williamr@2: return this->derived(); williamr@2: } williamr@2: williamr@2: Derived operator-(difference_type x) const williamr@2: { williamr@2: Derived result(this->derived()); williamr@2: return result -= x; williamr@2: } williamr@2: williamr@2: # if BOOST_WORKAROUND(BOOST_MSVC, < 1300) williamr@2: // There appears to be a bug which trashes the data of classes williamr@2: // derived from iterator_facade when they are assigned unless we williamr@2: // define this assignment operator. This bug is only revealed williamr@2: // (so far) in STLPort debug mode, but it's clearly a codegen williamr@2: // problem so we apply the workaround for all MSVC6. williamr@2: iterator_facade& operator=(iterator_facade const&) williamr@2: { williamr@2: return *this; williamr@2: } williamr@2: # endif williamr@2: }; williamr@2: williamr@2: # if !BOOST_WORKAROUND(BOOST_MSVC, < 1300) williamr@2: template williamr@2: inline typename detail::postfix_increment_result::type williamr@2: operator++( williamr@2: iterator_facade& i williamr@2: , int williamr@2: ) williamr@2: { williamr@2: typename detail::postfix_increment_result::type williamr@2: tmp(*static_cast(&i)); williamr@2: williamr@2: ++i; williamr@2: williamr@2: return tmp; williamr@2: } williamr@2: # endif williamr@2: williamr@2: williamr@2: // williamr@2: // Comparison operator implementation. The library supplied operators williamr@2: // enables the user to provide fully interoperable constant/mutable williamr@2: // iterator types. I.e. the library provides all operators williamr@2: // for all mutable/constant iterator combinations. williamr@2: // williamr@2: // Note though that this kind of interoperability for constant/mutable williamr@2: // iterators is not required by the standard for container iterators. williamr@2: // All the standard asks for is a conversion mutable -> constant. williamr@2: // Most standard library implementations nowadays provide fully interoperable williamr@2: // iterator implementations, but there are still heavily used implementations williamr@2: // that do not provide them. (Actually it's even worse, they do not provide williamr@2: // them for only a few iterators.) williamr@2: // williamr@2: // ?? Maybe a BOOST_ITERATOR_NO_FULL_INTEROPERABILITY macro should williamr@2: // enable the user to turn off mixed type operators williamr@2: // williamr@2: // The library takes care to provide only the right operator overloads. williamr@2: // I.e. williamr@2: // williamr@2: // bool operator==(Iterator, Iterator); williamr@2: // bool operator==(ConstIterator, Iterator); williamr@2: // bool operator==(Iterator, ConstIterator); williamr@2: // bool operator==(ConstIterator, ConstIterator); williamr@2: // williamr@2: // ... williamr@2: // williamr@2: // In order to do so it uses c++ idioms that are not yet widely supported williamr@2: // by current compiler releases. The library is designed to degrade gracefully williamr@2: // in the face of compiler deficiencies. In general compiler williamr@2: // deficiencies result in less strict error checking and more obscure williamr@2: // error messages, functionality is not affected. williamr@2: // williamr@2: // For full operation compiler support for "Substitution Failure Is Not An Error" williamr@2: // (aka. enable_if) and boost::is_convertible is required. williamr@2: // williamr@2: // The following problems occur if support is lacking. williamr@2: // williamr@2: // Pseudo code williamr@2: // williamr@2: // --------------- williamr@2: // AdaptorA a1; williamr@2: // AdaptorA a2; williamr@2: // williamr@2: // // This will result in a no such overload error in full operation williamr@2: // // If enable_if or is_convertible is not supported williamr@2: // // The instantiation will fail with an error hopefully indicating that williamr@2: // // there is no operator== for Iterator1, Iterator2 williamr@2: // // The same will happen if no enable_if is used to remove williamr@2: // // false overloads from the templated conversion constructor williamr@2: // // of AdaptorA. williamr@2: // williamr@2: // a1 == a2; williamr@2: // ---------------- williamr@2: // williamr@2: // AdaptorA a; williamr@2: // AdaptorB b; williamr@2: // williamr@2: // // This will result in a no such overload error in full operation williamr@2: // // If enable_if is not supported the static assert used williamr@2: // // in the operator implementation will fail. williamr@2: // // This will accidently work if is_convertible is not supported. williamr@2: // williamr@2: // a == b; williamr@2: // ---------------- williamr@2: // williamr@2: williamr@2: # ifdef BOOST_NO_ONE_WAY_ITERATOR_INTEROP williamr@2: # define BOOST_ITERATOR_CONVERTIBLE(a,b) mpl::true_() williamr@2: # else williamr@2: # define BOOST_ITERATOR_CONVERTIBLE(a,b) is_convertible() williamr@2: # endif williamr@2: williamr@2: # define BOOST_ITERATOR_FACADE_INTEROP(op, result_type, return_prefix, base_op) \ williamr@2: BOOST_ITERATOR_FACADE_INTEROP_HEAD(inline, op, result_type) \ williamr@2: { \ williamr@2: /* For those compilers that do not support enable_if */ \ williamr@2: BOOST_STATIC_ASSERT(( \ williamr@2: is_interoperable< Derived1, Derived2 >::value \ williamr@2: )); \ williamr@2: return_prefix iterator_core_access::base_op( \ williamr@2: *static_cast(&lhs) \ williamr@2: , *static_cast(&rhs) \ williamr@2: , BOOST_ITERATOR_CONVERTIBLE(Derived2,Derived1) \ williamr@2: ); \ williamr@2: } williamr@2: williamr@2: # define BOOST_ITERATOR_FACADE_RELATION(op, return_prefix, base_op) \ williamr@2: BOOST_ITERATOR_FACADE_INTEROP( \ williamr@2: op \ williamr@2: , detail::always_bool2 \ williamr@2: , return_prefix \ williamr@2: , base_op \ williamr@2: ) williamr@2: williamr@2: BOOST_ITERATOR_FACADE_RELATION(==, return, equal) williamr@2: BOOST_ITERATOR_FACADE_RELATION(!=, return !, equal) williamr@2: williamr@2: BOOST_ITERATOR_FACADE_RELATION(<, return 0 >, distance_from) williamr@2: BOOST_ITERATOR_FACADE_RELATION(>, return 0 <, distance_from) williamr@2: BOOST_ITERATOR_FACADE_RELATION(<=, return 0 >=, distance_from) williamr@2: BOOST_ITERATOR_FACADE_RELATION(>=, return 0 <=, distance_from) williamr@2: # undef BOOST_ITERATOR_FACADE_RELATION williamr@2: williamr@2: // operator- requires an additional part in the static assertion williamr@2: BOOST_ITERATOR_FACADE_INTEROP( williamr@2: - williamr@2: , detail::choose_difference_type williamr@2: , return williamr@2: , distance_from williamr@2: ) williamr@2: # undef BOOST_ITERATOR_FACADE_INTEROP williamr@2: # undef BOOST_ITERATOR_FACADE_INTEROP_HEAD williamr@2: williamr@2: # define BOOST_ITERATOR_FACADE_PLUS(args) \ williamr@2: BOOST_ITERATOR_FACADE_PLUS_HEAD(inline, args) \ williamr@2: { \ williamr@2: Derived tmp(static_cast(i)); \ williamr@2: return tmp += n; \ williamr@2: } williamr@2: williamr@2: BOOST_ITERATOR_FACADE_PLUS(( williamr@2: iterator_facade const& i williamr@2: , typename Derived::difference_type n williamr@2: )) williamr@2: williamr@2: BOOST_ITERATOR_FACADE_PLUS(( williamr@2: typename Derived::difference_type n williamr@2: , iterator_facade const& i williamr@2: )) williamr@2: # undef BOOST_ITERATOR_FACADE_PLUS williamr@2: # undef BOOST_ITERATOR_FACADE_PLUS_HEAD williamr@2: williamr@2: } // namespace boost williamr@2: williamr@2: #include williamr@2: williamr@2: #endif // BOOST_ITERATOR_FACADE_23022003THW_HPP