1 ///
2 /// @file   littleendian_cast.hpp
3 /// @brief  Cast bytes in ascending address order on both little and
4 ///         big endian CPUs.
5 ///
6 /// Copyright (C) 2020 Kim Walisch, <kim.walisch@gmail.com>
7 ///
8 /// This file is distributed under the BSD License. See the COPYING
9 /// file in the top level directory.
10 ///
11 
12 #ifndef LITTLEENDIAN_CAST_HPP
13 #define LITTLEENDIAN_CAST_HPP
14 
15 #include <stdint.h>
16 
17 namespace {
18 
19 /// http://c-faq.com/misc/endiantest.html
is_littleendian()20 inline bool is_littleendian()
21 {
22   union {
23     int word;
24     char c[sizeof(int)];
25   } x;
26   x.word = 1;
27   return (x.c[0] == 1);
28 }
29 
30 /// Recursively sum bytes using template metaprogramming.
31 /// e.g. littleendian_cast<int32_t>(array) =
32 /// return (array[0] <<  0) +
33 ///        (array[1] <<  8) +
34 ///        (array[2] << 16) +
35 ///        (array[3] << 24);
36 ///
37 template <typename T, int INDEX, int STOP>
38 struct littleendian_cast_helper
39 {
sum__anon6530e0770111::littleendian_cast_helper40   static T sum(const uint8_t* array, T n)
41   {
42     n += static_cast<T>(array[INDEX]) << (INDEX * 8);
43     return littleendian_cast_helper<T, INDEX + 1, STOP - 1>::sum(array, n);
44   }
45 };
46 
47 template <typename T, int INDEX>
48 struct littleendian_cast_helper<T, INDEX, 0>
49 {
sum__anon6530e0770111::littleendian_cast_helper50   static T sum(const uint8_t*, T n)
51   {
52     return n;
53   }
54 };
55 
56 template <typename T>
littleendian_cast(const uint8_t * array)57 inline T littleendian_cast(const uint8_t* array)
58 {
59   if (is_littleendian())
60     return *reinterpret_cast<const T*>(array);
61   return littleendian_cast_helper<T, 0, sizeof(T)>::sum(array, 0);
62 }
63 
64 } // namespace
65 
66 #endif
67