blob: b4d2efa877dd51e86f54dbdefc53c4e957aee6cd [file] [log] [blame]
Brian Silverman59623332018-08-04 23:36:56 -07001// 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
32namespace boost {
33
34 // use this for the value type
35struct dummyT {
36 dummyT() { }
37 dummyT(detail::dummy_constructor) { }
38 dummyT(int x) : m_x(x) { }
39 int foo() const { return m_x; }
40 bool operator==(const dummyT& d) const { return m_x == d.m_x; }
41 int m_x;
42};
43
44}
45
46namespace boost {
47namespace iterators {
48
49// Tests whether type Iterator satisfies the requirements for a
50// TrivialIterator.
51// Preconditions: i != j, *i == val
52template <class Iterator, class T>
53void 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
83template <class Iterator, class T>
84void 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
92template <class Iterator, class T>
93void 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
136template <bool is_pointer> struct lvalue_test
137{
138 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
155template <> struct lvalue_test<true> {
156 template <class T> static void check(T) {}
157};
158#endif
159
160template <class Iterator, class T>
161void 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(__BORLANDC__) || (__BORLANDC__ > 0x551)
184 lvalue_test<(boost::is_pointer<Iterator>::value)>::check(i);
185#endif
186}
187
188// Preconditions: *i == v1, *++i == v2
189template <class Iterator, class T>
190void 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
215template <class U> struct undefined;
216
217// Preconditions: [i,i+N) is a valid range
218template <class Iterator, class TrueVals>
219void 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
258template <class Iterator, class ConstIterator>
259void 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
276using iterators::undefined;
277using iterators::trivial_iterator_test;
278using iterators::mutable_trivial_iterator_test;
279using iterators::input_iterator_test;
280using iterators::lvalue_test;
281using iterators::forward_iterator_test;
282using iterators::bidirectional_iterator_test;
283using iterators::random_access_iterator_test;
284using iterators::const_nonconst_iterator_test;
285
286} // namespace boost
287
288#endif // BOOST_ITERATOR_TESTS_HPP