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 boost::int8_t;
33 using boost::uint8_t;
34 using boost::int16_t;
35 using boost::uint16_t;
36 using boost::int32_t;
37 using boost::uint32_t;
38 using boost::int64_t;
39 using boost::uint64_t;
40
std_endian_reverse(T x)41 template <class T> inline T std_endian_reverse(T x) BOOST_NOEXCEPT
42 {
43 T tmp(x);
44 std::reverse( reinterpret_cast<unsigned char*>(&tmp), 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
native_value(T & x)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( &x, test_value_bytes, sizeof( x ) );
59 }
60
little_value(T & x)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
big_value(T & x)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>
test()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>
udt_test()231 void udt_test()
232 {
233 UDT udt, tmp;
234 int64_t big;
235 int64_t little;
236 int64_t native;
237 big_value(big);
238 little_value(little);
239 native_value(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
endian_reverse(const UDT1 & udt)286 UDT1 endian_reverse(const UDT1& udt) BOOST_NOEXCEPT
287 {
288 UDT1 tmp;
289 tmp.member1 = boost::endian::endian_reverse(udt.member1);
290 tmp.member2 = boost::endian::endian_reverse(udt.member2);
291 tmp.member3 = boost::endian::endian_reverse(udt.member3);
292 return tmp;
293 }
294
endian_reverse_inplace(UDT1 & udt)295 void endian_reverse_inplace(UDT1& udt) BOOST_NOEXCEPT
296 {
297 boost::endian::endian_reverse_inplace(udt.member1);
298 boost::endian::endian_reverse_inplace(udt.member2);
299 boost::endian::endian_reverse_inplace(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
endian_reverse(const UDT2 & udt)310 UDT2 endian_reverse(const UDT2& udt) BOOST_NOEXCEPT
311 {
312 UDT2 tmp;
313 tmp.member1 = boost::endian::endian_reverse(udt.member1);
314 tmp.member2 = boost::endian::endian_reverse(udt.member2);
315 tmp.member3 = boost::endian::endian_reverse(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
cpp_main(int,char * [])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
main(int argc,char * argv[])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