diff --git a/include/boost/iterator/iterator_adaptors.hpp b/include/boost/iterator/iterator_adaptors.hpp index 7bf438e..d2158d1 100644 --- a/include/boost/iterator/iterator_adaptors.hpp +++ b/include/boost/iterator/iterator_adaptors.hpp @@ -4,6 +4,10 @@ #include // for prior #include #include +#include +#include + +#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 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 - struct traits_of_value_type - : detail::iterator_traits::value_type> + struct has_element_type + : mpl::if_< + is_class +# if __GNUC__ == 2 // gcc 2.95 doesn't seem to be able to detect element_type without barfing + , mpl::bool_c +# else + , aux::has_element_type +# endif + , mpl::bool_c + >::type { }; -} + + // Metafunction returning the nested element_type typedef + template + struct smart_pointer_traits + { + typedef typename remove_const< + typename T::element_type + >::type value_type; -template ::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 - > + 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 + struct indirect_defaults + : mpl::if_c< + has_element_type::value_type>::value + , smart_pointer_traits::value_type> + , iterator_traits::value_type> + >::type + { + typedef typename iterator_traits::iterator_category iterator_category; + typedef typename iterator_traits::difference_type difference_type; + }; + + template + struct indirect_traits + : mpl::if_, indirect_defaults, Traits>::type + { + }; +} // namespace detail + +template struct indirect_iterator : iterator_adaptor< - indirect_iterator - , Value, Reference, Pointer, Category - , typename detail::iterator_traits::difference_type + indirect_iterator + , typename detail::indirect_traits::value_type + , typename detail::indirect_traits::reference + , typename detail::indirect_traits::pointer + , typename detail::indirect_traits::iterator_category + , typename detail::indirect_traits::difference_type > { - Reference dereference() const { return **this->m_base; } - indirect_iterator() {} + + typename detail::indirect_traits::reference + dereference() const { return **this->m_base; } indirect_iterator(Base iter) : m_base(iter) {} - template - indirect_iterator(const indirect_iterator& y) + template + indirect_iterator(const indirect_iterator& y) : m_base(y.base()) {} @@ -332,6 +384,18 @@ struct indirect_iterator Base m_base; }; +template +indirect_iterator make_indirect_iterator(Iter x) +{ + return indirect_iterator(x); +} + +template +indirect_iterator make_indirect_iterator(Iter x, Traits* = 0) +{ + return indirect_iterator(x); +} + } // namespace boost diff --git a/test/indirect_iterator_test.cpp b/test/indirect_iterator_test.cpp index 704aa92..4fb5b37 100644 --- a/test/indirect_iterator_test.cpp +++ b/test/indirect_iterator_test.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -35,10 +36,29 @@ struct indirect_iterator_pair_generator typedef boost::indirect_iterator const_iterator; }; +#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +namespace boost { namespace detail +{ + template<> struct iterator_traits + : ptr_iter_traits {}; + + template<> struct iterator_traits + : ptr_iter_traits {}; + + template<> struct iterator_traits + : ptr_iter_traits {}; + + template<> struct iterator_traits + : ptr_iter_traits {}; + + template<> struct iterator_traits + : ptr_iter_traits {}; +}} +#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(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 indirect_set_iterator; - typedef boost::indirect_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,45 +131,52 @@ main() dummyT(3), dummyT(4), dummyT(5) }; const int N = sizeof(array)/sizeof(dummyT); + typedef std::deque > shared_t; + shared_t shared; + // Test indirect_iterator_generator { - dummyT* ptr[N]; - for (int k = 0; k < N; ++k) - ptr[k] = array + k; + for (int jj = 0; jj < N; ++jj) + shared.push_back(boost::shared_ptr(new dummyT(jj))); + + dummyT* ptr[N]; + for (int k = 0; k < N; ++k) + ptr[k] = array + k; - typedef boost::indirect_iterator indirect_iterator; + typedef boost::indirect_iterator indirect_iterator; - typedef boost::indirect_iterator const_indirect_iterator; + typedef boost::indirect_iterator const_indirect_iterator; - indirect_iterator i(ptr); - boost::random_access_iterator_test(i, N, array); + 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); -#endif +#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.begin()) + , N, array); +#endif + + boost::random_access_iterator_test(boost::make_indirect_iterator(ptr), N, array); - // check operator-> - assert((*i).m_x == i->foo()); + // check operator-> + assert((*i).m_x == i->foo()); - const_indirect_iterator j(ptr); - boost::random_access_iterator_test(j, N, array); + const_indirect_iterator j(ptr); + 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); + dummyT const*const* const_ptr = ptr; + boost::random_access_iterator_test(boost::make_indirect_iterator(const_ptr), N, array); + + boost::const_nonconst_iterator_test(i, ++j); - more_indirect_iterator_tests(); + more_indirect_iterator_tests(); } std::cout << "test successful " << std::endl; return 0;