1 | // conversion_test.cpp ---------------------------------------------------------------// |
2 | |
3 | // Copyright Beman Dawes 2010 |
4 | |
5 | // Distributed under the Boost Software License, Version 1.0. |
6 | // See http://www.boost.org/LICENSE_1_0.txt |
7 | |
8 | //--------------------------------------------------------------------------------------// |
9 | |
10 | #if defined(_MSC_VER) |
11 | # pragma warning( disable: 4127 ) // conditional expression is constant |
12 | # if _MSC_VER < 1500 |
13 | # pragma warning( disable: 4267 ) // '+=': possible loss of data |
14 | # endif |
15 | #endif |
16 | |
17 | #include <boost/endian/detail/disable_warnings.hpp> |
18 | |
19 | #include <boost/endian/conversion.hpp> |
20 | #include <boost/core/lightweight_test.hpp> |
21 | #include <boost/type_traits/is_integral.hpp> |
22 | #include <boost/type_traits/make_unsigned.hpp> |
23 | #include <boost/static_assert.hpp> |
24 | #include <iostream> |
25 | #include <cstring> |
26 | #include <algorithm> |
27 | #include <cstddef> |
28 | |
29 | namespace be = boost::endian; |
30 | using std::cout; |
31 | using std::endl; |
32 | using std::int8_t; |
33 | using std::uint8_t; |
34 | using std::int16_t; |
35 | using std::uint16_t; |
36 | using std::int32_t; |
37 | using std::uint32_t; |
38 | using std::int64_t; |
39 | using std::uint64_t; |
40 | |
41 | template <class T> inline T std_endian_reverse(T x) BOOST_NOEXCEPT |
42 | { |
43 | T tmp(x); |
44 | std::reverse( first: reinterpret_cast<unsigned char*>(&tmp), last: reinterpret_cast<unsigned char*>(&tmp) + sizeof(T) ); |
45 | return tmp; |
46 | } |
47 | |
48 | namespace |
49 | { |
50 | |
51 | // values for tests |
52 | |
53 | static unsigned char const test_value_bytes[] = { 0xF1, 0x02, 0xE3, 0x04, 0xD5, 0x06, 0xC7, 0x08 }; |
54 | |
55 | template<class T> void native_value( T& x ) |
56 | { |
57 | BOOST_STATIC_ASSERT( boost::is_integral<T>::value && sizeof( T ) <= 8 ); |
58 | std::memcpy( dest: &x, src: test_value_bytes, n: sizeof( x ) ); |
59 | } |
60 | |
61 | template<class T> void little_value( T& x ) |
62 | { |
63 | BOOST_STATIC_ASSERT( boost::is_integral<T>::value && sizeof( T ) <= 8 ); |
64 | |
65 | typedef typename boost::make_unsigned<T>::type U; |
66 | |
67 | x = 0; |
68 | |
69 | for( std::size_t i = 0; i < sizeof( x ); ++i ) |
70 | { |
71 | x += static_cast<U>( test_value_bytes[ i ] ) << ( 8 * i ); |
72 | } |
73 | } |
74 | |
75 | template<class T> void big_value( T& x ) |
76 | { |
77 | BOOST_STATIC_ASSERT( boost::is_integral<T>::value && sizeof( T ) <= 8 ); |
78 | |
79 | typedef typename boost::make_unsigned<T>::type U; |
80 | |
81 | x = 0; |
82 | |
83 | for( std::size_t i = 0; i < sizeof( x ); ++i ) |
84 | { |
85 | x += static_cast<U>( test_value_bytes[ i ] ) << ( 8 * ( sizeof( x ) - i - 1 ) ); |
86 | } |
87 | } |
88 | |
89 | template <class T> |
90 | void test() |
91 | { |
92 | T native; |
93 | T big; |
94 | T little; |
95 | native_value(native); |
96 | big_value(big); |
97 | little_value(little); |
98 | |
99 | // validate the values used by the tests below |
100 | |
101 | if( be::order::native == be::order::big ) |
102 | { |
103 | BOOST_TEST_EQ(native, big); |
104 | BOOST_TEST_EQ(::std_endian_reverse(native), little); |
105 | } |
106 | else |
107 | { |
108 | BOOST_TEST_EQ(::std_endian_reverse(native), big); |
109 | BOOST_TEST_EQ(native, little); |
110 | } |
111 | |
112 | // value-by-value tests |
113 | |
114 | // unconditional reverse |
115 | BOOST_TEST_EQ(be::endian_reverse(big), little); |
116 | BOOST_TEST_EQ(be::endian_reverse(little), big); |
117 | |
118 | // conditional reverse |
119 | BOOST_TEST_EQ(be::native_to_big(native), big); |
120 | BOOST_TEST_EQ(be::native_to_little(native), little); |
121 | BOOST_TEST_EQ(be::big_to_native(big), native); |
122 | BOOST_TEST_EQ(be::little_to_native(little), native); |
123 | |
124 | // generic conditional reverse |
125 | BOOST_TEST_EQ((be::conditional_reverse<be::order::big, be::order::big>(big)), big); |
126 | BOOST_TEST_EQ((be::conditional_reverse<be::order::little, |
127 | be::order::little>(little)), little); |
128 | BOOST_TEST_EQ((be::conditional_reverse<be::order::native, |
129 | be::order::native>(native)), native); |
130 | BOOST_TEST_EQ((be::conditional_reverse<be::order::big, |
131 | be::order::little>(big)), little); |
132 | BOOST_TEST_EQ((be::conditional_reverse<be::order::big, |
133 | be::order::native>(big)), native); |
134 | BOOST_TEST_EQ((be::conditional_reverse<be::order::little, |
135 | be::order::big>(little)), big); |
136 | BOOST_TEST_EQ((be::conditional_reverse<be::order::little, |
137 | be::order::native>(little)), native); |
138 | BOOST_TEST_EQ((be::conditional_reverse<be::order::native, |
139 | be::order::big>(native)), big); |
140 | BOOST_TEST_EQ((be::conditional_reverse<be::order::native, |
141 | be::order::little>(native)), little); |
142 | |
143 | // runtime conditional reverse |
144 | BOOST_TEST_EQ((be::conditional_reverse(big, be::order::big, be::order::big)), |
145 | big); |
146 | BOOST_TEST_EQ((be::conditional_reverse(little, be::order::little, |
147 | be::order::little)), little); |
148 | BOOST_TEST_EQ((be::conditional_reverse(native, be::order::native, |
149 | be::order::native)), native); |
150 | BOOST_TEST_EQ((be::conditional_reverse(big, be::order::big, |
151 | be::order::little)), little); |
152 | BOOST_TEST_EQ((be::conditional_reverse(big, be::order::big, |
153 | be::order::native)), native); |
154 | BOOST_TEST_EQ((be::conditional_reverse(little, be::order::little, |
155 | be::order::big)), big); |
156 | BOOST_TEST_EQ((be::conditional_reverse(little, be::order::little, |
157 | be::order::native)), native); |
158 | BOOST_TEST_EQ((be::conditional_reverse(native, be::order::native, |
159 | be::order::big)), big); |
160 | BOOST_TEST_EQ((be::conditional_reverse(native, be::order::native, |
161 | be::order::little)), little); |
162 | |
163 | // modify-in-place tests |
164 | |
165 | T x; |
166 | |
167 | // unconditional reverse |
168 | x = big; be::endian_reverse_inplace(x); BOOST_TEST_EQ(x, little); |
169 | x = little; be::endian_reverse_inplace(x); BOOST_TEST_EQ(x, big); |
170 | |
171 | // conditional reverse |
172 | x = native; be::native_to_big_inplace(x); BOOST_TEST_EQ(x, big); |
173 | x = native; be::native_to_little_inplace(x); BOOST_TEST_EQ(x, little); |
174 | x = big; be::big_to_native_inplace(x); BOOST_TEST_EQ(x, native); |
175 | x = little; be::little_to_native_inplace(x); BOOST_TEST_EQ(x, native); |
176 | |
177 | // generic conditional reverse |
178 | x = big; be::conditional_reverse_inplace<be::order::big, be::order::big>(x); |
179 | BOOST_TEST_EQ(x, big); |
180 | x = little; be::conditional_reverse_inplace<be::order::little, be::order::little>(x); |
181 | BOOST_TEST_EQ(x, little); |
182 | x = native; be::conditional_reverse_inplace<be::order::native, be::order::native>(x); |
183 | BOOST_TEST_EQ(x, native); |
184 | x = big; be::conditional_reverse_inplace<be::order::big, be::order::little>(x); |
185 | BOOST_TEST_EQ(x, little); |
186 | x = big; be::conditional_reverse_inplace<be::order::big, be::order::native>(x); |
187 | BOOST_TEST_EQ(x, native); |
188 | x = little; be::conditional_reverse_inplace<be::order::little, be::order::big>(x); |
189 | BOOST_TEST_EQ(x, big); |
190 | x = little; be::conditional_reverse_inplace<be::order::little, be::order::native>(x); |
191 | BOOST_TEST_EQ(x, native); |
192 | x = native; be::conditional_reverse_inplace<be::order::native, be::order::big>(x); |
193 | BOOST_TEST_EQ(x, big); |
194 | x = native; be::conditional_reverse_inplace<be::order::native, be::order::little>(x); |
195 | BOOST_TEST_EQ(x, little); |
196 | |
197 | // runtime conditional reverse |
198 | x = big; |
199 | be::conditional_reverse_inplace(x, be::order::big, be::order::big); |
200 | BOOST_TEST_EQ(x, big); |
201 | x = little; |
202 | be::conditional_reverse_inplace(x, be::order::little, be::order::little); |
203 | BOOST_TEST_EQ(x, little); |
204 | x = native; |
205 | be::conditional_reverse_inplace(x, be::order::native, be::order::native); |
206 | BOOST_TEST_EQ(x, native); |
207 | x = big; |
208 | be::conditional_reverse_inplace(x, be::order::big, be::order::little); |
209 | BOOST_TEST_EQ(x, little); |
210 | x = big; |
211 | be::conditional_reverse_inplace(x, be::order::big, be::order::native); |
212 | BOOST_TEST_EQ(x, native); |
213 | x = little; |
214 | be::conditional_reverse_inplace(x, be::order::little, be::order::big); |
215 | BOOST_TEST_EQ(x, big); |
216 | x = little; |
217 | be::conditional_reverse_inplace(x, be::order::little, be::order::native); |
218 | BOOST_TEST_EQ(x, native); |
219 | x = native; |
220 | be::conditional_reverse_inplace(x, be::order::native, be::order::big); |
221 | BOOST_TEST_EQ(x, big); |
222 | x = native; |
223 | be::conditional_reverse_inplace(x, be::order::native, be::order::little); |
224 | BOOST_TEST_EQ(x, little); |
225 | |
226 | } |
227 | |
228 | //--------------------------------------------------------------------------------------// |
229 | |
230 | template <class UDT> |
231 | void udt_test() |
232 | { |
233 | UDT udt, tmp; |
234 | int64_t big; |
235 | int64_t little; |
236 | int64_t native; |
237 | big_value(x&: big); |
238 | little_value(x&: little); |
239 | native_value(x&: native); |
240 | |
241 | udt.member1 = big; |
242 | udt.member2 = little; |
243 | udt.member3 = native; |
244 | |
245 | tmp = be::conditional_reverse<be::order::big, be::order::little>(udt); |
246 | BOOST_TEST_EQ(tmp.member1, be::endian_reverse(big)); |
247 | BOOST_TEST_EQ(tmp.member2, be::endian_reverse(little)); |
248 | BOOST_TEST_EQ(tmp.member3, be::endian_reverse(native)); |
249 | |
250 | be::conditional_reverse_inplace<be::order::big, be::order::little>(udt); |
251 | BOOST_TEST_EQ(udt.member1, be::endian_reverse(big)); |
252 | BOOST_TEST_EQ(udt.member2, be::endian_reverse(little)); |
253 | BOOST_TEST_EQ(udt.member3, be::endian_reverse(native)); |
254 | |
255 | udt.member1 = big; |
256 | udt.member2 = little; |
257 | udt.member3 = native; |
258 | tmp.member1 = tmp.member2 = tmp.member3 = 0; |
259 | |
260 | tmp = be::conditional_reverse<be::order::big, be::order::big>(udt); |
261 | BOOST_TEST_EQ(tmp.member1, big); |
262 | BOOST_TEST_EQ(tmp.member2, little); |
263 | BOOST_TEST_EQ(tmp.member3, native); |
264 | |
265 | be::conditional_reverse_inplace<be::order::big, be::order::big>(udt); |
266 | BOOST_TEST_EQ(udt.member1, big); |
267 | BOOST_TEST_EQ(udt.member2, little); |
268 | BOOST_TEST_EQ(udt.member3, native); |
269 | } |
270 | } // unnamed namespace |
271 | |
272 | //--------------------------------------------------------------------------------------// |
273 | |
274 | // User-defined types |
275 | |
276 | namespace user |
277 | { |
278 | // UDT1 supplies both endian_reverse and endian_reverse_inplace |
279 | struct UDT1 |
280 | { |
281 | int64_t member1; |
282 | int64_t member2; |
283 | int64_t member3; |
284 | }; |
285 | |
286 | UDT1 endian_reverse(const UDT1& udt) BOOST_NOEXCEPT |
287 | { |
288 | UDT1 tmp; |
289 | tmp.member1 = boost::endian::endian_reverse(x: udt.member1); |
290 | tmp.member2 = boost::endian::endian_reverse(x: udt.member2); |
291 | tmp.member3 = boost::endian::endian_reverse(x: udt.member3); |
292 | return tmp; |
293 | } |
294 | |
295 | void endian_reverse_inplace(UDT1& udt) BOOST_NOEXCEPT |
296 | { |
297 | boost::endian::endian_reverse_inplace(x&: udt.member1); |
298 | boost::endian::endian_reverse_inplace(x&: udt.member2); |
299 | boost::endian::endian_reverse_inplace(x&: udt.member3); |
300 | } |
301 | |
302 | // UDT2 supplies only endian_reverse |
303 | struct UDT2 |
304 | { |
305 | int64_t member1; |
306 | int64_t member2; |
307 | int64_t member3; |
308 | }; |
309 | |
310 | UDT2 endian_reverse(const UDT2& udt) BOOST_NOEXCEPT |
311 | { |
312 | UDT2 tmp; |
313 | tmp.member1 = boost::endian::endian_reverse(x: udt.member1); |
314 | tmp.member2 = boost::endian::endian_reverse(x: udt.member2); |
315 | tmp.member3 = boost::endian::endian_reverse(x: udt.member3); |
316 | return tmp; |
317 | } |
318 | |
319 | // UDT3 supplies neither endian_reverse nor endian_reverse_inplace, |
320 | // so udt_test<UDT3>() should fail to compile |
321 | struct UDT3 |
322 | { |
323 | int64_t member1; |
324 | int64_t member2; |
325 | int64_t member3; |
326 | }; |
327 | |
328 | } // namespace user |
329 | |
330 | //--------------------------------------------------------------------------------------// |
331 | |
332 | int cpp_main(int, char * []) |
333 | { |
334 | if( be::order::native == be::order::little ) |
335 | { |
336 | cout << "Little endian" << endl; |
337 | } |
338 | else if( be::order::native == be::order::big ) |
339 | { |
340 | cout << "Big endian" << endl; |
341 | } |
342 | else |
343 | { |
344 | cout << "Unknown endian" << endl; |
345 | } |
346 | |
347 | cout << "byte swap intrinsics: " BOOST_ENDIAN_INTRINSIC_MSG << endl; |
348 | |
349 | //std::cerr << std::hex; |
350 | |
351 | cout << "int8_t" << endl; |
352 | test<int8_t>(); |
353 | cout << "uint8_t" << endl; |
354 | test<uint8_t>(); |
355 | |
356 | cout << "int16_t" << endl; |
357 | test<int16_t>(); |
358 | cout << "uint16_t" << endl; |
359 | test<uint16_t>(); |
360 | |
361 | cout << "int32_t" << endl; |
362 | test<int32_t>(); |
363 | cout << "uint32_t" << endl; |
364 | test<uint32_t>(); |
365 | |
366 | cout << "int64_t" << endl; |
367 | test<int64_t>(); |
368 | cout << "uint64_t" << endl; |
369 | test<uint64_t>(); |
370 | |
371 | cout << "UDT 1" << endl; |
372 | udt_test<user::UDT1>(); |
373 | |
374 | cout << "UDT 2" << endl; |
375 | udt_test<user::UDT2>(); |
376 | |
377 | #ifdef BOOST_ENDIAN_COMPILE_FAIL |
378 | cout << "UDT 3" << endl; |
379 | udt_test<user::UDT3>(); // should fail to compile since has not endian_reverse() |
380 | #endif |
381 | |
382 | return ::boost::report_errors(); |
383 | } |
384 | |
385 | int main( int argc, char* argv[] ) |
386 | { |
387 | try |
388 | { |
389 | return cpp_main( argc, argv ); |
390 | } |
391 | catch( std::exception const & x ) |
392 | { |
393 | BOOST_ERROR( x.what() ); |
394 | return boost::report_errors(); |
395 | } |
396 | } |
397 | |
398 | #include <boost/endian/detail/disable_warnings_pop.hpp> |
399 | |