1 // Copyright David Abrahams and Jeremy Siek 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 BOOST_ITERATOR_TESTS_HPP
6 # define BOOST_ITERATOR_TESTS_HPP
7
8 // This is meant to be the beginnings of a comprehensive, generic
9 // test suite for STL concepts such as iterators and containers.
10 //
11 // Revision History:
12 // 28 Apr 2002 Fixed input iterator requirements.
13 // For a == b a++ == b++ is no longer required.
14 // See 24.1.1/3 for details.
15 // (Thomas Witt)
16 // 08 Feb 2001 Fixed bidirectional iterator test so that
17 // --i is no longer a precondition.
18 // (Jeremy Siek)
19 // 04 Feb 2001 Added lvalue test, corrected preconditions
20 // (David Abrahams)
21
22 # include <iterator>
23 # include <boost/static_assert.hpp>
24 # include <boost/concept_archetype.hpp> // for detail::dummy_constructor
25 # include <boost/implicit_cast.hpp>
26 # include <boost/core/ignore_unused.hpp>
27 # include <boost/core/lightweight_test.hpp>
28 # include <boost/type_traits/is_same.hpp>
29 # include <boost/type_traits/is_pointer.hpp>
30 # include <boost/type_traits/is_reference.hpp>
31
32 namespace boost {
33
34 // use this for the value type
35 struct dummyT {
dummyTboost::dummyT36 dummyT() { }
dummyTboost::dummyT37 dummyT(detail::dummy_constructor) { }
dummyTboost::dummyT38 dummyT(int x) : m_x(x) { }
fooboost::dummyT39 int foo() const { return m_x; }
operator ==boost::dummyT40 bool operator==(const dummyT& d) const { return m_x == d.m_x; }
41 int m_x;
42 };
43
44 }
45
46 namespace boost {
47 namespace iterators {
48
49 // Tests whether type Iterator satisfies the requirements for a
50 // TrivialIterator.
51 // Preconditions: i != j, *i == val
52 template <class Iterator, class T>
trivial_iterator_test(const Iterator i,const Iterator j,T val)53 void trivial_iterator_test(const Iterator i, const Iterator j, T val)
54 {
55 Iterator k;
56 BOOST_TEST(i == i);
57 BOOST_TEST(j == j);
58 BOOST_TEST(i != j);
59 #ifdef BOOST_NO_STD_ITERATOR_TRAITS
60 T v = *i;
61 #else
62 typename std::iterator_traits<Iterator>::value_type v = *i;
63 #endif
64 BOOST_TEST(v == val);
65 boost::ignore_unused(v);
66 #if 0
67 // hmm, this will give a warning for transform_iterator... perhaps
68 // this should be separated out into a stand-alone test since there
69 // are several situations where it can't be used, like for
70 // integer_range::iterator.
71 BOOST_TEST(v == i->foo());
72 #endif
73 k = i;
74 BOOST_TEST(k == k);
75 BOOST_TEST(k == i);
76 BOOST_TEST(k != j);
77 BOOST_TEST(*k == val);
78 boost::ignore_unused(k);
79 }
80
81
82 // Preconditions: i != j
83 template <class Iterator, class T>
mutable_trivial_iterator_test(const Iterator i,const Iterator j,T val)84 void mutable_trivial_iterator_test(const Iterator i, const Iterator j, T val)
85 {
86 *i = val;
87 trivial_iterator_test(i, j, val);
88 }
89
90
91 // Preconditions: *i == v1, *++i == v2
92 template <class Iterator, class T>
input_iterator_test(Iterator i,T v1,T v2)93 void input_iterator_test(Iterator i, T v1, T v2)
94 {
95 Iterator i1(i);
96
97 BOOST_TEST(i == i1);
98 BOOST_TEST(!(i != i1));
99
100 // I can see no generic way to create an input iterator
101 // that is in the domain of== of i and != i.
102 // The following works for istream_iterator but is not
103 // guaranteed to work for arbitrary input iterators.
104 //
105 // Iterator i2;
106 //
107 // BOOST_TEST(i != i2);
108 // BOOST_TEST(!(i == i2));
109
110 BOOST_TEST(*i1 == v1);
111 BOOST_TEST(*i == v1);
112
113 // we cannot test for equivalence of (void)++i & (void)i++
114 // as i is only guaranteed to be single pass.
115 BOOST_TEST(*i++ == v1);
116 boost::ignore_unused(i1);
117
118 i1 = i;
119
120 BOOST_TEST(i == i1);
121 BOOST_TEST(!(i != i1));
122
123 BOOST_TEST(*i1 == v2);
124 BOOST_TEST(*i == v2);
125 boost::ignore_unused(i1);
126
127 // i is dereferencable, so it must be incrementable.
128 ++i;
129
130 // how to test for operator-> ?
131 }
132
133 // how to test output iterator?
134
135
136 template <bool is_pointer> struct lvalue_test
137 {
checkboost::iterators::lvalue_test138 template <class Iterator> static void check(Iterator)
139 {
140 # ifndef BOOST_NO_STD_ITERATOR_TRAITS
141 typedef typename std::iterator_traits<Iterator>::reference reference;
142 typedef typename std::iterator_traits<Iterator>::value_type value_type;
143 # else
144 typedef typename Iterator::reference reference;
145 typedef typename Iterator::value_type value_type;
146 # endif
147 BOOST_STATIC_ASSERT(boost::is_reference<reference>::value);
148 BOOST_STATIC_ASSERT((boost::is_same<reference,value_type&>::value
149 || boost::is_same<reference,const value_type&>::value
150 ));
151 }
152 };
153
154 # ifdef BOOST_NO_STD_ITERATOR_TRAITS
155 template <> struct lvalue_test<true> {
checkboost::iterators::lvalue_test156 template <class T> static void check(T) {}
157 };
158 #endif
159
160 template <class Iterator, class T>
forward_iterator_test(Iterator i,T v1,T v2)161 void forward_iterator_test(Iterator i, T v1, T v2)
162 {
163 input_iterator_test(i, v1, v2);
164
165 Iterator i1 = i, i2 = i;
166
167 BOOST_TEST(i == i1++);
168 BOOST_TEST(i != ++i2);
169
170 trivial_iterator_test(i, i1, v1);
171 trivial_iterator_test(i, i2, v1);
172
173 ++i;
174 BOOST_TEST(i == i1);
175 BOOST_TEST(i == i2);
176 ++i1;
177 ++i2;
178
179 trivial_iterator_test(i, i1, v2);
180 trivial_iterator_test(i, i2, v2);
181
182 // borland doesn't allow non-type template parameters
183 # if !defined(BOOST_BORLANDC) || (BOOST_BORLANDC > 0x551)
184 lvalue_test<(boost::is_pointer<Iterator>::value)>::check(i);
185 #endif
186 }
187
188 // Preconditions: *i == v1, *++i == v2
189 template <class Iterator, class T>
bidirectional_iterator_test(Iterator i,T v1,T v2)190 void bidirectional_iterator_test(Iterator i, T v1, T v2)
191 {
192 forward_iterator_test(i, v1, v2);
193 ++i;
194
195 Iterator i1 = i, i2 = i;
196
197 BOOST_TEST(i == i1--);
198 BOOST_TEST(i != --i2);
199
200 trivial_iterator_test(i, i1, v2);
201 trivial_iterator_test(i, i2, v2);
202
203 --i;
204 BOOST_TEST(i == i1);
205 BOOST_TEST(i == i2);
206 ++i1;
207 ++i2;
208
209 trivial_iterator_test(i, i1, v1);
210 trivial_iterator_test(i, i2, v1);
211 }
212
213 // mutable_bidirectional_iterator_test
214
215 template <class U> struct undefined;
216
217 // Preconditions: [i,i+N) is a valid range
218 template <class Iterator, class TrueVals>
random_access_iterator_test(Iterator i,int N,TrueVals vals)219 void random_access_iterator_test(Iterator i, int N, TrueVals vals)
220 {
221 bidirectional_iterator_test(i, vals[0], vals[1]);
222 const Iterator j = i;
223 int c;
224
225 typedef typename std::iterator_traits<Iterator>::value_type value_type;
226 boost::ignore_unused<value_type>();
227
228 for (c = 0; c < N-1; ++c) {
229 BOOST_TEST(i == j + c);
230 BOOST_TEST(*i == vals[c]);
231 BOOST_TEST(*i == boost::implicit_cast<value_type>(j[c]));
232 BOOST_TEST(*i == *(j + c));
233 BOOST_TEST(*i == *(c + j));
234 ++i;
235 BOOST_TEST(i > j);
236 BOOST_TEST(i >= j);
237 BOOST_TEST(j <= i);
238 BOOST_TEST(j < i);
239 }
240
241 Iterator k = j + N - 1;
242 for (c = 0; c < N-1; ++c) {
243 BOOST_TEST(i == k - c);
244 BOOST_TEST(*i == vals[N - 1 - c]);
245 BOOST_TEST(*i == boost::implicit_cast<value_type>(j[N - 1 - c]));
246 Iterator q = k - c;
247 boost::ignore_unused(q);
248 BOOST_TEST(*i == *q);
249 BOOST_TEST(i > j);
250 BOOST_TEST(i >= j);
251 BOOST_TEST(j <= i);
252 BOOST_TEST(j < i);
253 --i;
254 }
255 }
256
257 // Precondition: i != j
258 template <class Iterator, class ConstIterator>
const_nonconst_iterator_test(Iterator i,ConstIterator j)259 void const_nonconst_iterator_test(Iterator i, ConstIterator j)
260 {
261 BOOST_TEST(i != j);
262 BOOST_TEST(j != i);
263
264 ConstIterator k(i);
265 BOOST_TEST(k == i);
266 BOOST_TEST(i == k);
267
268 k = i;
269 BOOST_TEST(k == i);
270 BOOST_TEST(i == k);
271 boost::ignore_unused(k);
272 }
273
274 } // namespace iterators
275
276 using iterators::undefined;
277 using iterators::trivial_iterator_test;
278 using iterators::mutable_trivial_iterator_test;
279 using iterators::input_iterator_test;
280 using iterators::lvalue_test;
281 using iterators::forward_iterator_test;
282 using iterators::bidirectional_iterator_test;
283 using iterators::random_access_iterator_test;
284 using iterators::const_nonconst_iterator_test;
285
286 } // namespace boost
287
288 #endif // BOOST_ITERATOR_TESTS_HPP
289