File: counting_iterator_test.cpp

package info (click to toggle)
boost1.35 1.35.0-5
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 203,856 kB
  • ctags: 337,867
  • sloc: cpp: 938,683; xml: 56,847; ansic: 41,589; python: 18,999; sh: 11,566; makefile: 664; perl: 494; yacc: 456; asm: 353; csh: 6
file content (300 lines) | stat: -rw-r--r-- 9,381 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
// (C) Copyright David Abrahams 2001.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
//  See http://www.boost.org for most recent version including documentation.
//
// Revision History
// 16 Feb 2001  Added a missing const. Made the tests run (somewhat) with
//              plain MSVC again. (David Abrahams)
// 11 Feb 2001  #if 0'd out use of counting_iterator on non-numeric types in
//              MSVC without STLport, so that the other tests may proceed
//              (David Abrahams)
// 04 Feb 2001  Added use of iterator_tests.hpp (David Abrahams)
// 28 Jan 2001  Removed not_an_iterator detritus (David Abrahams)
// 24 Jan 2001  Initial revision (David Abrahams)

#include <boost/config.hpp>

#ifdef __BORLANDC__     // Borland mis-detects our custom iterators
# pragma warn -8091     // template argument ForwardIterator passed to '...' is a output iterator
# pragma warn -8071     // Conversion may lose significant digits (due to counting_iterator<char> += n).
#endif

#ifdef BOOST_MSVC
# pragma warning(disable:4786) // identifier truncated in debug info
#endif

#include <boost/detail/iterator.hpp>
#include <boost/iterator/counting_iterator.hpp>
#include <boost/iterator/new_iterator_tests.hpp>

#include <boost/next_prior.hpp>
#include <boost/mpl/if.hpp>
#include <boost/detail/iterator.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/limits.hpp>

#include <algorithm>
#include <climits>
#include <iterator>
#include <stdlib.h>
#ifndef __BORLANDC__
# include <boost/tuple/tuple.hpp>
#endif 
#include <vector>
#include <list>
#include <boost/detail/lightweight_test.hpp>
#ifndef BOOST_NO_SLIST
# ifdef BOOST_SLIST_HEADER
#   include BOOST_SLIST_HEADER
# else
# include <slist>
# endif
#endif


#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
template <class T>
struct signed_assert_nonnegative
{
    static void test(T x) { BOOST_TEST(x >= 0); }
};

template <class T>
struct unsigned_assert_nonnegative
{
    static void test(T x) {}
};

template <class T>
struct assert_nonnegative
  : boost::mpl::if_c<
        std::numeric_limits<T>::is_signed
      , signed_assert_nonnegative<T>
      , unsigned_assert_nonnegative<T>
    >::type
{
};
#endif

// Special tests for RandomAccess CountingIterators.
template <class CountingIterator, class Value>
void category_test(
    CountingIterator start,
    CountingIterator finish,
    Value,
    std::random_access_iterator_tag)
{
    typedef typename
        boost::detail::iterator_traits<CountingIterator>::difference_type
        difference_type;
    difference_type distance = boost::detail::distance(start, finish);

    // Pick a random position internal to the range
    difference_type offset = (unsigned)rand() % distance;
    
#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
    BOOST_TEST(offset >= 0);
#else 
    assert_nonnegative<difference_type>::test(offset);
#endif
    
    CountingIterator internal = start;
    std::advance(internal, offset);

    // Try some binary searches on the range to show that it's ordered
    BOOST_TEST(std::binary_search(start, finish, *internal));

    // #including tuple crashed borland, so I had to give up on tie().
    std::pair<CountingIterator,CountingIterator> xy(
        std::equal_range(start, finish, *internal));
    CountingIterator x = xy.first, y = xy.second;
    
    BOOST_TEST(boost::detail::distance(x, y) == 1);

    // Show that values outside the range can't be found
    BOOST_TEST(!std::binary_search(start, boost::prior(finish), *finish));

    // Do the generic random_access_iterator_test
    typedef typename CountingIterator::value_type value_type;
    std::vector<value_type> v;
    for (value_type z = *start; !(z == *finish); ++z)
        v.push_back(z);
    
    // Note that this test requires a that the first argument is
    // dereferenceable /and/ a valid iterator prior to the first argument
    boost::random_access_iterator_test(start, v.size(), v.begin());
}

// Special tests for bidirectional CountingIterators
template <class CountingIterator, class Value>
void category_test(CountingIterator start, Value v1, std::bidirectional_iterator_tag)
{
    Value v2 = v1;
    ++v2;

    // Note that this test requires a that the first argument is
    // dereferenceable /and/ a valid iterator prior to the first argument
    boost::bidirectional_iterator_test(start, v1, v2);
}

template <class CountingIterator, class Value>
void category_test(CountingIterator start, CountingIterator finish, Value v1, std::forward_iterator_tag)
{
    Value v2 = v1;
    ++v2;
    if (finish != start && finish != boost::next(start))
        boost::forward_readable_iterator_test(start, finish, v1, v2);
}

template <class CountingIterator, class Value>
void test_aux(CountingIterator start, CountingIterator finish, Value v1)
{
    typedef typename CountingIterator::iterator_category category;
    typedef typename CountingIterator::value_type value_type;

    // If it's a RandomAccessIterator we can do a few delicate tests
    category_test(start, finish, v1, category());

    // Okay, brute force...
    for (CountingIterator p = start
             ; p != finish && boost::next(p) != finish
             ; ++p)
    {
        BOOST_TEST(boost::next(*p) == *boost::next(p));
    }

    // prove that a reference can be formed to these values
    typedef typename CountingIterator::value_type value;
    const value* q = &*start;
    (void)q; // suppress unused variable warning
}

template <class Incrementable>
void test(Incrementable start, Incrementable finish)
{
    test_aux(boost::make_counting_iterator(start), boost::make_counting_iterator(finish), start);
}

template <class Integer>
void test_integer(Integer* = 0) // default arg works around MSVC bug
{
    Integer start = 0;
    Integer finish = 120;
    test(start, finish);
}

template <class Integer, class Category, class Difference>
void test_integer3(Integer* = 0, Category* = 0, Difference* = 0) // default arg works around MSVC bug
{
    Integer start = 0;
    Integer finish = 120;
    typedef boost::counting_iterator<Integer,Category,Difference> iterator;
    test_aux(iterator(start), iterator(finish), start);
}

template <class Container>
void test_container(Container* = 0)  // default arg works around MSVC bug
{
    Container c(1 + (unsigned)rand() % 1673);

    const typename Container::iterator start = c.begin();
    
    // back off by 1 to leave room for dereferenceable value at the end
    typename Container::iterator finish = start;
    std::advance(finish, c.size() - 1);
    
    test(start, finish);

    typedef typename Container::const_iterator const_iterator;
    test(const_iterator(start), const_iterator(finish));
}

class my_int1 {
public:
  my_int1() { }
  my_int1(int x) : m_int(x) { }
  my_int1& operator++() { ++m_int; return *this; }
  bool operator==(const my_int1& x) const { return m_int == x.m_int; }
private:
  int m_int;
};

class my_int2 {
public:
  typedef void value_type;
  typedef void pointer;
  typedef void reference;
  typedef std::ptrdiff_t difference_type;
  typedef std::bidirectional_iterator_tag iterator_category;

  my_int2() { }
  my_int2(int x) : m_int(x) { }
  my_int2& operator++() { ++m_int; return *this; }
  my_int2& operator--() { --m_int; return *this; }
  bool operator==(const my_int2& x) const { return m_int == x.m_int; }
private:
  int m_int;
};

class my_int3 {
public:
  typedef void value_type;
  typedef void pointer;
  typedef void reference;
  typedef std::ptrdiff_t difference_type;
  typedef std::random_access_iterator_tag iterator_category;

  my_int3() { }
  my_int3(int x) : m_int(x) { }
  my_int3& operator++() { ++m_int; return *this; }
  my_int3& operator+=(std::ptrdiff_t n) { m_int += n; return *this; }
  std::ptrdiff_t operator-(const my_int3& x) const { return m_int - x.m_int; }
  my_int3& operator--() { --m_int; return *this; }
  bool operator==(const my_int3& x) const { return m_int == x.m_int; }
  bool operator!=(const my_int3& x) const { return m_int != x.m_int; }
  bool operator<(const my_int3& x) const { return m_int < x.m_int; }
private:
  int m_int;
};

int main()
{
    // Test the built-in integer types.
    test_integer<char>();
    test_integer<unsigned char>();
    test_integer<signed char>();
    test_integer<wchar_t>();
    test_integer<short>();
    test_integer<unsigned short>();
    test_integer<int>();
    test_integer<unsigned int>();
    test_integer<long>();
    test_integer<unsigned long>();
#if defined(BOOST_HAS_LONG_LONG)
    test_integer< ::boost::long_long_type>();
    test_integer< ::boost::ulong_long_type>();
#endif

    // Test user-defined type.

    test_integer3<my_int1, std::forward_iterator_tag, int>();
    test_integer3<long, std::random_access_iterator_tag, int>();
    test_integer<my_int2>();
    test_integer<my_int3>();
    
   // Some tests on container iterators, to prove we handle a few different categories
    test_container<std::vector<int> >();
    test_container<std::list<int> >();
# ifndef BOOST_NO_SLIST
    test_container<BOOST_STD_EXTENSION_NAMESPACE::slist<int> >();
# endif
    
    // Also prove that we can handle raw pointers.
    int array[2000];
    test(boost::make_counting_iterator(array), boost::make_counting_iterator(array+2000-1));

    return boost::report_errors();
}