351
|
1 #ifndef MINORI_CORE_ENDIAN_H_
|
|
2 #define MINORI_CORE_ENDIAN_H_
|
|
3
|
|
4 /* definition of endian-related stuff. primarily used for*/
|
|
5
|
|
6 #include <cstdint>
|
|
7 #include <type_traits>
|
|
8
|
|
9 class Endian {
|
|
10 private:
|
|
11 static constexpr uint32_t uint32_ = 0x01020304;
|
|
12 static constexpr uint8_t magic_ = static_cast<const uint8_t&>(uint32_);
|
|
13
|
|
14 /* check for compiler builtins for byteswapping */
|
|
15 #ifdef __has_builtin
|
|
16 # if __has_builtin(__builtin_bswap16)
|
|
17 # define COMPILER_BUILTIN_BSWAP16(x) __builtin_bswap16(x)
|
|
18 # endif
|
|
19 # if __has_builtin(__builtin_bswap32)
|
|
20 # define COMPILER_BUILTIN_BSWAP32(x) __builtin_bswap32(x)
|
|
21 # endif
|
|
22 # if __has_builtin(__builtin_bswap64)
|
|
23 # define COMPILER_BUILTIN_BSWAP64(x) __builtin_bswap64(x)
|
|
24 # endif
|
|
25 #endif
|
|
26
|
|
27 static constexpr uint16_t byteswap_16(uint16_t x) {
|
|
28 #ifdef COMPILER_BUILTIN_BSWAP16
|
|
29 return COMPILER_BUILTIN_BSWAP16(x);
|
|
30 #else
|
|
31 return (
|
|
32 ((x & UINT16_C(0x00FF)) << 8)
|
|
33 | ((x & UINT16_C(0xFF00)) >> 8)
|
|
34 );
|
|
35 #endif
|
|
36 }
|
|
37
|
|
38 static constexpr uint32_t byteswap_32(uint32_t x) {
|
|
39 #ifdef COMPILER_BUILTIN_BSWAP32
|
|
40 return COMPILER_BUILTIN_BSWAP32(x);
|
|
41 #else
|
|
42 return (
|
|
43 ((x & UINT32_C(0x000000FF)) << 24)
|
|
44 | ((x & UINT32_C(0x0000FF00)) << 8)
|
|
45 | ((x & UINT32_C(0x00FF0000)) >> 8)
|
|
46 | ((x & UINT32_C(0xFF000000)) >> 24)
|
|
47 );
|
|
48 #endif
|
|
49 }
|
|
50
|
|
51 static constexpr uint64_t byteswap_64(uint64_t x) {
|
|
52 #ifdef COMPILER_BUILTIN_BSWAP64
|
|
53 return COMPILER_BUILTIN_BSWAP64(x);
|
|
54 #else
|
|
55 return (
|
|
56 ((x & UINT64_C(0x00000000000000FF)) << 56)
|
|
57 | ((x & UINT64_C(0x000000000000FF00)) << 40)
|
|
58 | ((x & UINT64_C(0x0000000000FF0000)) << 24)
|
|
59 | ((x & UINT64_C(0x00000000FF000000)) << 8)
|
|
60 | ((x & UINT64_C(0x000000FF00000000)) >> 8)
|
|
61 | ((x & UINT64_C(0x0000FF0000000000)) >> 24)
|
|
62 | ((x & UINT64_C(0x00FF000000000000)) >> 40)
|
|
63 | ((x & UINT64_C(0xFF00000000000000)) >> 56)
|
|
64 );
|
|
65 #endif
|
|
66 }
|
|
67
|
|
68 #ifdef COMPILER_BUILTIN_BSWAP16
|
|
69 # undef COMPILER_BUILTIN_BSWAP16
|
|
70 #endif
|
|
71 #ifdef COMPILER_BUILTIN_BSWAP32
|
|
72 # undef COMPILER_BUILTIN_BSWAP32
|
|
73 #endif
|
|
74 #ifdef COMPILER_BUILTIN_BSWAP64
|
|
75 # undef COMPILER_BUILTIN_BSWAP64
|
|
76 #endif
|
|
77 public:
|
|
78 static constexpr bool little = magic_ == 0x04;
|
|
79 static constexpr bool big = magic_ == 0x01;
|
|
80 static_assert(little || big, "unsupported endianness");
|
|
81
|
|
82 template<typename T>
|
|
83 static constexpr T byteswap(T x) {
|
|
84 static_assert(std::is_integral<T>::value);
|
|
85 static_assert(std::is_unsigned<T>::value);
|
|
86
|
|
87 if constexpr (std::is_same<T, uint8_t>::value) {
|
|
88 return x;
|
|
89 } else if constexpr (std::is_same<T, uint16_t>::value) {
|
|
90 return byteswap_16(x);
|
|
91 } else if constexpr (std::is_same<T, uint32_t>::value) {
|
|
92 return byteswap_32(x);
|
|
93 } else if constexpr (std::is_same<T, uint64_t>::value) {
|
|
94 return byteswap_64(x);
|
|
95 } else {
|
|
96 static_assert(false, "byteswapping with unknown integer type");
|
|
97 }
|
|
98 }
|
|
99
|
|
100 template<typename T>
|
|
101 static constexpr T byteswap_little_to_host(T x) {
|
|
102 if constexpr (little) {
|
|
103 return x;
|
|
104 } else if constexpr (big) {
|
|
105 return byteswap(x);
|
|
106 }
|
|
107 }
|
|
108
|
|
109 template<typename T>
|
|
110 static constexpr T byteswap_big_to_host(T x) {
|
|
111 if constexpr (big) {
|
|
112 return x;
|
|
113 } else if constexpr (little) {
|
|
114 return byteswap(x);
|
|
115 }
|
|
116 }
|
|
117 private:
|
|
118 Endian() = delete;
|
|
119 };
|
|
120
|
|
121 #endif /* MINORI_CORE_ENDIAN_H_ */
|