merged from trunk

[SVN r21580]
This commit is contained in:
Dave Abrahams
2004-01-11 00:35:03 +00:00
parent f1d694c2d6
commit 6379561eb0
6 changed files with 89 additions and 55 deletions

View File

@ -46,14 +46,15 @@ objects for several reasons:
Usage Usage
----- -----
The user of ``iterator_facade`` derives his iterator class from an The user of ``iterator_facade`` derives his iterator class from a
specialization of ``iterator_facade`` which takes the derived iterator specialization of ``iterator_facade`` and passes the derived
class as the first template parameter. The order of the other iterator class as ``iterator_facade``\ 's first template parameter.
template parameters to ``iterator_facade`` have been carefully chosen The order of the other template parameters have been carefully
to take advantage of useful defaults. For example, when defining a chosen to take advantage of useful defaults. For example, when
constant lvalue iterator, the user can pass a const-qualified version defining a constant lvalue iterator, the user can pass a
of the iterator's ``value_type`` as ``iterator_facade``\ 's ``Value`` const-qualified version of the iterator's ``value_type`` as
parameter and omit the ``Reference`` parameter which follows. ``iterator_facade``\ 's ``Value`` parameter and omit the
``Reference`` parameter which follows.
The derived iterator class must define member functions implementing The derived iterator class must define member functions implementing
the iterator's core behaviors. The following table describes the iterator's core behaviors. The following table describes
@ -150,14 +151,16 @@ into the temporary iterator ``p+n``, which is destroyed when
Writable iterators built with ``iterator_facade`` implement the Writable iterators built with ``iterator_facade`` implement the
semantics required by the preferred resolution to `issue 299`_ and semantics required by the preferred resolution to `issue 299`_ and
adopted by proposal n1550_: the result of ``p[n]`` is a proxy object adopted by proposal n1550_: the result of ``p[n]`` is an object
containing a copy of ``p+n``, and ``p[n] = x`` is equivalent to ``*(p convertible to the iterator's ``value_type``, and ``p[n] = x`` is
+ n) = x``. This approach will work properly for any random-access equivalent to ``*(p + n) = x`` (Note: This result object may be
iterator regardless of the other details of its implementation. A implemented as a proxy containing a copy of ``p+n``). This approach
user who knows more about the implementation of her iterator is free will work properly for any random-access iterator regardless of the
to implement an ``operator[]`` which returns an lvalue in the derived other details of its implementation. A user who knows more about
iterator class; it will hide the one supplied by ``iterator_facade`` the implementation of her iterator is free to implement an
from clients of her iterator. ``operator[]`` that returns an lvalue in the derived iterator
class; it will hide the one supplied by ``iterator_facade`` from
clients of her iterator.
.. _n1550: http://anubis.dkuug.dk/JTC1/SC22/WG21/docs/papers/2003/n1550.html .. _n1550: http://anubis.dkuug.dk/JTC1/SC22/WG21/docs/papers/2003/n1550.html

View File

@ -245,10 +245,13 @@ __ `operator arrow`_
*unspecified* ``operator[](difference_type n) const;`` *unspecified* ``operator[](difference_type n) const;``
:Returns: an object convertible to ``reference`` and holding a copy :Returns: an object convertible to ``value_type``. For constant
*p* of ``*static_cast<Derived const*>(this) + n`` such that, for a constant object ``v`` of type objects ``v`` of type ``value_type``, and ``n`` of type
``value_type``, ``(*static_cast<Derived const*>(this))[n] = v`` is equivalent ``difference_type``, and reference ``p`` equal to
to ``p = v``. ``*static_cast<Derived const*>(this)``, ``(*this)[n] = v`` is
equivalent to ``*(p+ n) = v``, and ``static_cast<value_type
const&>((*this)[n])`` is equivalent to
``static_cast<value_type const&>(*(p+n))``

View File

@ -22,9 +22,11 @@
#include <boost/type_traits/add_pointer.hpp> #include <boost/type_traits/add_pointer.hpp>
#include <boost/type_traits/remove_const.hpp> #include <boost/type_traits/remove_const.hpp>
#include <boost/type_traits/is_convertible.hpp> #include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/is_POD.hpp>
#include <boost/mpl/apply_if.hpp> #include <boost/mpl/apply_if.hpp>
#include <boost/mpl/or.hpp> #include <boost/mpl/or.hpp>
#include <boost/mpl/and.hpp>
#include <boost/iterator/detail/config_def.hpp> // this goes last #include <boost/iterator/detail/config_def.hpp> // this goes last
@ -182,11 +184,21 @@ namespace boost
Iterator m_iter; Iterator m_iter;
}; };
template <class Value, class Reference>
struct use_operator_brackets_proxy
: mpl::and_<
// Really we want an is_copy_constructible trait here,
// but is_POD will have to suffice in the meantime.
boost::is_POD<Value>
, iterator_writability_disabled<Value,Reference>
>
{};
template <class Iterator, class Value, class Reference> template <class Iterator, class Value, class Reference>
struct operator_brackets_result struct operator_brackets_result
{ {
typedef typename mpl::if_< typedef typename mpl::if_<
iterator_writability_disabled<Value,Reference> use_operator_brackets_proxy<Value,Reference>
, Value , Value
, operator_brackets_proxy<Iterator> , operator_brackets_proxy<Iterator>
>::type type; >::type type;
@ -387,12 +399,11 @@ namespace boost
typename detail::operator_brackets_result<Derived,Value,Reference>::type typename detail::operator_brackets_result<Derived,Value,Reference>::type
operator[](difference_type n) const operator[](difference_type n) const
{ {
typedef detail::iterator_writability_disabled<Value,Reference> typedef detail::use_operator_brackets_proxy<Value,Reference> use_proxy;
not_writable;
return detail::make_operator_brackets_result<Derived>( return detail::make_operator_brackets_result<Derived>(
this->derived() + n this->derived() + n
, not_writable() , use_proxy()
); );
} }

View File

@ -9,7 +9,9 @@
# include <boost/detail/is_incrementable.hpp> # include <boost/detail/is_incrementable.hpp>
# include <boost/iterator/iterator_traits.hpp> # include <boost/iterator/iterator_traits.hpp>
# include <boost/type_traits/add_const.hpp>
# include <boost/type_traits/remove_cv.hpp> # include <boost/type_traits/remove_cv.hpp>
# include <boost/mpl/if.hpp>
# include <boost/mpl/apply_if.hpp> # include <boost/mpl/apply_if.hpp>
namespace boost { namespace boost {
@ -17,9 +19,37 @@ namespace boost {
namespace detail namespace detail
{ {
template <class P> template <class P>
struct smart_ptr_value struct smart_ptr_pointee
{ {
typedef typename remove_cv<typename P::element_type>::type type; typedef typename P::element_type type;
};
template <class Iterator>
struct iterator_pointee
{
typedef typename iterator_traits<Iterator>::value_type value_type;
struct impl
{
template <class T>
static char test(T const&);
static char (& test(value_type&) )[2];
static Iterator& x;
};
BOOST_STATIC_CONSTANT(bool, is_constant = sizeof(impl::test(*impl::x)) == 1);
typedef typename mpl::if_c<
# if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x551))
::boost::detail::iterator_pointee<Iterator>::is_constant
# else
is_constant
# endif
, typename add_const<value_type>::type
, value_type
>::type type;
}; };
} }
@ -27,11 +57,11 @@ template <class P>
struct pointee struct pointee
{ {
typedef typename remove_cv<P>::type stripped; typedef typename remove_cv<P>::type stripped;
typedef typename mpl::apply_if< typedef typename mpl::apply_if<
detail::is_incrementable<stripped> detail::is_incrementable<stripped>
, iterator_value<stripped> , detail::iterator_pointee<stripped>
, detail::smart_ptr_value<stripped> , detail::smart_ptr_pointee<stripped>
>::type type; >::type type;
}; };

View File

@ -6,6 +6,8 @@
subproject libs/iterator/test ; subproject libs/iterator/test ;
subinclude libs/iterator/example ;
import testing ; import testing ;
test-suite iterator test-suite iterator
@ -29,6 +31,7 @@ test-suite iterator
# These tests should work for just about everything. # These tests should work for just about everything.
[ compile is_lvalue_iterator.cpp ] [ compile is_lvalue_iterator.cpp ]
[ compile is_readable_iterator.cpp ] [ compile is_readable_iterator.cpp ]
[ compile pointee.cpp ]
[ run unit_tests.cpp ] [ run unit_tests.cpp ]
[ run concept_tests.cpp ] [ run concept_tests.cpp ]

View File

@ -30,19 +30,8 @@ struct my_ptr {
BOOST_TT_BROKEN_COMPILER_SPEC(my_ptr) BOOST_TT_BROKEN_COMPILER_SPEC(my_ptr)
BOOST_TT_BROKEN_COMPILER_SPEC(zow) BOOST_TT_BROKEN_COMPILER_SPEC(zow)
#ifndef BOOST_ITERATOR_REF_CONSTNESS_KILLS_WRITABILITY // Borland 5.6.4 and earlier drop const all over the place, so this
// test will fail in the lines marked with (**)
# define STATIC_ASSERT_SAME_POINTER(P1, P2) \
STATIC_ASSERT_SAME( \
boost::remove_const<boost::remove_pointer<P1>::type>::type \
, boost::remove_const<boost::remove_pointer<P2>::type>::type \
)
#else
# define STATIC_ASSERT_SAME_POINTER(P1, P2) STATIC_ASSERT_SAME(P1,P2)
#endif
int main() int main()
{ {
@ -50,7 +39,7 @@ int main()
typedef boost::indirect_iterator<int**> Iter; typedef boost::indirect_iterator<int**> Iter;
STATIC_ASSERT_SAME(Iter::value_type, int); STATIC_ASSERT_SAME(Iter::value_type, int);
STATIC_ASSERT_SAME(Iter::reference, int&); STATIC_ASSERT_SAME(Iter::reference, int&);
STATIC_ASSERT_SAME_POINTER(Iter::pointer, int*); STATIC_ASSERT_SAME(Iter::pointer, int*);
STATIC_ASSERT_SAME(Iter::difference_type, std::ptrdiff_t); STATIC_ASSERT_SAME(Iter::difference_type, std::ptrdiff_t);
BOOST_STATIC_ASSERT((boost::is_convertible<Iter::iterator_category, BOOST_STATIC_ASSERT((boost::is_convertible<Iter::iterator_category,
@ -62,31 +51,26 @@ int main()
typedef boost::indirect_iterator<int const**> Iter; typedef boost::indirect_iterator<int const**> Iter;
STATIC_ASSERT_SAME(Iter::value_type, int); STATIC_ASSERT_SAME(Iter::value_type, int);
STATIC_ASSERT_SAME(Iter::reference, const int&); STATIC_ASSERT_SAME(Iter::reference, const int&);
#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) // Borland drops const all over the place STATIC_ASSERT_SAME(Iter::pointer, const int*); // (**)
STATIC_ASSERT_SAME_POINTER(Iter::pointer, const int*);
#endif
} }
{ {
typedef boost::indirect_iterator<int**, int> Iter; typedef boost::indirect_iterator<int**, int> Iter;
STATIC_ASSERT_SAME(Iter::value_type, int); STATIC_ASSERT_SAME(Iter::value_type, int);
STATIC_ASSERT_SAME(Iter::reference, int&); STATIC_ASSERT_SAME(Iter::reference, int&);
STATIC_ASSERT_SAME_POINTER(Iter::pointer, int*); STATIC_ASSERT_SAME(Iter::pointer, int*);
} }
{ {
typedef boost::indirect_iterator<int**, const int> Iter; typedef boost::indirect_iterator<int**, const int> Iter;
STATIC_ASSERT_SAME(Iter::value_type, int); STATIC_ASSERT_SAME(Iter::value_type, int);
STATIC_ASSERT_SAME(Iter::reference, const int&); STATIC_ASSERT_SAME(Iter::reference, const int&);
#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) // Borland drops const all over the place STATIC_ASSERT_SAME(Iter::pointer, const int*); // (**)
STATIC_ASSERT_SAME_POINTER(Iter::pointer, const int*);
#endif
} }
{ {
typedef boost::indirect_iterator<my_ptr*> Iter; typedef boost::indirect_iterator<my_ptr*> Iter;
STATIC_ASSERT_SAME(Iter::value_type, zow); STATIC_ASSERT_SAME(Iter::value_type, zow);
#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) // Borland drops const all over the place STATIC_ASSERT_SAME(Iter::reference, const zow&); // (**)
STATIC_ASSERT_SAME(Iter::reference, const zow&); STATIC_ASSERT_SAME(Iter::pointer, const zow*); // (**)
STATIC_ASSERT_SAME_POINTER(Iter::pointer, const zow*);
#endif
STATIC_ASSERT_SAME(Iter::difference_type, std::ptrdiff_t); STATIC_ASSERT_SAME(Iter::difference_type, std::ptrdiff_t);
BOOST_STATIC_ASSERT((boost::is_convertible<Iter::iterator_category, BOOST_STATIC_ASSERT((boost::is_convertible<Iter::iterator_category,
@ -98,7 +82,7 @@ int main()
typedef boost::indirect_iterator<char**, int, std::random_access_iterator_tag, long&, short> Iter; typedef boost::indirect_iterator<char**, int, std::random_access_iterator_tag, long&, short> Iter;
STATIC_ASSERT_SAME(Iter::value_type, int); STATIC_ASSERT_SAME(Iter::value_type, int);
STATIC_ASSERT_SAME(Iter::reference, long&); STATIC_ASSERT_SAME(Iter::reference, long&);
STATIC_ASSERT_SAME_POINTER(Iter::pointer, int*); STATIC_ASSERT_SAME(Iter::pointer, int*);
STATIC_ASSERT_SAME(Iter::difference_type, short); STATIC_ASSERT_SAME(Iter::difference_type, short);
} }
return 0; return 0;