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