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