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(__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 | { |
128 | 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 | { |
138 | 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 | |
164 | counting_iterator() { } |
165 | |
166 | counting_iterator(counting_iterator const& rhs) : super_t(rhs.base()) {} |
167 | |
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 | |
185 | typename super_t::reference dereference() const |
186 | { |
187 | return this->base_reference(); |
188 | } |
189 | |
190 | template <class OtherIncrementable> |
191 | difference_type |
192 | 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> |
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 | |