diff --git a/include/boost/iterator/detail/categories.hpp b/include/boost/iterator/detail/categories.hpp index 7a1a6d6..48d1e3d 100644 --- a/include/boost/iterator/detail/categories.hpp +++ b/include/boost/iterator/detail/categories.hpp @@ -5,25 +5,24 @@ // to its suitability for any purpose. #ifndef BOOST_ITERATOR_DETAIL_CATEGORIES_HPP -#define BOOST_ITERATOR_DETAIL_CATEGORIES_HPP +# define BOOST_ITERATOR_DETAIL_CATEGORIES_HPP -#include -#include +# include +# include -#include +# include -#include -#include -#include +# include +# include -#include -#include -#include -#include -#include -#include +# include +# include +# include +# include +# include +# include -#include +# include namespace boost { @@ -78,19 +77,19 @@ namespace boost // // Traversal Categories // - struct incrementable_iterator_tag + struct incrementable_traversal_tag { typedef std::output_iterator_tag max_category; }; - struct single_pass_iterator_tag - : incrementable_iterator_tag + struct single_pass_traversal_tag + : incrementable_traversal_tag { typedef detail::input_output_iterator_tag max_category; }; struct forward_traversal_tag - : single_pass_iterator_tag + : single_pass_traversal_tag { typedef std::forward_iterator_tag max_category; }; @@ -118,53 +117,36 @@ namespace boost // I bet this is defined somewhere else. Let's wait and see. struct error_type; -#ifndef BOOST_NO_IS_CONVERTIBLE - template - struct is_same_or_derived -# ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - : mpl::or_< - is_same - , is_base_and_derived - > - {}; -# else - : is_base_and_derived - {}; +# ifndef BOOST_NO_IS_CONVERTIBLE - template struct is_same_or_derived : mpl::true_ {}; -# endif - + // True iff T is a tag "derived" from Tag template struct is_tag : mpl::or_< -# ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - is_same_or_derived -# else - is_base_and_derived -# endif + is_convertible // Because we can't actually get forward_iterator_tag to // derive from input_output_iterator_tag, we need this // case. , mpl::and_< - is_same_or_derived - , is_same_or_derived + is_convertible + , is_convertible > > {}; -#else +# else template struct is_tag; -#endif +# endif // Generate specializations which will allow us to find // null_category_tag as a minimum old-style category for new-style // iterators which don't have an actual old-style category. We // need that so there is a valid base class for all new-style // iterators. -#define BOOST_OLD_ITERATOR_CATEGORY(category) \ +# define BOOST_OLD_ITERATOR_CATEGORY(category) \ template <> \ struct is_tag \ : mpl::true_ {}; @@ -174,7 +156,7 @@ namespace boost BOOST_OLD_ITERATOR_CATEGORY(forward_iterator_tag) BOOST_OLD_ITERATOR_CATEGORY(bidirectional_iterator_tag) BOOST_OLD_ITERATOR_CATEGORY(random_access_iterator_tag) -#undef BOOST_OLD_ITERATOR_CATEGORY +# undef BOOST_OLD_ITERATOR_CATEGORY template <> struct is_tag @@ -182,7 +164,7 @@ namespace boost { }; -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template struct is_tag : mpl::true_ {}; @@ -214,14 +196,14 @@ namespace boost : is_tag_impl {}; -# define BOOST_ITERATOR_DERIVED_TAG1(base, derived) \ +# define BOOST_ITERATOR_DERIVED_TAG1(base, derived) \ BOOST_ITERATOR_DERIVED_TAG1_AUX(base, _, derived) -# define BOOST_ITERATOR_DERIVED_TAG1_AUX(base, underscore, derived) \ - template \ - struct is_tag_impl \ - : is_tag \ - { \ +# define BOOST_ITERATOR_DERIVED_TAG1_AUX(base, underscore, derived) \ + template \ + struct is_tag_impl \ + : is_tag \ + { \ }; // Old-style tag relations @@ -259,17 +241,66 @@ namespace boost // Traversal tag relations BOOST_ITERATOR_DERIVED_TAG1(bidirectional_traversal, random_access_traversal) BOOST_ITERATOR_DERIVED_TAG1(forward_traversal, bidirectional_traversal) - BOOST_ITERATOR_DERIVED_TAG1(single_pass_iterator, forward_traversal) - BOOST_ITERATOR_DERIVED_TAG1(incrementable_iterator, single_pass_iterator) + BOOST_ITERATOR_DERIVED_TAG1(single_pass_traversal, forward_traversal) + BOOST_ITERATOR_DERIVED_TAG1(incrementable_traversal, single_pass_traversal) -# endif // BOOST_NO_IS_CONVERTIBLE workarounds +# endif // BOOST_NO_IS_CONVERTIBLE workarounds -#else // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION case - - -#endif +# endif // ndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - + template + struct known_tag + : mpl::apply_if, mpl::identity, Else> + {}; + + template + struct max_known_traversal_tag + : known_tag< + Tag, random_access_traversal_tag + , known_tag< + Tag, bidirectional_traversal_tag + , known_tag< + Tag, forward_traversal_tag + , known_tag< + Tag, single_pass_traversal_tag + , known_tag< + Tag, incrementable_traversal_tag + , error_iterator_tag + > + > + > + > + > + {}; + + // Doesn't cope with these odd combinations: readable+swappable, + // writable+swappable. That doesn't matter for the sake of + // new-style tag base computation, which is all it's used for + // anyway. + template + struct max_known_access_tag + : known_tag< + Tag, writable_lvalue_iterator_tag + , known_tag< + Tag, readable_lvalue_iterator_tag + , known_tag< + Tag, readable_writable_iterator_tag + , known_tag< + Tag, writable_iterator_tag + , known_tag< + Tag, readable_iterator_tag + , mpl::apply_if< + is_tag + , mpl::identity + , error_iterator_tag + > + > + > + > + > + > + {}; + // // Returns the minimum category type or error_type // if T1 and T2 are unrelated. diff --git a/include/boost/iterator/iterator_archetypes.hpp b/include/boost/iterator/iterator_archetypes.hpp index d5649cf..e9439e7 100644 --- a/include/boost/iterator/iterator_archetypes.hpp +++ b/include/boost/iterator/iterator_archetypes.hpp @@ -90,7 +90,7 @@ namespace boost {}; template <> - struct traversal_archetype_impl + struct traversal_archetype_impl { template struct archetype @@ -103,32 +103,32 @@ namespace boost }; template <> - struct traversal_archetype_impl + struct traversal_archetype_impl { template struct archetype - : public equality_comparable< traversal_archetype_ >, - public traversal_archetype_ + : public equality_comparable< traversal_archetype_ >, + public traversal_archetype_ { }; }; template - bool operator==(traversal_archetype_ const&, - traversal_archetype_ const&); + bool operator==(traversal_archetype_ const&, + traversal_archetype_ const&); #if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) // doesn't seem to pick up != from equality_comparable template - bool operator!=(traversal_archetype_ const&, - traversal_archetype_ const&); + bool operator!=(traversal_archetype_ const&, + traversal_archetype_ const&); #endif template <> struct traversal_archetype_impl { template struct archetype - : public traversal_archetype_ + : public traversal_archetype_ { typedef std::ptrdiff_t difference_type; }; diff --git a/include/boost/iterator/iterator_categories.hpp b/include/boost/iterator/iterator_categories.hpp index 9e82708..23724b1 100644 --- a/include/boost/iterator/iterator_categories.hpp +++ b/include/boost/iterator/iterator_categories.hpp @@ -98,7 +98,7 @@ namespace boost { template <> struct std_to_new_tags { - typedef single_pass_iterator_tag type; + typedef single_pass_traversal_tag type; template struct apply @@ -109,7 +109,7 @@ namespace boost { template <> struct std_to_new_tags { - typedef incrementable_iterator_tag type; + typedef incrementable_traversal_tag type; template struct apply @@ -227,22 +227,55 @@ namespace boost { namespace detail { - template - struct get_access_category { - typedef typename NewCategoryTag::returns type; - }; template struct get_traversal_category { typedef typename NewCategoryTag::traversal type; }; + // Remove all writability from the given access tag. This + // functionality is part of new_category_to_access in order to + // support deduction of the proper default access category for + // iterator_adaptor; when the reference type is a reference to + // constant we must strip writability. + template + struct remove_access_writability + : mpl::apply_if< + is_tag + , mpl::identity + + , mpl::apply_if< + is_tag + , mpl::identity + + , mpl::if_< + is_tag + // Is this OK? I think it may correct be for all + // legitimate cases, because at this point the + // iterator is not readable, so it could not have + // been any more than writable + swappable. + , swappable_iterator_tag + , AccessTag + > + > + > + {}; + + template + struct new_category_to_access + : mpl::apply_if< + python::detail::is_reference_to_const + , remove_access_writability + , mpl::identity + > + {}; + template struct access_category_tag : mpl::apply_if< - is_new_iterator_tag - , get_access_category - , iter_category_to_access - > + is_new_iterator_tag + , new_category_to_access + , iter_category_to_access + > { }; @@ -261,7 +294,35 @@ namespace boost { template <> struct access_category_tag { typedef void type; }; template <> struct traversal_category_tag { typedef void type; }; # endif + + // iterator_tag_base - a metafunction to compute the appropriate + // old-style tag (if any) to use as a base for a new-style tag. + template + struct iterator_tag_base + : minimum_category< + typename KnownAccessTag::max_category + , typename KnownTraversalTag::max_category + > + {}; +# if BOOST_WORKAROUND(BOOST_MSVC,<=1200) + template <> + struct iterator_tag_base + : mpl::false_ {}; // just using false_ so that the result will be + // a legal base class +# endif + + // specialization for this special case. Otherwise we get + // input_output_iterator_tag, because the standard hierarchy has a + // sudden anomalous distinction between readability and + // writability at the level of input iterator/output iterator. + template <> + struct iterator_tag_base< + readable_lvalue_iterator_tag,single_pass_traversal_tag> + { + typedef std::input_iterator_tag type; + }; + } // namespace detail template @@ -279,7 +340,7 @@ namespace boost { { }; -#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) +# if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) template struct access_category @@ -296,18 +357,16 @@ namespace boost { typedef random_access_traversal_tag type; }; -#endif +# endif - template + template struct iterator_tag - : mpl::aux::msvc_eti_base< - typename detail::minimum_category< - typename ReturnTag::max_category - , typename TraversalTag::max_category - >::type - >::type + : detail::iterator_tag_base< + typename detail::max_known_access_tag::type + , typename detail::max_known_traversal_tag::type + >::type { - typedef ReturnTag returns; + typedef AccessTag access; typedef TraversalTag traversal; }; diff --git a/include/boost/iterator/iterator_concepts.hpp b/include/boost/iterator/iterator_concepts.hpp index 5affb96..fe5b433 100644 --- a/include/boost/iterator/iterator_concepts.hpp +++ b/include/boost/iterator/iterator_concepts.hpp @@ -164,7 +164,7 @@ namespace boost_concepts { boost::function_requires< boost::DefaultConstructibleConcept >(); - BOOST_STATIC_ASSERT((boost::detail::is_tag::value)); + BOOST_STATIC_ASSERT((boost::detail::is_tag::value)); ++i; (void)i++; @@ -182,7 +182,7 @@ namespace boost_concepts { boost::function_requires< IncrementableIteratorConcept >(); boost::function_requires< boost::EqualityComparableConcept >(); - BOOST_STATIC_ASSERT((boost::detail::is_tag::value)); + BOOST_STATIC_ASSERT((boost::detail::is_tag::value)); } }; @@ -254,7 +254,7 @@ namespace detail struct Operations; template <> - struct Operations + struct Operations { template static void constraints(Iterator1 const& i1, Iterator2 const& i2) @@ -264,12 +264,12 @@ namespace detail }; template <> - struct Operations + struct Operations { template static void constraints(Iterator1 const& i1, Iterator2 const& i2) { - Operations(i1, i2); + Operations(i1, i2); i1 == i2; i1 != i2; @@ -284,7 +284,7 @@ namespace detail template static void constraints(Iterator1 const& i1, Iterator2 const& i2) { - Operations::constraints(i1, i2); + Operations::constraints(i1, i2); } }; diff --git a/include/boost/iterator/iterator_facade.hpp b/include/boost/iterator/iterator_facade.hpp index b1eede9..4c22c2c 100644 --- a/include/boost/iterator/iterator_facade.hpp +++ b/include/boost/iterator/iterator_facade.hpp @@ -62,11 +62,22 @@ namespace boost }; + // + // Add const qualification for iterators which are not writable + // template - struct const_qualified : + struct const_qualified_ref : mpl::if_< is_tag< writable_iterator_tag, AccessCategory >, - Value, - Value const > + Value&, + Value const& > + {}; + + // The apparent duplication here works around a Borland problem + template + struct const_qualified_ptr : + mpl::if_< is_tag< writable_iterator_tag, AccessCategory >, + Value*, + Value const* > {}; // @@ -84,7 +95,7 @@ namespace boost , Difference - , typename const_qualified::type* + , typename const_qualified_ptr::type // The use_default support is needed for iterator_adaptor. // For practical reasons iterator_adaptor needs to specify @@ -93,7 +104,7 @@ namespace boost // is your default parameter". , typename mpl::if_< is_same - , typename const_qualified::type& + , typename const_qualified_ref::type , Reference >::type > @@ -333,7 +344,7 @@ namespace boost , class Value , class AccessCategory , class TraversalCategory - , class Reference = typename detail::const_qualified::type& + , class Reference = typename detail::const_qualified_ref::type , class Difference = std::ptrdiff_t > class iterator_facade diff --git a/test/concept_tests.cpp b/test/concept_tests.cpp index 698c6bc..64d2c05 100644 --- a/test/concept_tests.cpp +++ b/test/concept_tests.cpp @@ -7,6 +7,8 @@ #include #include #include // remove +#include +#include "static_assert_same.hpp" // remove struct new_iterator : public boost::iterator< boost::iterator_tag< @@ -50,13 +52,26 @@ struct old_iterator }; old_iterator operator+(std::ptrdiff_t, old_iterator x) { return x; } +struct my_writable_lvalue_iterator_tag +{ + operator boost::writable_lvalue_iterator_tag() const; +}; + +struct my_single_pass_traversal_tag +{ + operator boost::single_pass_traversal_tag() const; +}; + void test_tag_convertibility() { -#ifndef BOOST_NO_IS_CONVERTIBLE + // This set of tests is by no means complete. + + // Test that this is an input/output iterator +#if !BOOST_WORKAROUND(__MWERKS__, <= 0x2407) { typedef boost::iterator_tag< boost::writable_lvalue_iterator_tag - , boost::single_pass_iterator_tag + , boost::single_pass_traversal_tag > tag; BOOST_STATIC_ASSERT(( @@ -69,10 +84,33 @@ void test_tag_convertibility() !boost::is_convertible::value )); } + + // Test that it's possible to build new sub-tags without + // derivation. Convertibility should be enough + { + typedef boost::iterator_tag< + my_writable_lvalue_iterator_tag + , my_single_pass_traversal_tag + > tag; + + BOOST_STATIC_ASSERT(( + boost::is_convertible::value + )); + BOOST_STATIC_ASSERT(( + boost::is_convertible::value + )); + BOOST_STATIC_ASSERT(( + !boost::is_convertible::value + )); + } + + // Test that a single-pass readable lvalue iterator is only an + // input iterator. Requires special case handling in + // categories.hpp { typedef boost::iterator_tag< boost::readable_lvalue_iterator_tag - , boost::single_pass_iterator_tag + , boost::single_pass_traversal_tag > tag; BOOST_STATIC_ASSERT(( boost::is_convertible::value @@ -95,12 +133,12 @@ main() typedef boost::iterator_tag< boost::writable_lvalue_iterator_tag, boost::random_access_traversal_tag > tag; // BOOST_STATIC_ASSERT((boost::detail::is_random_access_iterator::value)); - BOOST_STATIC_ASSERT((boost::is_same::value)); - BOOST_STATIC_ASSERT((boost::is_same::value)); + int test = static_assert_same::value; + test = static_assert_same::value; // BOOST_STATIC_ASSERT((boost::detail::is_random_access_iterator::value)); - BOOST_STATIC_ASSERT((boost::is_same::value)); - BOOST_STATIC_ASSERT((boost::is_same::value)); + test = static_assert_same::value; + test = static_assert_same::value; typedef boost::traversal_category::type traversal_category; @@ -108,8 +146,8 @@ main() BOOST_STATIC_ASSERT(boost::detail::is_new_iterator_tag::value); - BOOST_STATIC_ASSERT((boost::is_same::value)); - + test = static_assert_same::value; + (void)test; #if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) boost::function_requires< diff --git a/test/iterator_adaptor_test.cpp b/test/iterator_adaptor_test.cpp index 6e71714..32edd85 100644 --- a/test/iterator_adaptor_test.cpp +++ b/test/iterator_adaptor_test.cpp @@ -13,15 +13,6 @@ #include #include -#if 0 -#include -#include -#include -#include -#include -#include -#endif - #include #include @@ -31,6 +22,8 @@ #include #include +#include "static_assert_same.hpp" + struct my_iterator_tag : public std::random_access_iterator_tag { }; using boost::dummyT; @@ -163,9 +156,15 @@ struct constant_iterator , typename std::iterator_traits::value_type const > { + typedef boost::iterator_adaptor< + constant_iterator + , Iter + , typename std::iterator_traits::value_type const + > base_t; + constant_iterator() {} constant_iterator(Iter it) - : constant_iterator::iterator_adaptor(it) {} + : base_t(it) {} }; int @@ -187,16 +186,17 @@ main() boost::random_access_iterator_test(j, N, array); boost::const_nonconst_iterator_test(i, ++j); } - + + int test; // Test the iterator_traits { // Test computation of defaults typedef ptr_iterator Iter1; // don't use std::iterator_traits here to avoid VC++ problems - BOOST_STATIC_ASSERT((boost::is_same::value)); - BOOST_STATIC_ASSERT((boost::is_same::value)); - BOOST_STATIC_ASSERT((boost::is_same::value)); - BOOST_STATIC_ASSERT((boost::is_same::value)); + test = static_assert_same::value; + test = static_assert_same::value; + test = static_assert_same::value; + test = static_assert_same::value; #if !BOOST_WORKAROUND(__MWERKS__, <= 0x2407) BOOST_STATIC_ASSERT((boost::is_convertible::value)); #endif @@ -205,14 +205,9 @@ main() { // Test computation of default when the Value is const typedef ptr_iterator Iter1; - BOOST_STATIC_ASSERT((boost::is_same::value)); - BOOST_STATIC_ASSERT((boost::is_same::value)); - BOOST_STATIC_ASSERT((boost::is_same::value)); - -#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x551)) - // Borland has known problems with const - BOOST_STATIC_ASSERT((boost::is_same::value)); -#endif + test = static_assert_same::value; + test = static_assert_same::value; + test = static_assert_same::value; test = static_assert_same::value; } { @@ -220,12 +215,12 @@ main() typedef ptr_iterator BaseIter; typedef constant_iterator Iter; - BOOST_STATIC_ASSERT((boost::is_same::value)); - BOOST_STATIC_ASSERT((boost::is_same::value)); - BOOST_STATIC_ASSERT((boost::is_same::value)); + test = static_assert_same::value; + test = static_assert_same::value; + test = static_assert_same::value; - BOOST_STATIC_ASSERT((boost::is_same::value)); - BOOST_STATIC_ASSERT((boost::is_same::value)); + test = static_assert_same::value; + test = static_assert_same::value; } // Test the iterator_adaptor @@ -261,5 +256,6 @@ main() } std::cout << "test successful " << std::endl; + (void)test; return 0; } diff --git a/test/static_assert_same.hpp b/test/static_assert_same.hpp new file mode 100755 index 0000000..3bff6bf --- /dev/null +++ b/test/static_assert_same.hpp @@ -0,0 +1,31 @@ +// Copyright David Abrahams 2003. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef STATIC_ASSERT_SAME_DWA2003530_HPP +# define STATIC_ASSERT_SAME_DWA2003530_HPP + +# include + +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +template +struct static_assert_same; + +template +struct static_assert_same +{ + enum { value = 1 }; +}; +#else +# include +# include +# include + +template +struct static_assert_same + : boost::mpl::if_,boost::mpl::true_,void>::type +{}; +#endif + +#endif // STATIC_ASSERT_SAME_DWA2003530_HPP diff --git a/test/unit_tests.cpp b/test/unit_tests.cpp index bd533a2..4887357 100755 --- a/test/unit_tests.cpp +++ b/test/unit_tests.cpp @@ -5,7 +5,7 @@ // to its suitability for any purpose. #include #include -#include +#include "static_assert_same.hpp" struct X { int a; }; @@ -30,25 +30,6 @@ void operator_arrow_test() take_xptr(Xiter(&x).operator->()); } -template -struct static_assert_same -#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION -{ - template - static int check(V, V); - enum { value = sizeof(check(boost::type(), boost::type())) }; -} -#endif -; - -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION -template -struct static_assert_same -{ - enum { value }; -}; -#endif - template struct static_assert_min_cat : static_assert_same< @@ -109,6 +90,8 @@ void category_test() test = static_assert_min_cat< std::output_iterator_tag,std::random_access_iterator_tag, std::output_iterator_tag >::value; + + (void)test; } int main()