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