• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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