Home | History | Annotate | Download | only in detail
      1 // Copyright David Abrahams 2003. Use, modification and distribution is
      2 // subject to the Boost Software License, Version 1.0. (See accompanying
      3 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
      4 #ifndef FACADE_ITERATOR_CATEGORY_DWA20031118_HPP
      5 # define FACADE_ITERATOR_CATEGORY_DWA20031118_HPP
      6 
      7 # include <boost/iterator/iterator_categories.hpp>
      8 
      9 # include <boost/mpl/or.hpp>  // used in iterator_tag inheritance logic
     10 # include <boost/mpl/and.hpp>
     11 # include <boost/mpl/if.hpp>
     12 # include <boost/mpl/eval_if.hpp>
     13 # include <boost/mpl/identity.hpp>
     14 # include <boost/mpl/assert.hpp>
     15 
     16 # include <boost/type_traits/is_same.hpp>
     17 # include <boost/type_traits/is_const.hpp>
     18 # include <boost/type_traits/is_reference.hpp>
     19 # include <boost/type_traits/is_convertible.hpp>
     20 
     21 # include <boost/type_traits/is_same.hpp>
     22 
     23 # include <boost/iterator/detail/config_def.hpp> // try to keep this last
     24 
     25 # ifdef BOOST_ITERATOR_REF_CONSTNESS_KILLS_WRITABILITY
     26 #  include <boost/detail/indirect_traits.hpp>
     27 # endif
     28 
     29 //
     30 // iterator_category deduction for iterator_facade
     31 //
     32 
     33 // forward declaration
     34 namespace boost { struct use_default; }
     35 
     36 namespace boost { namespace detail  {
     37 
     38 struct input_output_iterator_tag
     39   : std::input_iterator_tag
     40 {
     41     // Using inheritance for only input_iterator_tag helps to avoid
     42     // ambiguities when a stdlib implementation dispatches on a
     43     // function which is overloaded on both input_iterator_tag and
     44     // output_iterator_tag, as STLPort does, in its __valid_range
     45     // function.  I claim it's better to avoid the ambiguity in these
     46     // cases.
     47     operator std::output_iterator_tag() const
     48     {
     49         return std::output_iterator_tag();
     50     }
     51 };
     52 
     53 //
     54 // True iff the user has explicitly disabled writability of this
     55 // iterator.  Pass the iterator_facade's Value parameter and its
     56 // nested ::reference type.
     57 //
     58 template <class ValueParam, class Reference>
     59 struct iterator_writability_disabled
     60 # ifdef BOOST_ITERATOR_REF_CONSTNESS_KILLS_WRITABILITY // Adding Thomas' logic?
     61   : mpl::or_<
     62         is_const<Reference>
     63       , boost::detail::indirect_traits::is_reference_to_const<Reference>
     64       , is_const<ValueParam>
     65     >
     66 # else
     67   : is_const<ValueParam>
     68 # endif
     69 {};
     70 
     71 
     72 //
     73 // Convert an iterator_facade's traversal category, Value parameter,
     74 // and ::reference type to an appropriate old-style category.
     75 //
     76 // If writability has been disabled per the above metafunction, the
     77 // result will not be convertible to output_iterator_tag.
     78 //
     79 // Otherwise, if Traversal == single_pass_traversal_tag, the following
     80 // conditions will result in a tag that is convertible both to
     81 // input_iterator_tag and output_iterator_tag:
     82 //
     83 //    1. Reference is a reference to non-const
     84 //    2. Reference is not a reference and is convertible to Value
     85 //
     86 template <class Traversal, class ValueParam, class Reference>
     87 struct iterator_facade_default_category
     88   : mpl::eval_if<
     89         mpl::and_<
     90             is_reference<Reference>
     91           , is_convertible<Traversal,forward_traversal_tag>
     92         >
     93       , mpl::eval_if<
     94             is_convertible<Traversal,random_access_traversal_tag>
     95           , mpl::identity<std::random_access_iterator_tag>
     96           , mpl::if_<
     97                 is_convertible<Traversal,bidirectional_traversal_tag>
     98               , std::bidirectional_iterator_tag
     99               , std::forward_iterator_tag
    100             >
    101         >
    102       , typename mpl::eval_if<
    103             mpl::and_<
    104                 is_convertible<Traversal, single_pass_traversal_tag>
    105 
    106                 // check for readability
    107               , is_convertible<Reference, ValueParam>
    108             >
    109           , mpl::identity<std::input_iterator_tag>
    110           , mpl::identity<Traversal>
    111         >
    112     >
    113 {
    114 };
    115 
    116 // True iff T is convertible to an old-style iterator category.
    117 template <class T>
    118 struct is_iterator_category
    119   : mpl::or_<
    120         is_convertible<T,std::input_iterator_tag>
    121       , is_convertible<T,std::output_iterator_tag>
    122     >
    123 {
    124 };
    125 
    126 template <class T>
    127 struct is_iterator_traversal
    128   : is_convertible<T,incrementable_traversal_tag>
    129 {};
    130 
    131 //
    132 // A composite iterator_category tag convertible to Category (a pure
    133 // old-style category) and Traversal (a pure traversal tag).
    134 // Traversal must be a strict increase of the traversal power given by
    135 // Category.
    136 //
    137 template <class Category, class Traversal>
    138 struct iterator_category_with_traversal
    139   : Category, Traversal
    140 {
    141 # if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
    142     // Make sure this isn't used to build any categories where
    143     // convertibility to Traversal is redundant.  Should just use the
    144     // Category element in that case.
    145     BOOST_MPL_ASSERT_NOT((
    146         is_convertible<
    147               typename iterator_category_to_traversal<Category>::type
    148             , Traversal
    149           >));
    150 
    151     BOOST_MPL_ASSERT((is_iterator_category<Category>));
    152     BOOST_MPL_ASSERT_NOT((is_iterator_category<Traversal>));
    153     BOOST_MPL_ASSERT_NOT((is_iterator_traversal<Category>));
    154 #  if !BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1310))
    155     BOOST_MPL_ASSERT((is_iterator_traversal<Traversal>));
    156 #  endif
    157 # endif
    158 };
    159 
    160 // Computes an iterator_category tag whose traversal is Traversal and
    161 // which is appropriate for an iterator
    162 template <class Traversal, class ValueParam, class Reference>
    163 struct facade_iterator_category_impl
    164 {
    165 # if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
    166     BOOST_MPL_ASSERT_NOT((is_iterator_category<Traversal>));
    167 # endif
    168 
    169     typedef typename iterator_facade_default_category<
    170         Traversal,ValueParam,Reference
    171     >::type category;
    172 
    173     typedef typename mpl::if_<
    174         is_same<
    175             Traversal
    176           , typename iterator_category_to_traversal<category>::type
    177         >
    178       , category
    179       , iterator_category_with_traversal<category,Traversal>
    180     >::type type;
    181 };
    182 
    183 //
    184 // Compute an iterator_category for iterator_facade
    185 //
    186 template <class CategoryOrTraversal, class ValueParam, class Reference>
    187 struct facade_iterator_category
    188   : mpl::eval_if<
    189         is_iterator_category<CategoryOrTraversal>
    190       , mpl::identity<CategoryOrTraversal> // old-style categories are fine as-is
    191       , facade_iterator_category_impl<CategoryOrTraversal,ValueParam,Reference>
    192     >
    193 {
    194 };
    195 
    196 }} // namespace boost::detail
    197 
    198 # include <boost/iterator/detail/config_undef.hpp>
    199 
    200 #endif // FACADE_ITERATOR_CATEGORY_DWA20031118_HPP
    201