1 // Copyright David Abrahams 2003.
2 // Distributed under the Boost Software License, Version 1.0. (See
3 // accompanying file LICENSE_1_0.txt or copy at
4 // http://www.boost.org/LICENSE_1_0.txt)
5 #ifndef COUNTING_ITERATOR_DWA200348_HPP
6 # define COUNTING_ITERATOR_DWA200348_HPP
7 
8 # include <boost/iterator/iterator_adaptor.hpp>
9 # include <boost/detail/numeric_traits.hpp>
10 # include <boost/mpl/bool.hpp>
11 # include <boost/mpl/if.hpp>
12 # include <boost/mpl/identity.hpp>
13 # include <boost/mpl/eval_if.hpp>
14 
15 namespace boost {
16 namespace iterators {
17 
18 template <
19     class Incrementable
20   , class CategoryOrTraversal
21   , class Difference
22 >
23 class counting_iterator;
24 
25 namespace detail
26 {
27   // Try to detect numeric types at compile time in ways compatible
28   // with the limitations of the compiler and library.
29   template <class T>
30   struct is_numeric_impl
31   {
32       // For a while, this wasn't true, but we rely on it below. This is a regression assert.
33       BOOST_STATIC_ASSERT(::boost::is_integral<char>::value);
34 
35 # ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
36 
37       BOOST_STATIC_CONSTANT(bool, value = std::numeric_limits<T>::is_specialized);
38 
39 # else
40 
41 #  if !BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x551))
42       BOOST_STATIC_CONSTANT(
43           bool, value = (
44               boost::is_convertible<int,T>::value
45            && boost::is_convertible<T,int>::value
46       ));
47 #  else
48     BOOST_STATIC_CONSTANT(bool, value = ::boost::is_arithmetic<T>::value);
49 #  endif
50 
51 # endif
52   };
53 
54   template <class T>
55   struct is_numeric
56     : mpl::bool_<(::boost::iterators::detail::is_numeric_impl<T>::value)>
57   {};
58 
59 #  if defined(BOOST_HAS_LONG_LONG)
60   template <>
61   struct is_numeric< ::boost::long_long_type>
62     : mpl::true_ {};
63 
64   template <>
65   struct is_numeric< ::boost::ulong_long_type>
66     : mpl::true_ {};
67 #  endif
68 
69   // Some compilers fail to have a numeric_limits specialization
70   template <>
71   struct is_numeric<wchar_t>
72     : mpl::true_ {};
73 
74   template <class T>
75   struct numeric_difference
76   {
77       typedef typename boost::detail::numeric_traits<T>::difference_type type;
78   };
79 
80   BOOST_STATIC_ASSERT(is_numeric<int>::value);
81 
82   template <class Incrementable, class CategoryOrTraversal, class Difference>
83   struct counting_iterator_base
84   {
85       typedef typename detail::ia_dflt_help<
86           CategoryOrTraversal
87         , mpl::eval_if<
88               is_numeric<Incrementable>
89             , mpl::identity<random_access_traversal_tag>
90             , iterator_traversal<Incrementable>
91           >
92       >::type traversal;
93 
94       typedef typename detail::ia_dflt_help<
95           Difference
96         , mpl::eval_if<
97               is_numeric<Incrementable>
98             , numeric_difference<Incrementable>
99             , iterator_difference<Incrementable>
100           >
101       >::type difference;
102 
103       typedef iterator_adaptor<
104           counting_iterator<Incrementable, CategoryOrTraversal, Difference> // self
105         , Incrementable                                           // Base
106         , Incrementable                                           // Value
107 # ifndef BOOST_ITERATOR_REF_CONSTNESS_KILLS_WRITABILITY
108           const  // MSVC won't strip this.  Instead we enable Thomas'
109                  // criterion (see boost/iterator/detail/facade_iterator_category.hpp)
110 # endif
111         , traversal
112         , Incrementable const&                                    // reference
113         , difference
114       > type;
115   };
116 
117   // Template class distance_policy_select -- choose a policy for computing the
118   // distance between counting_iterators at compile-time based on whether or not
119   // the iterator wraps an integer or an iterator, using "poor man's partial
120   // specialization".
121 
122   template <bool is_integer> struct distance_policy_select;
123 
124   // A policy for wrapped iterators
125   template <class Difference, class Incrementable1, class Incrementable2>
126   struct iterator_distance
127   {
distanceboost::iterators::detail::iterator_distance128       static Difference distance(Incrementable1 x, Incrementable2 y)
129       {
130           return y - x;
131       }
132   };
133 
134   // A policy for wrapped numbers
135   template <class Difference, class Incrementable1, class Incrementable2>
136   struct number_distance
137   {
distanceboost::iterators::detail::number_distance138       static Difference distance(Incrementable1 x, Incrementable2 y)
139       {
140           return boost::detail::numeric_distance(x, y);
141       }
142   };
143 }
144 
145 template <
146     class Incrementable
147   , class CategoryOrTraversal = use_default
148   , class Difference = use_default
149 >
150 class counting_iterator
151   : public detail::counting_iterator_base<
152         Incrementable, CategoryOrTraversal, Difference
153     >::type
154 {
155     typedef typename detail::counting_iterator_base<
156         Incrementable, CategoryOrTraversal, Difference
157     >::type super_t;
158 
159     friend class iterator_core_access;
160 
161  public:
162     typedef typename super_t::difference_type difference_type;
163 
counting_iterator()164     counting_iterator() { }
165 
counting_iterator(counting_iterator const & rhs)166     counting_iterator(counting_iterator const& rhs) : super_t(rhs.base()) {}
167 
counting_iterator(Incrementable x)168     counting_iterator(Incrementable x)
169       : super_t(x)
170     {
171     }
172 
173 # if 0
174     template<class OtherIncrementable>
175     counting_iterator(
176         counting_iterator<OtherIncrementable, CategoryOrTraversal, Difference> const& t
177       , typename enable_if_convertible<OtherIncrementable, Incrementable>::type* = 0
178     )
179       : super_t(t.base())
180     {}
181 # endif
182 
183  private:
184 
dereference() const185     typename super_t::reference dereference() const
186     {
187         return this->base_reference();
188     }
189 
190     template <class OtherIncrementable>
191     difference_type
distance_to(counting_iterator<OtherIncrementable,CategoryOrTraversal,Difference> const & y) const192     distance_to(counting_iterator<OtherIncrementable, CategoryOrTraversal, Difference> const& y) const
193     {
194       typedef typename mpl::if_<
195           detail::is_numeric<Incrementable>
196         , detail::number_distance<difference_type, Incrementable, OtherIncrementable>
197         , detail::iterator_distance<difference_type, Incrementable, OtherIncrementable>
198       >::type d;
199 
200       return d::distance(this->base(), y.base());
201     }
202 };
203 
204 // Manufacture a counting iterator for an arbitrary incrementable type
205 template <class Incrementable>
206 inline counting_iterator<Incrementable>
make_counting_iterator(Incrementable x)207 make_counting_iterator(Incrementable x)
208 {
209   typedef counting_iterator<Incrementable> result_t;
210   return result_t(x);
211 }
212 
213 } // namespace iterators
214 
215 using iterators::counting_iterator;
216 using iterators::make_counting_iterator;
217 
218 } // namespace boost
219 
220 #endif // COUNTING_ITERATOR_DWA200348_HPP
221