]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // (C) Copyright David Abrahams 2001. |
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 | // | |
6 | // See http://www.boost.org for most recent version including documentation. | |
7 | // | |
8 | // Revision History | |
9 | // 16 Feb 2001 Added a missing const. Made the tests run (somewhat) with | |
10 | // plain MSVC again. (David Abrahams) | |
11 | // 11 Feb 2001 #if 0'd out use of counting_iterator on non-numeric types in | |
12 | // MSVC without STLport, so that the other tests may proceed | |
13 | // (David Abrahams) | |
14 | // 04 Feb 2001 Added use of iterator_tests.hpp (David Abrahams) | |
15 | // 28 Jan 2001 Removed not_an_iterator detritus (David Abrahams) | |
16 | // 24 Jan 2001 Initial revision (David Abrahams) | |
17 | ||
18 | #include <boost/config.hpp> | |
19 | ||
20effc67 | 20 | #ifdef BOOST_BORLANDC // Borland mis-detects our custom iterators |
7c673cae FG |
21 | # pragma warn -8091 // template argument ForwardIterator passed to '...' is a output iterator |
22 | # pragma warn -8071 // Conversion may lose significant digits (due to counting_iterator<char> += n). | |
23 | #endif | |
24 | ||
25 | #ifdef BOOST_MSVC | |
26 | # pragma warning(disable:4786) // identifier truncated in debug info | |
27 | #endif | |
28 | ||
7c673cae FG |
29 | #include <boost/iterator/counting_iterator.hpp> |
30 | #include <boost/iterator/new_iterator_tests.hpp> | |
31 | ||
32 | #include <boost/next_prior.hpp> | |
33 | #include <boost/mpl/if.hpp> | |
7c673cae FG |
34 | #include <boost/detail/workaround.hpp> |
35 | #include <boost/limits.hpp> | |
36 | ||
37 | #include <algorithm> | |
38 | #include <climits> | |
39 | #include <iterator> | |
40 | #include <stdlib.h> | |
20effc67 | 41 | #ifndef BOOST_BORLANDC |
7c673cae | 42 | # include <boost/tuple/tuple.hpp> |
f67539c2 | 43 | #endif |
7c673cae FG |
44 | #include <vector> |
45 | #include <list> | |
f67539c2 | 46 | #include <boost/core/lightweight_test.hpp> |
7c673cae FG |
47 | #ifndef BOOST_NO_SLIST |
48 | # ifdef BOOST_SLIST_HEADER | |
49 | # include BOOST_SLIST_HEADER | |
50 | # else | |
51 | # include <slist> | |
52 | # endif | |
53 | #endif | |
54 | ||
55 | ||
56 | #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS | |
57 | template <class T> | |
58 | struct signed_assert_nonnegative | |
59 | { | |
60 | static void test(T x) { BOOST_TEST(x >= 0); } | |
61 | }; | |
62 | ||
63 | template <class T> | |
64 | struct unsigned_assert_nonnegative | |
65 | { | |
66 | static void test(T x) {} | |
67 | }; | |
68 | ||
69 | template <class T> | |
70 | struct assert_nonnegative | |
71 | : boost::mpl::if_c< | |
72 | std::numeric_limits<T>::is_signed | |
73 | , signed_assert_nonnegative<T> | |
74 | , unsigned_assert_nonnegative<T> | |
75 | >::type | |
76 | { | |
77 | }; | |
78 | #endif | |
79 | ||
80 | // Special tests for RandomAccess CountingIterators. | |
81 | template <class CountingIterator, class Value> | |
82 | void category_test( | |
83 | CountingIterator start, | |
84 | CountingIterator finish, | |
85 | Value, | |
86 | std::random_access_iterator_tag) | |
87 | { | |
88 | typedef typename | |
20effc67 | 89 | std::iterator_traits<CountingIterator>::difference_type |
7c673cae | 90 | difference_type; |
20effc67 | 91 | difference_type distance = std::distance(start, finish); |
7c673cae FG |
92 | |
93 | // Pick a random position internal to the range | |
94 | difference_type offset = (unsigned)rand() % distance; | |
f67539c2 | 95 | |
7c673cae FG |
96 | #ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS |
97 | BOOST_TEST(offset >= 0); | |
f67539c2 | 98 | #else |
7c673cae FG |
99 | assert_nonnegative<difference_type>::test(offset); |
100 | #endif | |
f67539c2 | 101 | |
7c673cae FG |
102 | CountingIterator internal = start; |
103 | std::advance(internal, offset); | |
104 | ||
105 | // Try some binary searches on the range to show that it's ordered | |
106 | BOOST_TEST(std::binary_search(start, finish, *internal)); | |
107 | ||
108 | // #including tuple crashed borland, so I had to give up on tie(). | |
109 | std::pair<CountingIterator,CountingIterator> xy( | |
110 | std::equal_range(start, finish, *internal)); | |
111 | CountingIterator x = xy.first, y = xy.second; | |
f67539c2 | 112 | |
20effc67 | 113 | BOOST_TEST(std::distance(x, y) == 1); |
7c673cae FG |
114 | |
115 | // Show that values outside the range can't be found | |
116 | BOOST_TEST(!std::binary_search(start, boost::prior(finish), *finish)); | |
117 | ||
118 | // Do the generic random_access_iterator_test | |
119 | typedef typename CountingIterator::value_type value_type; | |
120 | std::vector<value_type> v; | |
121 | for (value_type z = *start; !(z == *finish); ++z) | |
122 | v.push_back(z); | |
f67539c2 | 123 | |
7c673cae FG |
124 | // Note that this test requires a that the first argument is |
125 | // dereferenceable /and/ a valid iterator prior to the first argument | |
126 | boost::random_access_iterator_test(start, v.size(), v.begin()); | |
127 | } | |
128 | ||
129 | // Special tests for bidirectional CountingIterators | |
130 | template <class CountingIterator, class Value> | |
131 | void category_test(CountingIterator start, Value v1, std::bidirectional_iterator_tag) | |
132 | { | |
133 | Value v2 = v1; | |
134 | ++v2; | |
135 | ||
136 | // Note that this test requires a that the first argument is | |
137 | // dereferenceable /and/ a valid iterator prior to the first argument | |
138 | boost::bidirectional_iterator_test(start, v1, v2); | |
139 | } | |
140 | ||
141 | template <class CountingIterator, class Value> | |
142 | void category_test(CountingIterator start, CountingIterator finish, Value v1, std::forward_iterator_tag) | |
143 | { | |
144 | Value v2 = v1; | |
145 | ++v2; | |
146 | if (finish != start && finish != boost::next(start)) | |
147 | boost::forward_readable_iterator_test(start, finish, v1, v2); | |
148 | } | |
149 | ||
150 | template <class CountingIterator, class Value> | |
151 | void test_aux(CountingIterator start, CountingIterator finish, Value v1) | |
152 | { | |
153 | typedef typename CountingIterator::iterator_category category; | |
7c673cae FG |
154 | |
155 | // If it's a RandomAccessIterator we can do a few delicate tests | |
156 | category_test(start, finish, v1, category()); | |
157 | ||
158 | // Okay, brute force... | |
159 | for (CountingIterator p = start | |
160 | ; p != finish && boost::next(p) != finish | |
161 | ; ++p) | |
162 | { | |
163 | BOOST_TEST(boost::next(*p) == *boost::next(p)); | |
164 | } | |
165 | ||
166 | // prove that a reference can be formed to these values | |
167 | typedef typename CountingIterator::value_type value; | |
168 | const value* q = &*start; | |
169 | (void)q; // suppress unused variable warning | |
170 | } | |
171 | ||
172 | template <class Incrementable> | |
173 | void test(Incrementable start, Incrementable finish) | |
174 | { | |
175 | test_aux(boost::make_counting_iterator(start), boost::make_counting_iterator(finish), start); | |
176 | } | |
177 | ||
178 | template <class Integer> | |
179 | void test_integer(Integer* = 0) // default arg works around MSVC bug | |
180 | { | |
181 | Integer start = 0; | |
182 | Integer finish = 120; | |
183 | test(start, finish); | |
184 | } | |
185 | ||
186 | template <class Integer, class Category, class Difference> | |
187 | void test_integer3(Integer* = 0, Category* = 0, Difference* = 0) // default arg works around MSVC bug | |
188 | { | |
189 | Integer start = 0; | |
190 | Integer finish = 120; | |
191 | typedef boost::counting_iterator<Integer,Category,Difference> iterator; | |
192 | test_aux(iterator(start), iterator(finish), start); | |
193 | } | |
194 | ||
195 | template <class Container> | |
196 | void test_container(Container* = 0) // default arg works around MSVC bug | |
197 | { | |
198 | Container c(1 + (unsigned)rand() % 1673); | |
199 | ||
200 | const typename Container::iterator start = c.begin(); | |
f67539c2 | 201 | |
7c673cae FG |
202 | // back off by 1 to leave room for dereferenceable value at the end |
203 | typename Container::iterator finish = start; | |
204 | std::advance(finish, c.size() - 1); | |
f67539c2 | 205 | |
7c673cae FG |
206 | test(start, finish); |
207 | ||
208 | typedef typename Container::const_iterator const_iterator; | |
209 | test(const_iterator(start), const_iterator(finish)); | |
210 | } | |
211 | ||
212 | class my_int1 { | |
213 | public: | |
214 | my_int1() { } | |
215 | my_int1(int x) : m_int(x) { } | |
216 | my_int1& operator++() { ++m_int; return *this; } | |
217 | bool operator==(const my_int1& x) const { return m_int == x.m_int; } | |
218 | private: | |
219 | int m_int; | |
220 | }; | |
221 | ||
222 | class my_int2 { | |
223 | public: | |
224 | typedef void value_type; | |
225 | typedef void pointer; | |
226 | typedef void reference; | |
227 | typedef std::ptrdiff_t difference_type; | |
228 | typedef std::bidirectional_iterator_tag iterator_category; | |
229 | ||
230 | my_int2() { } | |
231 | my_int2(int x) : m_int(x) { } | |
232 | my_int2& operator++() { ++m_int; return *this; } | |
233 | my_int2& operator--() { --m_int; return *this; } | |
234 | bool operator==(const my_int2& x) const { return m_int == x.m_int; } | |
235 | private: | |
236 | int m_int; | |
237 | }; | |
238 | ||
239 | class my_int3 { | |
240 | public: | |
241 | typedef void value_type; | |
242 | typedef void pointer; | |
243 | typedef void reference; | |
244 | typedef std::ptrdiff_t difference_type; | |
245 | typedef std::random_access_iterator_tag iterator_category; | |
246 | ||
247 | my_int3() { } | |
248 | my_int3(int x) : m_int(x) { } | |
249 | my_int3& operator++() { ++m_int; return *this; } | |
250 | my_int3& operator+=(std::ptrdiff_t n) { m_int += n; return *this; } | |
251 | std::ptrdiff_t operator-(const my_int3& x) const { return m_int - x.m_int; } | |
252 | my_int3& operator--() { --m_int; return *this; } | |
253 | bool operator==(const my_int3& x) const { return m_int == x.m_int; } | |
254 | bool operator!=(const my_int3& x) const { return m_int != x.m_int; } | |
255 | bool operator<(const my_int3& x) const { return m_int < x.m_int; } | |
256 | private: | |
257 | int m_int; | |
258 | }; | |
259 | ||
260 | int main() | |
261 | { | |
262 | // Test the built-in integer types. | |
263 | test_integer<char>(); | |
264 | test_integer<unsigned char>(); | |
265 | test_integer<signed char>(); | |
266 | test_integer<wchar_t>(); | |
267 | test_integer<short>(); | |
268 | test_integer<unsigned short>(); | |
269 | test_integer<int>(); | |
270 | test_integer<unsigned int>(); | |
271 | test_integer<long>(); | |
272 | test_integer<unsigned long>(); | |
273 | #if defined(BOOST_HAS_LONG_LONG) | |
274 | test_integer< ::boost::long_long_type>(); | |
275 | test_integer< ::boost::ulong_long_type>(); | |
276 | #endif | |
277 | ||
278 | // Test user-defined type. | |
279 | ||
280 | test_integer3<my_int1, std::forward_iterator_tag, int>(); | |
281 | test_integer3<long, std::random_access_iterator_tag, int>(); | |
282 | test_integer<my_int2>(); | |
283 | test_integer<my_int3>(); | |
f67539c2 | 284 | |
7c673cae FG |
285 | // Some tests on container iterators, to prove we handle a few different categories |
286 | test_container<std::vector<int> >(); | |
287 | test_container<std::list<int> >(); | |
288 | # ifndef BOOST_NO_SLIST | |
289 | test_container<BOOST_STD_EXTENSION_NAMESPACE::slist<int> >(); | |
290 | # endif | |
f67539c2 | 291 | |
7c673cae FG |
292 | // Also prove that we can handle raw pointers. |
293 | int array[2000]; | |
294 | test(boost::make_counting_iterator(array), boost::make_counting_iterator(array+2000-1)); | |
295 | ||
296 | return boost::report_errors(); | |
297 | } |