indirect iterators

[SVN r672]
This commit is contained in:
Dave Abrahams
2002-11-09 03:38:24 +00:00
parent 844386825a
commit 0f502e2476
2 changed files with 157 additions and 59 deletions

View File

@@ -4,6 +4,10 @@
#include <boost/utility.hpp> // for prior
#include <boost/iterator.hpp>
#include <boost/iterator/iterator_categories.hpp>
#include <boost/mpl/aux_/has_xxx.hpp>
#include <boost/type_traits/is_same.hpp>
#include "boost/type_traits/detail/bool_trait_def.hpp"
namespace boost {
@@ -100,11 +104,14 @@ typename Base1::difference_type operator-(
return j.self().distance_to(i.self());
}
// Used for a default template argument, when we can't afford to
// instantiate the default calculation if unused.
struct unspecified {};
#if 0
// Beginnings of a failed attempt to conditionally provide base()
// functions in iterator_adaptor. It may be that a public m_base
// member is the only way to avoid boilerplate!
struct unspecified {};
template <class Base>
struct base_wrapper_impl
@@ -287,42 +294,87 @@ private:
namespace detail
{
//
// Detection for whether a type has a nested `element_type'
// typedef. Used to detect smart pointers. We're having trouble
// auto-detecting smart pointers with gcc-2.95 via the nested
// element_type member. However, we really ought to have a
// specializable is_pointer template which can be used instead with
// something like boost/python/pointee.hpp to find the value_type.
//
namespace aux
{
BOOST_MPL_HAS_XXX_TRAIT_DEF(element_type)
}
template <class T>
struct traits_of_value_type
: detail::iterator_traits<typename detail::iterator_traits<T>::value_type>
struct has_element_type
: mpl::if_<
is_class<T>
# if __GNUC__ == 2 // gcc 2.95 doesn't seem to be able to detect element_type without barfing
, mpl::bool_c<false>
# else
, aux::has_element_type<T>
# endif
, mpl::bool_c<false>
>::type
{
};
}
template <class Base, // Mutable or Immutable, does not matter
class Value
= BOOST_ARG_DEPENDENT_TYPENAME detail::traits_of_value_type<
Base>::value_type
, class Reference
= BOOST_ARG_DEPENDENT_TYPENAME detail::traits_of_value_type<
Base>::reference
, class Category = BOOST_ARG_DEPENDENT_TYPENAME boost::detail::iterator_traits<
Base>::iterator_category
, class Pointer
= BOOST_ARG_DEPENDENT_TYPENAME detail::traits_of_value_type<
Base>::pointer
>
// Metafunction returning the nested element_type typedef
template <class T>
struct smart_pointer_traits
{
typedef typename remove_const<
typename T::element_type
>::type value_type;
typedef typename T::element_type& reference;
typedef typename T::element_type* pointer;
};
// If the Value parameter is unspecified, we use this metafunction
// to deduce the default types
template <class Iter>
struct indirect_defaults
: mpl::if_c<
has_element_type<typename iterator_traits<Iter>::value_type>::value
, smart_pointer_traits<typename iterator_traits<Iter>::value_type>
, iterator_traits<typename iterator_traits<Iter>::value_type>
>::type
{
typedef typename iterator_traits<Iter>::iterator_category iterator_category;
typedef typename iterator_traits<Iter>::difference_type difference_type;
};
template <class Base, class Traits>
struct indirect_traits
: mpl::if_<is_same<Traits,unspecified>, indirect_defaults<Base>, Traits>::type
{
};
} // namespace detail
template <class Base, class Traits = unspecified>
struct indirect_iterator
: iterator_adaptor<
indirect_iterator<Base,Value,Reference,Category,Pointer>
, Value, Reference, Pointer, Category
, typename detail::iterator_traits<Base>::difference_type
indirect_iterator<Base,Traits>
, typename detail::indirect_traits<Base,Traits>::value_type
, typename detail::indirect_traits<Base,Traits>::reference
, typename detail::indirect_traits<Base,Traits>::pointer
, typename detail::indirect_traits<Base,Traits>::iterator_category
, typename detail::indirect_traits<Base,Traits>::difference_type
>
{
Reference dereference() const { return **this->m_base; }
indirect_iterator() {}
typename detail::indirect_traits<Base,Traits>::reference
dereference() const { return **this->m_base; }
indirect_iterator(Base iter)
: m_base(iter) {}
template <class Base2, class Reference2, class Pointer2>
indirect_iterator(const indirect_iterator<Base2,Value,Reference2,Category,Pointer2>& y)
template <class Base2, class Traits2>
indirect_iterator(const indirect_iterator<Base2,Traits2>& y)
: m_base(y.base())
{}
@@ -332,6 +384,18 @@ struct indirect_iterator
Base m_base;
};
template <class Iter>
indirect_iterator<Iter> make_indirect_iterator(Iter x)
{
return indirect_iterator<Iter>(x);
}
template <class Traits, class Iter>
indirect_iterator<Iter,Traits> make_indirect_iterator(Iter x, Traits* = 0)
{
return indirect_iterator<Iter,Traits>(x);
}
} // namespace boost

View File

@@ -16,6 +16,7 @@
#include <boost/iterator/iterator_adaptors.hpp>
#include <boost/iterator/iterator_tests.hpp>
#include <boost/concept_archetype.hpp>
#include <boost/shared_ptr.hpp>
#include <stdlib.h>
#include <deque>
#include <set>
@@ -35,10 +36,29 @@ struct indirect_iterator_pair_generator
typedef boost::indirect_iterator<typename Container::const_iterator> const_iterator;
};
#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
namespace boost { namespace detail
{
template<> struct iterator_traits<int*>
: ptr_iter_traits<int> {};
template<> struct iterator_traits<dummyT*>
: ptr_iter_traits<dummyT> {};
template<> struct iterator_traits<dummyT const*>
: ptr_iter_traits<dummyT, dummyT const> {};
template<> struct iterator_traits<dummyT**>
: ptr_iter_traits<dummyT*> {};
template<> struct iterator_traits<dummyT const*const*>
: ptr_iter_traits<dummyT const*, dummyT const*const> {};
}}
#endif
void more_indirect_iterator_tests()
{
// For some reason all heck breaks loose in the compiler under these conditions.
#if 1// !defined(BOOST_MSVC) || BOOST_MSVC > 1200 || !defined(__STL_DEBUG)
storage store(1000);
std::generate(store.begin(), store.end(), rand);
@@ -58,13 +78,24 @@ void more_indirect_iterator_tests()
assert(static_cast<std::size_t>(de - db) == store.size());
assert(db + store.size() == de);
IndirectDeque::const_iterator dci(db);
assert(db == dci);
assert(dci == db);
// Older Dinkumware and GCC standard lib don't supply symmetric constant/mutable
// iterator operators
#if !defined(BOOST_MSVC_STD_ITERATOR) && (!defined(_CPPLIB_VER) || _CPPLIB_VER > 310) \
&& (__GNUC__ != 2 || defined(__SGI_STL_PORT))
assert(db == dci);
assert(dci != de);
assert(dci < de);
assert(dci <= de);
#endif
assert(de >= dci);
assert(de > dci);
dci = de;
assert(dci == de);
@@ -73,10 +104,8 @@ void more_indirect_iterator_tests()
*db = 999;
assert(store.front() == 999);
// Borland C++ is getting very confused about the typedef's here
// Borland C++ is getting very confused about the typedefs here
typedef boost::indirect_iterator<iterator_set::iterator> indirect_set_iterator;
typedef boost::indirect_iterator<iterator_set::const_iterator> const_indirect_set_iterator;
indirect_set_iterator sb(iter_set.begin());
@@ -93,8 +122,6 @@ void more_indirect_iterator_tests()
boost::bidirectional_iterator_test(boost::next(sb), store[1], store[2]);
assert(std::equal(db, de, store.begin()));
#endif
}
int
@@ -104,31 +131,39 @@ main()
dummyT(3), dummyT(4), dummyT(5) };
const int N = sizeof(array)/sizeof(dummyT);
typedef std::deque<boost::shared_ptr<dummyT> > shared_t;
shared_t shared;
// Test indirect_iterator_generator
{
for (int jj = 0; jj < N; ++jj)
shared.push_back(boost::shared_ptr<dummyT>(new dummyT(jj)));
dummyT* ptr[N];
for (int k = 0; k < N; ++k)
ptr[k] = array + k;
typedef boost::indirect_iterator<dummyT**
#ifdef BOOST_NO_PARTIAL_SPECIALIZATION
, dummyT
#endif
> indirect_iterator;
typedef boost::indirect_iterator<dummyT**> indirect_iterator;
typedef boost::indirect_iterator<dummyT const* const*
#ifdef BOOST_NO_PARTIAL_SPECIALIZATION
, dummyT
#endif
> const_indirect_iterator;
typedef boost::indirect_iterator<dummyT const* const*> const_indirect_iterator;
indirect_iterator i(ptr);
boost::random_access_iterator_test(i, N, array);
#if 0 // BOOST_NO_STD_ITERATOR_TRAITS
boost::random_access_iterator_test(boost::make_indirect_iterator(ptr), N, array);
#if __GNUC__ != 2
// We're having trouble auto-detecting smart pointers with
// gcc-2.95 via the nested element_type member. However, we
// really ought to have a specializable is_pointer template
// which can be used instead with something like
// boost/python/pointee.hpp to find the value_type.
boost::random_access_iterator_test(
boost::indirect_iterator<shared_t::iterator>(shared.begin())
, N, array);
#endif
boost::random_access_iterator_test(boost::make_indirect_iterator(ptr), N, array);
// check operator->
assert((*i).m_x == i->foo());
@@ -136,10 +171,9 @@ main()
boost::random_access_iterator_test(j, N, array);
#if 0 // BOOST_NO_STD_ITERATOR_TRAITS
dummyT const*const* const_ptr = ptr;
boost::random_access_iterator_test(boost::make_indirect_iterator(const_ptr), N, array);
#endif
boost::const_nonconst_iterator_test(i, ++j);
more_indirect_iterator_tests();