1 | // endian_operations_test.cpp --------------------------------------------------------// |
2 | |
3 | // Copyright Beman Dawes 2008 |
4 | |
5 | // Distributed under the Boost Software License, Version 1.0. (See accompanying |
6 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
7 | |
8 | // See library home page at http://www.boost.org/libs/endian |
9 | |
10 | //--------------------------------------------------------------------------------------// |
11 | |
12 | // This test probes operator overloading, including interaction between |
13 | // operand types. |
14 | |
15 | // See endian_test for tests of endianness correctness, size, and value. |
16 | |
17 | #include <boost/endian/detail/disable_warnings.hpp> |
18 | |
19 | #ifdef _MSC_VER |
20 | # pragma warning( disable : 4242 ) // conversion ..., possible loss of data |
21 | # pragma warning( disable : 4244 ) // conversion ..., possible loss of data |
22 | # pragma warning( disable : 4018 ) // signed/unsigned mismatch |
23 | # pragma warning( disable : 4365 ) // signed/unsigned mismatch |
24 | # pragma warning( disable : 4389 ) // signed/unsigned mismatch |
25 | #elif defined(__GNUC__) |
26 | # pragma GCC diagnostic ignored "-Wconversion" |
27 | #endif |
28 | |
29 | #include <boost/endian/arithmetic.hpp> |
30 | #include <boost/type_traits/is_signed.hpp> |
31 | #include <boost/core/lightweight_test.hpp> |
32 | #include <boost/cstdint.hpp> |
33 | #include <cassert> |
34 | #include <iostream> |
35 | #include <sstream> |
36 | |
37 | namespace be = boost::endian; |
38 | |
39 | template <class T> |
40 | struct value_type |
41 | { |
42 | typedef typename T::value_type type; |
43 | }; |
44 | |
45 | template<> struct value_type<char> { typedef char type; }; |
46 | template<> struct value_type<unsigned char> { typedef unsigned char type; }; |
47 | template<> struct value_type<signed char> { typedef signed char type; }; |
48 | template<> struct value_type<short> { typedef short type; }; |
49 | template<> struct value_type<unsigned short> { typedef unsigned short type; }; |
50 | template<> struct value_type<int> { typedef int type; }; |
51 | template<> struct value_type<unsigned int> { typedef unsigned int type; }; |
52 | template<> struct value_type<long> { typedef long type; }; |
53 | template<> struct value_type<unsigned long> { typedef unsigned long type; }; |
54 | template<> struct value_type<long long> { typedef long long type; }; |
55 | template<> struct value_type<unsigned long long> { typedef unsigned long long type; }; |
56 | |
57 | template <class T1, class T2> |
58 | struct default_construct |
59 | { |
60 | static void test() |
61 | { |
62 | T1 o1; |
63 | o1 = 1; // quiet warnings |
64 | if (o1) return; // quiet warnings |
65 | } |
66 | }; |
67 | |
68 | template <class T1, class T2> |
69 | struct construct |
70 | { |
71 | static void test() |
72 | { |
73 | T2 o2(1); |
74 | T1 o1(static_cast<T1>(o2)); |
75 | ++o1; // quiet gcc unused variable warning |
76 | } |
77 | }; |
78 | |
79 | template <class T1, class T2> |
80 | struct initialize |
81 | { |
82 | static void test() |
83 | { |
84 | T1 o2(2); |
85 | T1 o1 = o2; |
86 | ++o1; // quiet gcc unused variable warning |
87 | } |
88 | }; |
89 | |
90 | template <class T1, class T2> |
91 | struct assign |
92 | { |
93 | static void test() |
94 | { |
95 | T2 o2; |
96 | o2 = 1; |
97 | T1 o1; |
98 | o1 = o2; |
99 | if (o1) return; // quiet warnings |
100 | } |
101 | }; |
102 | |
103 | template <class T1, class T2, bool SameSignedness> |
104 | struct do_relational |
105 | { |
106 | static void test() |
107 | { |
108 | T1 o1(1); |
109 | T2 o2(2); |
110 | BOOST_TEST( !(o1 == o2) ); |
111 | BOOST_TEST( o1 != o2 ); |
112 | BOOST_TEST( o1 < o2 ); |
113 | BOOST_TEST( o1 <= o2 ); |
114 | BOOST_TEST( !(o1 > o2) ); |
115 | BOOST_TEST( !(o1 >= o2 ) ); |
116 | } |
117 | }; |
118 | |
119 | template <class T1, class T2> |
120 | struct do_relational<T1, T2, false> |
121 | { |
122 | static void test() |
123 | { |
124 | } |
125 | }; |
126 | |
127 | template <class T1, class T2> |
128 | struct relational |
129 | { |
130 | static void test() |
131 | { |
132 | do_relational<T1, T2, |
133 | boost::is_signed<typename value_type<T1>::type>::value |
134 | == boost::is_signed<typename value_type<T2>::type>::value |
135 | >::test(); |
136 | // do_relational<T1, T2, true>::test(); |
137 | } |
138 | }; |
139 | |
140 | template <class T1, class T2> |
141 | struct op_plus |
142 | { |
143 | static void test() |
144 | { |
145 | T1 o1(1); |
146 | T2 o2(2); |
147 | T1 o3; |
148 | |
149 | o3 = +o1; |
150 | |
151 | o3 = o1 + o2; |
152 | |
153 | o1 += o2; |
154 | |
155 | if (o3) return; // quiet warnings |
156 | } |
157 | }; |
158 | |
159 | template <class T1, class T2> |
160 | struct op_star |
161 | { |
162 | static void test() |
163 | { |
164 | T1 o1(1); |
165 | T2 o2(2); |
166 | T1 o3; |
167 | |
168 | o3 = o1 * o2; |
169 | |
170 | o1 *= o2; |
171 | |
172 | if (o3) return; // quiet warnings |
173 | } |
174 | }; |
175 | |
176 | template <template<class, class> class Test, class T1> |
177 | void op_test_aux() |
178 | { |
179 | Test<T1, char>::test(); |
180 | Test<T1, unsigned char>::test(); |
181 | Test<T1, signed char>::test(); |
182 | Test<T1, short>::test(); |
183 | Test<T1, unsigned short>::test(); |
184 | Test<T1, int>::test(); |
185 | Test<T1, unsigned int>::test(); |
186 | Test<T1, long>::test(); |
187 | Test<T1, unsigned long>::test(); |
188 | Test<T1, long long>::test(); |
189 | Test<T1, unsigned long long>::test(); |
190 | Test<T1, be::big_int16_at>::test(); |
191 | Test<T1, be::big_int32_at>::test(); |
192 | Test<T1, be::big_int64_at>::test(); |
193 | Test<T1, be::big_uint16_at>::test(); |
194 | Test<T1, be::big_uint32_at>::test(); |
195 | Test<T1, be::big_uint64_at>::test(); |
196 | Test<T1, be::little_int16_at>::test(); |
197 | Test<T1, be::little_int32_at>::test(); |
198 | Test<T1, be::little_int64_at>::test(); |
199 | Test<T1, be::little_uint16_at>::test(); |
200 | Test<T1, be::little_uint32_at>::test(); |
201 | Test<T1, be::little_uint64_at>::test(); |
202 | Test<T1, be::big_int8_t>::test(); |
203 | Test<T1, be::big_int16_t>::test(); |
204 | Test<T1, be::big_int24_t>::test(); |
205 | Test<T1, be::big_int32_t>::test(); |
206 | Test<T1, be::big_int40_t>::test(); |
207 | Test<T1, be::big_int48_t>::test(); |
208 | Test<T1, be::big_int56_t>::test(); |
209 | Test<T1, be::big_int64_t>::test(); |
210 | Test<T1, be::big_uint8_t>::test(); |
211 | Test<T1, be::big_uint16_t>::test(); |
212 | Test<T1, be::big_uint24_t>::test(); |
213 | Test<T1, be::big_uint32_t>::test(); |
214 | Test<T1, be::big_uint40_t>::test(); |
215 | Test<T1, be::big_uint64_t>::test(); |
216 | Test<T1, be::little_int16_t>::test(); |
217 | Test<T1, be::little_int24_t>::test(); |
218 | Test<T1, be::little_int32_t>::test(); |
219 | Test<T1, be::little_int64_t>::test(); |
220 | Test<T1, be::little_uint16_t>::test(); |
221 | Test<T1, be::little_uint32_t>::test(); |
222 | Test<T1, be::little_uint56_t>::test(); |
223 | Test<T1, be::little_uint64_t>::test(); |
224 | Test<T1, be::native_int16_t>::test(); |
225 | Test<T1, be::native_int24_t>::test(); |
226 | Test<T1, be::native_int32_t>::test(); |
227 | Test<T1, be::native_int64_t>::test(); |
228 | #ifdef BOOST_LONG_ENDIAN_TEST |
229 | Test<T1, be::native_uint16_t>::test(); |
230 | Test<T1, be::native_uint24_t>::test(); |
231 | Test<T1, be::native_uint32_t>::test(); |
232 | Test<T1, be::native_uint48_t>::test(); |
233 | Test<T1, be::native_uint64_t>::test(); |
234 | Test<T1, be::big_uint48_t>::test(); |
235 | Test<T1, be::big_uint56_t>::test(); |
236 | Test<T1, be::little_int8_t>::test(); |
237 | Test<T1, be::little_int56_t>::test(); |
238 | Test<T1, be::little_int40_t>::test(); |
239 | Test<T1, be::little_int48_t>::test(); |
240 | Test<T1, be::little_uint8_t>::test(); |
241 | Test<T1, be::little_uint24_t>::test(); |
242 | Test<T1, be::little_uint40_t>::test(); |
243 | Test<T1, be::little_uint48_t>::test(); |
244 | Test<T1, be::native_int8_t>::test(); |
245 | Test<T1, be::native_int40_t>::test(); |
246 | Test<T1, be::native_int48_t>::test(); |
247 | Test<T1, be::native_int56_t>::test(); |
248 | Test<T1, be::native_uint8_t>::test(); |
249 | Test<T1, be::native_uint40_t>::test(); |
250 | Test<T1, be::native_uint56_t>::test(); |
251 | #endif |
252 | } |
253 | |
254 | template <template<class, class> class Test> |
255 | void op_test() |
256 | { |
257 | op_test_aux<Test, char>(); |
258 | op_test_aux<Test, unsigned char>(); |
259 | op_test_aux<Test, signed char>(); |
260 | op_test_aux<Test, short>(); |
261 | op_test_aux<Test, unsigned short>(); |
262 | op_test_aux<Test, int>(); |
263 | op_test_aux<Test, unsigned int>(); |
264 | op_test_aux<Test, long>(); |
265 | op_test_aux<Test, unsigned long>(); |
266 | op_test_aux<Test, long long>(); |
267 | op_test_aux<Test, unsigned long long>(); |
268 | op_test_aux<Test, be::big_int16_at>(); |
269 | op_test_aux<Test, be::big_int32_at>(); |
270 | op_test_aux<Test, be::big_int64_at>(); |
271 | op_test_aux<Test, be::little_int16_at>(); |
272 | op_test_aux<Test, be::little_int32_at>(); |
273 | op_test_aux<Test, be::little_int64_at>(); |
274 | #ifdef BOOST_LONG_ENDIAN_TEST |
275 | op_test_aux<Test, be::big_int8_t>(); |
276 | op_test_aux<Test, be::big_int16_t>(); |
277 | op_test_aux<Test, be::big_int24_t>(); |
278 | op_test_aux<Test, be::big_int32_t>(); |
279 | op_test_aux<Test, be::big_int40_t>(); |
280 | op_test_aux<Test, be::big_int48_t>(); |
281 | op_test_aux<Test, be::big_int56_t>(); |
282 | op_test_aux<Test, be::big_int64_t>(); |
283 | op_test_aux<Test, be::big_uint8_t>(); |
284 | op_test_aux<Test, be::big_uint16_t>(); |
285 | op_test_aux<Test, be::big_uint24_t>(); |
286 | op_test_aux<Test, be::big_uint32_t>(); |
287 | op_test_aux<Test, be::big_uint40_t>(); |
288 | op_test_aux<Test, be::big_uint48_t>(); |
289 | op_test_aux<Test, be::big_uint56_t>(); |
290 | op_test_aux<Test, be::big_uint64_t>(); |
291 | op_test_aux<Test, be::little_int8_t>(); |
292 | op_test_aux<Test, be::little_int16_t>(); |
293 | op_test_aux<Test, be::little_int24_t>(); |
294 | op_test_aux<Test, be::little_int32_t>(); |
295 | op_test_aux<Test, be::little_int40_t>(); |
296 | op_test_aux<Test, be::little_int48_t>(); |
297 | op_test_aux<Test, be::little_int56_t>(); |
298 | op_test_aux<Test, be::little_int64_t>(); |
299 | op_test_aux<Test, be::little_uint8_t>(); |
300 | op_test_aux<Test, be::little_uint16_t>(); |
301 | op_test_aux<Test, be::little_uint24_t>(); |
302 | op_test_aux<Test, be::little_uint32_t>(); |
303 | op_test_aux<Test, be::little_uint40_t>(); |
304 | op_test_aux<Test, be::little_uint48_t>(); |
305 | op_test_aux<Test, be::little_uint56_t>(); |
306 | op_test_aux<Test, be::little_uint64_t>(); |
307 | op_test_aux<Test, be::native_int8_t>(); |
308 | op_test_aux<Test, be::native_int16_t>(); |
309 | op_test_aux<Test, be::native_int24_t>(); |
310 | op_test_aux<Test, be::native_int32_t>(); |
311 | op_test_aux<Test, be::native_int40_t>(); |
312 | op_test_aux<Test, be::native_int48_t>(); |
313 | op_test_aux<Test, be::native_int56_t>(); |
314 | op_test_aux<Test, be::native_int64_t>(); |
315 | op_test_aux<Test, be::native_uint8_t>(); |
316 | op_test_aux<Test, be::native_uint16_t>(); |
317 | op_test_aux<Test, be::native_uint24_t>(); |
318 | op_test_aux<Test, be::native_uint32_t>(); |
319 | op_test_aux<Test, be::native_uint40_t>(); |
320 | op_test_aux<Test, be::native_uint48_t>(); |
321 | op_test_aux<Test, be::native_uint56_t>(); |
322 | op_test_aux<Test, be::native_uint64_t>(); |
323 | #endif |
324 | } |
325 | |
326 | // test_inserter_and_extractor -----------------------------------------------------// |
327 | |
328 | void test_inserter_and_extractor() |
329 | { |
330 | std::cout << "test inserter and extractor..." << std::endl; |
331 | |
332 | be::big_uint64_t bu64(0x010203040506070ULL); |
333 | be::little_uint64_t lu64(0x010203040506070ULL); |
334 | |
335 | boost::uint64_t x; |
336 | |
337 | std::stringstream ss; |
338 | |
339 | ss << bu64; |
340 | ss >> x; |
341 | BOOST_TEST_EQ(x, 0x010203040506070ULL); |
342 | |
343 | ss.clear(); |
344 | ss << lu64; |
345 | ss >> x; |
346 | BOOST_TEST_EQ(x, 0x010203040506070ULL); |
347 | |
348 | ss.clear(); |
349 | ss << 0x010203040506070ULL; |
350 | be::big_uint64_t bu64z(0); |
351 | ss >> bu64z; |
352 | BOOST_TEST_EQ(bu64z, bu64); |
353 | |
354 | ss.clear(); |
355 | ss << 0x010203040506070ULL; |
356 | be::little_uint64_t lu64z(0); |
357 | ss >> lu64z; |
358 | BOOST_TEST_EQ(lu64z, lu64); |
359 | |
360 | std::cout << "test inserter and extractor complete" << std::endl; |
361 | |
362 | } |
363 | |
364 | void f_big_int32_ut(be::big_int32_t) {} |
365 | |
366 | // main ------------------------------------------------------------------------------// |
367 | |
368 | int cpp_main(int, char * []) |
369 | { |
370 | // make sure some simple things work |
371 | |
372 | be::big_int32_t o1(1); |
373 | be::big_int32_t o2(2L); |
374 | be::big_int32_t o3(3LL); |
375 | be::big_int64_t o4(1); |
376 | |
377 | std::clog << "set up test values\n" ; |
378 | be::big_int32_t big(12345); |
379 | be::little_uint16_t little_u(10); |
380 | be::big_int64_t result; |
381 | |
382 | // this is the use case that is so irritating that it caused the endian |
383 | // constructors to be made non-explicit |
384 | std::clog << "\nf(1234) where f(big_int32_t)\n" ; |
385 | f_big_int32_ut(1234); |
386 | |
387 | std::clog << "\nresult = big\n" ; |
388 | result = big; |
389 | |
390 | std::clog << "\nresult = +big\n" ; |
391 | result = +big; |
392 | |
393 | std::clog << "\nresult = -big\n" ; |
394 | result = -big; |
395 | |
396 | std::clog << "\n++big\n" ; |
397 | ++big; |
398 | |
399 | std::clog << "\nresult = big++\n" ; |
400 | result = big++; |
401 | |
402 | std::clog << "\n--big\n" ; |
403 | --big; |
404 | |
405 | std::clog << "\nbig--\n" ; |
406 | big--; |
407 | |
408 | std::clog << "\nresult = big * big\n" ; |
409 | result = big * big; |
410 | |
411 | std::clog << "\nresult = big * big\n" ; |
412 | result = big * big; |
413 | |
414 | std::clog << "\nresult = big * little_u\n" ; |
415 | result = big * little_u; |
416 | |
417 | std::clog << "\nbig *= little_u\n" ; |
418 | big *= little_u; |
419 | |
420 | std::clog << "\nresult = little_u * big\n" ; |
421 | result = little_u * big; |
422 | |
423 | std::clog << "\nresult = big * 5\n" ; |
424 | result = big * 5; |
425 | |
426 | std::clog << "\nbig *= 5\n" ; |
427 | big *= 5; |
428 | |
429 | std::clog << "\nresult = 5 * big\n" ; |
430 | result = 5 * big; |
431 | |
432 | std::clog << "\nresult = little_u * 5\n" ; |
433 | result = little_u * 5; |
434 | |
435 | std::clog << "\nresult = 5 * little_u\n" ; |
436 | result = 5 * little_u; |
437 | |
438 | std::clog << "\nresult = 5 * 10\n" ; |
439 | result = 5 * 10; |
440 | std::clog << "\n" ; |
441 | |
442 | // test from Roland Schwarz that detected ambiguities; these ambiguities |
443 | // were eliminated by BOOST_ENDIAN_MINIMAL_COVER_OPERATORS |
444 | unsigned u; |
445 | be::little_uint32_t u1; |
446 | be::little_uint32_t u2; |
447 | |
448 | u = 9; |
449 | u1 = 1; |
450 | std::clog << "\nu2 = u1 + u\n" ; |
451 | u2 = u1 + u; |
452 | std::clog << "\n" ; |
453 | |
454 | // variations to detect ambiguities |
455 | |
456 | be::little_uint32_t u3 = u1 + 5; |
457 | u3 = u1 + 5u; |
458 | |
459 | if (u1 == 5) |
460 | {} |
461 | if (u1 == 5u) |
462 | {} |
463 | |
464 | u1 += 5; |
465 | u1 += 5u; |
466 | |
467 | u2 = u1 + 5; |
468 | u2 = u1 + 5u; |
469 | |
470 | // one more wrinkle |
471 | be::little_uint16_t u4(3); |
472 | u4 = 3; |
473 | std::clog << "\nu2 = u1 + u4\n" ; |
474 | u2 = u1 + u4; |
475 | std::clog << "\n" ; |
476 | |
477 | test_inserter_and_extractor(); |
478 | |
479 | // perform the indicated test on ~60*60 operand types |
480 | |
481 | op_test<default_construct>(); |
482 | op_test<construct>(); // includes copy construction |
483 | op_test<initialize>(); |
484 | op_test<assign>(); |
485 | op_test<relational>(); |
486 | op_test<op_plus>(); |
487 | op_test<op_star>(); |
488 | |
489 | return boost::report_errors(); |
490 | } |
491 | |
492 | int main( int argc, char* argv[] ) |
493 | { |
494 | try |
495 | { |
496 | return cpp_main( argc, argv ); |
497 | } |
498 | catch( std::exception const & x ) |
499 | { |
500 | BOOST_ERROR( x.what() ); |
501 | return boost::report_errors(); |
502 | } |
503 | } |
504 | |