1 // Demonstrate and test boost/operators.hpp on std::iterators --------------//
2
3 // (C) Copyright Jeremy Siek 1999.
4 // Distributed under the Boost Software License, Version 1.0. (See
5 // accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
7
8 // See http://www.boost.org for most recent version including documentation.
9
10 // Revision History
11 // 29 May 01 Factored implementation, added comparison tests, use Test Tools
12 // library (Daryle Walker)
13 // 12 Dec 99 Initial version with iterator operators (Jeremy Siek)
14
15 #include <boost/core/lightweight_test.hpp>
16
17 #include <boost/config.hpp> // for BOOST_STATIC_CONSTANT
18 #include <boost/operators.hpp> // for boost::random_access_iterator_helper
19
20 #include <cstddef> // for std::ptrdiff_t, std::size_t
21 #include <cstring> // for std::strcmp
22 #include <iostream> // for std::cout (std::endl, ends, and flush indirectly)
23 #include <string> // for std::string
24 #include <sstream> // for std::stringstream
25
26 # ifdef BOOST_NO_STDC_NAMESPACE
27 namespace std { using ::strcmp; }
28 # endif
29
30
31 // Iterator test class
32 template <class T, class R, class P>
33 struct test_iter
34 : public boost::random_access_iterator_helper<
35 test_iter<T,R,P>, T, std::ptrdiff_t, P, R>
36 {
37 typedef test_iter self;
38 typedef R Reference;
39 typedef std::ptrdiff_t Distance;
40
41 public:
test_itertest_iter42 explicit test_iter(T* i =0) : _i(i) { }
test_itertest_iter43 test_iter(const self& x) : _i(x._i) { }
operator =test_iter44 self& operator=(const self& x) { _i = x._i; return *this; }
operator *test_iter45 Reference operator*() const { return *_i; }
operator ++test_iter46 self& operator++() { ++_i; return *this; }
operator --test_iter47 self& operator--() { --_i; return *this; }
operator +=test_iter48 self& operator+=(Distance n) { _i += n; return *this; }
operator -=test_iter49 self& operator-=(Distance n) { _i -= n; return *this; }
operator ==test_iter50 bool operator==(const self& x) const { return _i == x._i; }
operator <test_iter51 bool operator<(const self& x) const { return _i < x._i; }
operator -(const self & x,const self & y)52 friend Distance operator-(const self& x, const self& y) {
53 return x._i - y._i;
54 }
55 protected:
56 P _i;
57 };
58
59 // Iterator operator testing classes
60 class test_opr_base
61 {
62 protected:
63 // Test data and types
64 BOOST_STATIC_CONSTANT( std::size_t, fruit_length = 6u );
65
66 typedef std::string fruit_array_type[ fruit_length ];
67
68 static fruit_array_type fruit;
69
70 }; // test_opr_base
71
72 #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
73 // A definition is required even for integral static constants
74 const std::size_t test_opr_base::fruit_length;
75 #endif
76
77 template <typename T, typename R = T&, typename P = T*>
78 class test_opr
79 : public test_opr_base
80 {
81 typedef test_opr<T, R, P> self_type;
82
83 public:
84 // Types
85 typedef T value_type;
86 typedef R reference;
87 typedef P pointer;
88
89 typedef test_iter<T, R, P> iter_type;
90
91 // Test controller
92 static void master_test( char const name[] );
93
94 private:
95 // Test data
96 static iter_type const fruit_begin;
97 static iter_type const fruit_end;
98
99 // Test parts
100 static void post_increment_test();
101 static void post_decrement_test();
102 static void indirect_referral_test();
103 static void offset_addition_test();
104 static void reverse_offset_addition_test();
105 static void offset_subtraction_test();
106 static void comparison_test();
107 static void indexing_test();
108
109 }; // test_opr
110
111
112 // Class-static data definitions
113 test_opr_base::fruit_array_type
114 test_opr_base::fruit = { "apple", "orange", "pear", "peach", "grape", "plum" };
115
116 template <typename T, typename R, typename P>
117 typename test_opr<T, R, P>::iter_type const
118 test_opr<T, R, P>::fruit_begin = test_iter<T,R,P>( fruit );
119
120 template <typename T, typename R, typename P>
121 typename test_opr<T, R, P>::iter_type const
122 test_opr<T, R, P>::fruit_end = test_iter<T,R,P>( fruit + fruit_length );
123
124
125 // Main testing function
126 int
main()127 main()
128 {
129 using std::string;
130
131 typedef test_opr<string, string &, string *> test1_type;
132 typedef test_opr<string, string const &, string const *> test2_type;
133
134 test1_type::master_test( "non-const string" );
135 test2_type::master_test( "const string" );
136
137 return boost::report_errors();
138 }
139
140 // Tests for all of the operators added by random_access_iterator_helper
141 template <typename T, typename R, typename P>
142 void
master_test(char const name[])143 test_opr<T, R, P>::master_test
144 (
145 char const name[]
146 )
147 {
148 std::cout << "Doing test run for " << name << '.' << std::endl;
149
150 post_increment_test();
151 post_decrement_test();
152 indirect_referral_test();
153 offset_addition_test();
154 reverse_offset_addition_test();
155 offset_subtraction_test();
156 comparison_test();
157 indexing_test();
158 }
159
160 // Test post-increment
161 template <typename T, typename R, typename P>
162 void
post_increment_test()163 test_opr<T, R, P>::post_increment_test
164 (
165 )
166 {
167 std::cout << "\tDoing post-increment test." << std::endl;
168
169 std::stringstream oss;
170 for ( iter_type i = fruit_begin ; i != fruit_end ; )
171 {
172 oss << *i++ << ' ';
173 }
174
175 BOOST_TEST( oss.str() == "apple orange pear peach grape plum ");
176 }
177
178 // Test post-decrement
179 template <typename T, typename R, typename P>
180 void
post_decrement_test()181 test_opr<T, R, P>::post_decrement_test
182 (
183 )
184 {
185 std::cout << "\tDoing post-decrement test." << std::endl;
186
187 std::stringstream oss;
188 for ( iter_type i = fruit_end ; i != fruit_begin ; )
189 {
190 i--;
191 oss << *i << ' ';
192 }
193
194 BOOST_TEST( oss.str() == "plum grape peach pear orange apple ");
195 }
196
197 // Test indirect structure referral
198 template <typename T, typename R, typename P>
199 void
indirect_referral_test()200 test_opr<T, R, P>::indirect_referral_test
201 (
202 )
203 {
204 std::cout << "\tDoing indirect reference test." << std::endl;
205
206 std::stringstream oss;
207 for ( iter_type i = fruit_begin ; i != fruit_end ; ++i )
208 {
209 oss << i->size() << ' ';
210 }
211
212 BOOST_TEST( oss.str() == "5 6 4 5 5 4 ");
213 }
214
215 // Test offset addition
216 template <typename T, typename R, typename P>
217 void
offset_addition_test()218 test_opr<T, R, P>::offset_addition_test
219 (
220 )
221 {
222 std::cout << "\tDoing offset addition test." << std::endl;
223
224 std::ptrdiff_t const two = 2;
225 std::stringstream oss;
226 for ( iter_type i = fruit_begin ; i != fruit_end ; i = i + two )
227 {
228 oss << *i << ' ';
229 }
230
231 BOOST_TEST( oss.str() == "apple pear grape ");
232 }
233
234 // Test offset addition, in reverse order
235 template <typename T, typename R, typename P>
236 void
reverse_offset_addition_test()237 test_opr<T, R, P>::reverse_offset_addition_test
238 (
239 )
240 {
241 std::cout << "\tDoing reverse offset addition test." << std::endl;
242
243 std::ptrdiff_t const two = 2;
244 std::stringstream oss;
245 for ( iter_type i = fruit_begin ; i != fruit_end ; i = two + i )
246 {
247 oss << *i << ' ';
248 }
249
250 BOOST_TEST( oss.str() == "apple pear grape ");
251 }
252
253 // Test offset subtraction
254 template <typename T, typename R, typename P>
255 void
offset_subtraction_test()256 test_opr<T, R, P>::offset_subtraction_test
257 (
258 )
259 {
260 std::cout << "\tDoing offset subtraction test." << std::endl;
261
262 std::ptrdiff_t const two = 2;
263 std::stringstream oss;
264 for ( iter_type i = fruit_end ; fruit_begin < i ; )
265 {
266 i = i - two;
267 if ( (fruit_begin < i) || (fruit_begin == i) )
268 {
269 oss << *i << ' ';
270 }
271 }
272
273 BOOST_TEST( oss.str() == "grape pear apple ");
274 }
275
276 // Test comparisons
277 template <typename T, typename R, typename P>
278 void
comparison_test()279 test_opr<T, R, P>::comparison_test
280 (
281 )
282 {
283 using std::cout;
284 using std::ptrdiff_t;
285
286 cout << "\tDoing comparison tests.\n\t\tPass:";
287
288 for ( iter_type i = fruit_begin ; i != fruit_end ; ++i )
289 {
290 ptrdiff_t const i_offset = i - fruit_begin;
291
292 cout << ' ' << *i << std::flush;
293 for ( iter_type j = fruit_begin ; j != fruit_end ; ++j )
294 {
295 ptrdiff_t const j_offset = j - fruit_begin;
296
297 BOOST_TEST( (i != j) == (i_offset != j_offset) );
298 BOOST_TEST( (i > j) == (i_offset > j_offset) );
299 BOOST_TEST( (i <= j) == (i_offset <= j_offset) );
300 BOOST_TEST( (i >= j) == (i_offset >= j_offset) );
301 }
302 }
303 cout << std::endl;
304 }
305
306 // Test indexing
307 template <typename T, typename R, typename P>
308 void
indexing_test()309 test_opr<T, R, P>::indexing_test
310 (
311 )
312 {
313 std::cout << "\tDoing indexing test." << std::endl;
314
315 std::stringstream oss;
316 for ( std::size_t k = 0u ; k < fruit_length ; ++k )
317 {
318 oss << fruit_begin[ k ] << ' ';
319 }
320
321 BOOST_TEST( oss.str() == "apple orange pear peach grape plum ");
322 }
323