Fix indirect iterators for broken compilers

[SVN r843]
This commit is contained in:
Dave Abrahams
2003-01-11 18:13:43 +00:00
parent a20f712cdc
commit 9a99ffb2ab
2 changed files with 142 additions and 84 deletions

View File

@@ -7,14 +7,19 @@
#include <boost/iterator.hpp> #include <boost/iterator.hpp>
#include <boost/detail/workaround.hpp> #include <boost/detail/workaround.hpp>
#include <boost/iterator/iterator_categories.hpp> #include <boost/iterator/iterator_categories.hpp>
#include <boost/mpl/aux_/has_xxx.hpp> #include <boost/mpl/aux_/has_xxx.hpp>
#include <boost/mpl/logical/or.hpp> #include <boost/mpl/logical/or.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/type_traits/is_same.hpp> #include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/is_convertible.hpp> #include <boost/type_traits/is_convertible.hpp>
#include "boost/type_traits/detail/bool_trait_def.hpp" #include "boost/type_traits/detail/bool_trait_def.hpp"
#if BOOST_WORKAROUND(BOOST_MSVC, <= 1301) || BOOST_WORKAROUND(__GNUC__, <= 2 && __GNUC_MINOR__ <= 95) || BOOST_WORKAROUND(__MWERKS__, <= 0x3000) #if BOOST_WORKAROUND(BOOST_MSVC, <= 1301) \
|| BOOST_WORKAROUND(__GNUC__, <= 2 && __GNUC_MINOR__ <= 95) \
|| BOOST_WORKAROUND(__MWERKS__, <= 0x3000)
# define BOOST_NO_SFINAE // "Substitution Failure Is Not An Error not implemented" # define BOOST_NO_SFINAE // "Substitution Failure Is Not An Error not implemented"
#endif #endif
@@ -25,9 +30,21 @@
#endif #endif
#if BOOST_WORKAROUND(__MWERKS__, <=0x2407) #if BOOST_WORKAROUND(__MWERKS__, <=0x2407)
# define BOOST_NO_IS_CONVERTIBLE // "Convertible does not provide enough/is not working" # define BOOST_NO_IS_CONVERTIBLE // "is_convertible doesn't work"
#endif #endif
#if BOOST_WORKAROUND(__GNUC__, == 2 && __GNUC_MINOR__ == 95) \
|| BOOST_WORKAROUND(__MWERKS__, <= 0x2407)
# define BOOST_NO_MPL_AUX_HAS_XXX // "MPL's has_xxx facility doesn't work"
#endif
#ifdef BOOST_NO_MPL_AUX_HAS_XXX
# include <boost/shared_ptr.hpp>
# include <boost/scoped_ptr.hpp>
# include <memory>
#endif
namespace boost { namespace boost {
namespace detail { namespace detail {
@@ -86,12 +103,12 @@ namespace boost {
// on operator implementation for consequences. // on operator implementation for consequences.
// //
template <typename A, typename B> template <typename A, typename B>
struct is_interoperable : struct is_interoperable
#ifdef BOOST_NO_IS_CONVERTIBLE #ifdef BOOST_NO_IS_CONVERTIBLE
mpl::true_c : mpl::true_c
#else #else
mpl::logical_or< is_convertible< A, B >, : mpl::logical_or< is_convertible< A, B >,
is_convertible< B, A > > is_convertible< B, A > >
#endif #endif
{ {
}; };
@@ -105,12 +122,16 @@ namespace boost {
template <class Facade1, template <class Facade1,
class Facade2, class Facade2,
class Return> class Return>
struct enable_if_interoperable : struct enable_if_interoperable
enabled< is_interoperable<Facade1, Facade2>::value >::template base<Return> # if !defined(BOOST_NO_SFINAE) && !defined(BOOST_NO_IS_CONVERTIBLE)
: enabled< is_interoperable<Facade1, Facade2>::value >::template base<Return>
# else
: mpl::identity<Return>
# endif
{ {
#if BOOST_WORKAROUND(BOOST_MSVC, <=1200) # if BOOST_WORKAROUND(BOOST_MSVC, <= 1200)
typedef typename enabled< is_interoperable<Facade1, Facade2>::value >::template base<Return>::type type; typedef Return type;
#endif # endif
}; };
// //
@@ -161,24 +182,19 @@ namespace boost {
// false positives for user/library defined iterator types. See comments // false positives for user/library defined iterator types. See comments
// on operator implementation for consequences. // on operator implementation for consequences.
// //
#ifdef BOOST_NO_IS_CONVERTIBLE
template<typename From, template<typename From,
typename To> typename To>
struct enable_if_convertible struct enable_if_convertible
{ #if !defined(BOOST_NO_IS_CONVERTIBLE) && !defined(BOOST_NO_SFINAE)
typedef detail::enable_type type; : detail::enabled< is_convertible<From, To>::value >::template base<detail::enable_type>
};
#else #else
template<typename From, : mpl::identity<detail::enable_type>
typename To> #endif
struct enable_if_convertible :
detail::enabled< is_convertible<From, To>::value >::template base<detail::enable_type>
{ {
#if BOOST_WORKAROUND(BOOST_MSVC, <=1200) # if BOOST_WORKAROUND(BOOST_MSVC, <= 1200)
typedef typename detail::enabled< is_convertible<From, To>::value >::template base<detail::enable_type>::type type; typedef detail::enable_type type;
#endif # endif
}; };
#endif
// //
// Helper class for granting access to the iterator core interface. // Helper class for granting access to the iterator core interface.
@@ -708,31 +724,44 @@ namespace boost {
{ {
// //
// Detection for whether a type has a nested `element_type' // Detection for whether a type has a nested `element_type'
// typedef. Used to detect smart pointers. We're having trouble // typedef. Used to detect smart pointers. For compilers not
// auto-detecting smart pointers with gcc-2.95 via the nested // supporting mpl's has_xxx, we supply specialzations. However, we
// element_type member. However, we really ought to have a // really ought to have a specializable is_pointer template which
// specializable is_pointer template which can be used instead with // can be used instead with something like
// something like boost/python/pointee.hpp to find the value_type. // boost/python/pointee.hpp to find the value_type.
// //
# if !defined BOOST_NO_MPL_AUX_HAS_XXX
namespace aux namespace aux
{ {
BOOST_MPL_HAS_XXX_TRAIT_DEF(element_type) BOOST_MPL_HAS_XXX_TRAIT_DEF(element_type)
} }
template <class T> template <class T>
struct has_element_type struct has_element_type
: mpl::if_< : mpl::if_<
is_class<T> is_class<T>
// gcc 2.95 doesn't seem to be able to detect element_type without barfing , aux::has_element_type<T>
# if BOOST_WORKAROUND(__GNUC__, == 2 && __GNUC_MINOR__ == 95) , mpl::false_c
, mpl::bool_c<false> >::type
# else
, aux::has_element_type<T>
# endif
, mpl::bool_c<false>
>::type
{ {
}; };
# else
template <class T>
struct has_element_type
: mpl::false_c {};
template <class T>
struct has_element_type<boost::shared_ptr<T> >
: mpl::true_c {};
template <class T>
struct has_element_type<boost::scoped_ptr<T> >
: mpl::true_c {};
template <class T>
struct has_element_type<std::auto_ptr<T> >
: mpl::true_c {};
# endif
// Metafunction returning the nested element_type typedef // Metafunction returning the nested element_type typedef
template <class T> template <class T>
@@ -750,11 +779,11 @@ namespace boost {
// to deduce the default types // to deduce the default types
template <class Iter> template <class Iter>
struct indirect_defaults struct indirect_defaults
: mpl::if_c< : mpl::if_<
has_element_type<typename iterator_traits<Iter>::value_type>::value has_element_type<typename iterator_traits<Iter>::value_type>
, smart_pointer_traits<typename iterator_traits<Iter>::value_type> , smart_pointer_traits<typename iterator_traits<Iter>::value_type>
, iterator_traits<typename iterator_traits<Iter>::value_type> , iterator_traits<typename iterator_traits<Iter>::value_type>
>::type >::type
{ {
typedef typename iterator_traits<Iter>::iterator_category iterator_category; typedef typename iterator_traits<Iter>::iterator_category iterator_category;
typedef typename iterator_traits<Iter>::difference_type difference_type; typedef typename iterator_traits<Iter>::difference_type difference_type;
@@ -824,14 +853,9 @@ namespace boost {
// clean up local workaround macros // clean up local workaround macros
// //
#ifdef BOOST_NO_SFINAE #undef BOOST_NO_SFINAE
# undef BOOST_NO_SFINAE
#endif
#undef BOOST_ARG_DEP_TYPENAME #undef BOOST_ARG_DEP_TYPENAME
#undef BOOST_NO_IS_CONVERTIBLE
#ifdef BOOST_NO_IS_CONVERTIBLE #undef BOOST_NO_MPL_AUX_HAS_XXX
# undef BOOST_NO_IS_CONVERTIBLE
#endif
#endif // BOOST_ITERATOR_ADAPTORS_HPP #endif // BOOST_ITERATOR_ADAPTORS_HPP

View File

@@ -26,22 +26,64 @@
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <stdlib.h> #include <stdlib.h>
#include <deque>
#include <set> #include <set>
#if defined(BOOST_MSVC_STD_ITERATOR) \
|| BOOST_WORKAROUND(_CPPLIB_VER, <= 310) \
|| BOOST_WORKAROUND(__GNUC__, <= 2 && !defined(__SGI_STL_PORT))
// std container random-access iterators don't support mutable/const
// interoperability (but may support const/mutable interop).
# define NO_MUTABLE_CONST_STD_DEQUE_ITERATOR_INTEROPERABILITY
# define NO_MUTABLE_CONST_STD_SET_ITERATOR_INTEROPERABILITY
#endif
#if defined(BOOST_MSVC_STD_ITERATOR) \
|| defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
// No working iterator_traits implementation, so we must use deque
# define RA_CONTAINER std::deque
# include <deque>
# ifdef NO_MUTABLE_CONST_STD_DEQUE_ITERATOR_INTEROPERABILITY
# define NO_MUTABLE_CONST_RA_ITERATOR_INTEROPERABILITY
# endif
#else
# define RA_CONTAINER std::vector
# include <vector>
#endif
struct my_iterator_tag : public std::random_access_iterator_tag { }; struct my_iterator_tag : public std::random_access_iterator_tag { };
using boost::dummyT; using boost::dummyT;
typedef std::deque<int> storage; typedef RA_CONTAINER<int> storage;
typedef std::deque<int*> pointer_deque; typedef RA_CONTAINER<int*> pointer_ra_container;
typedef std::set<storage::iterator> iterator_set; typedef std::set<storage::iterator> iterator_set;
// Something has to be done about putting this in the lib
template <class Iter>
struct indirect_const_iterator_traits
: boost::detail::indirect_defaults<Iter>
{
typedef boost::detail::indirect_defaults<Iter> base;
typedef typename base::value_type const& reference;
typedef typename base::value_type const* pointer;
};
template <class Container> template <class Container>
struct indirect_iterator_pair_generator struct indirect_iterator_pair_generator
{ {
typedef boost::indirect_iterator<typename Container::iterator> iterator; typedef boost::indirect_iterator<typename Container::iterator> iterator;
typedef boost::indirect_iterator<typename Container::const_iterator> const_iterator;
typedef boost::indirect_iterator<
typename Container::iterator
, indirect_const_iterator_traits<typename Container::iterator>
> const_iterator;
}; };
#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION #ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
@@ -70,40 +112,37 @@ void more_indirect_iterator_tests()
storage store(1000); storage store(1000);
std::generate(store.begin(), store.end(), rand); std::generate(store.begin(), store.end(), rand);
pointer_deque ptr_deque; pointer_ra_container ptr_ra_container;
iterator_set iter_set; iterator_set iter_set;
for (storage::iterator p = store.begin(); p != store.end(); ++p) for (storage::iterator p = store.begin(); p != store.end(); ++p)
{ {
ptr_deque.push_back(&*p); ptr_ra_container.push_back(&*p);
iter_set.insert(p); iter_set.insert(p);
} }
typedef indirect_iterator_pair_generator<pointer_deque> IndirectDeque; typedef indirect_iterator_pair_generator<pointer_ra_container> indirect_ra_container;
IndirectDeque::iterator db(ptr_deque.begin()); indirect_ra_container::iterator db(ptr_ra_container.begin());
IndirectDeque::iterator de(ptr_deque.end()); indirect_ra_container::iterator de(ptr_ra_container.end());
assert(static_cast<std::size_t>(de - db) == store.size()); assert(static_cast<std::size_t>(de - db) == store.size());
assert(db + store.size() == de); assert(db + store.size() == de);
IndirectDeque::const_iterator dci(db); indirect_ra_container::const_iterator dci = db;
assert(dci == db); assert(dci == db);
// Older Dinkumware and GCC standard lib don't supply symmetric constant/mutable #ifndef NO_MUTABLE_CONST_RA_ITERATOR_INTEROPERABILITY
// iterator operators
#if !defined(BOOST_MSVC_STD_ITERATOR) \
&& !BOOST_WORKAROUND(_CPPLIB_VER, <= 310) \
&& !BOOST_WORKAROUND(__GNUC__, <= 2 && !defined(__SGI_STL_PORT))
assert(db == dci); assert(db == dci);
#endif
assert(dci != de); assert(dci != de);
assert(dci < de); assert(dci < de);
assert(dci <= de); assert(dci <= de);
#endif
#ifndef NO_MUTABLE_CONST_RA_ITERATOR_INTEROPERABILITY
assert(de >= dci); assert(de >= dci);
assert(de > dci); assert(de > dci);
#endif
dci = de; dci = de;
assert(dci == de); assert(dci == de);
@@ -121,6 +160,11 @@ void more_indirect_iterator_tests()
indirect_set_iterator se(iter_set.end()); indirect_set_iterator se(iter_set.end());
const_indirect_set_iterator sci(iter_set.begin()); const_indirect_set_iterator sci(iter_set.begin());
assert(sci == sb); assert(sci == sb);
# ifndef NO_MUTABLE_CONST_STD_SET_ITERATOR_INTEROPERABILITY
assert(se != sci);
# endif
assert(sci != se); assert(sci != se);
sci = se; sci = se;
assert(sci == se); assert(sci == se);
@@ -140,7 +184,7 @@ main()
dummyT(3), dummyT(4), dummyT(5) }; dummyT(3), dummyT(4), dummyT(5) };
const int N = sizeof(array)/sizeof(dummyT); const int N = sizeof(array)/sizeof(dummyT);
typedef std::deque<boost::shared_ptr<dummyT> > shared_t; typedef RA_CONTAINER<boost::shared_ptr<dummyT> > shared_t;
shared_t shared; shared_t shared;
// Concept checks // Concept checks
@@ -148,12 +192,9 @@ main()
typedef boost::indirect_iterator<shared_t::iterator> iter_t; typedef boost::indirect_iterator<shared_t::iterator> iter_t;
typedef boost::indirect_iterator<shared_t::const_iterator> c_iter_t; typedef boost::indirect_iterator<shared_t::const_iterator> c_iter_t;
// Older Dinkumware and GCC standard lib don't supply symmetric constant/mutable # ifndef NO_MUTABLE_CONST_RA_ITERATOR_INTEROPERABILITY
// iterator operators
#if !defined(BOOST_MSVC_STD_ITERATOR) && (!defined(_CPPLIB_VER) || _CPPLIB_VER > 310) \
&& (__GNUC__ != 2 || defined(__SGI_STL_PORT))
boost::function_requires< boost_concepts::InteroperableConcept<iter_t, c_iter_t> >(); boost::function_requires< boost_concepts::InteroperableConcept<iter_t, c_iter_t> >();
#endif # endif
} }
// Test indirect_iterator_generator // Test indirect_iterator_generator
@@ -167,22 +208,15 @@ main()
typedef boost::indirect_iterator<dummyT**> indirect_iterator; typedef boost::indirect_iterator<dummyT**> indirect_iterator;
typedef boost::indirect_iterator<dummyT const* const*> const_indirect_iterator; typedef boost::indirect_iterator<dummyT**, indirect_const_iterator_traits<dummyT**> >
const_indirect_iterator;
indirect_iterator i(ptr); indirect_iterator i(ptr);
boost::random_access_iterator_test(i, N, array); boost::random_access_iterator_test(i, 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::random_access_iterator_test(
boost::indirect_iterator<shared_t::iterator>(shared.begin()) boost::indirect_iterator<shared_t::iterator>(shared.begin())
, N, array); , N, array);
#endif
boost::random_access_iterator_test(boost::make_indirect_iterator(ptr), N, array); boost::random_access_iterator_test(boost::make_indirect_iterator(ptr), N, array);