HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
endian.hpp
1// Copyright Take Vos 2019-2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "memory.hpp"
8
9#ifdef HI_HAS_SSE
10#include <immintrin.h>
11#endif
12#ifdef HI_HAS_SSE2
13#include <emmintrin.h>
14#endif
15#ifdef HI_HAS_SSE4_1
16#include <smmintrin.h>
17#endif
18#if HI_COMPILER == HI_CC_MSVC
19#include <stdlib.h>
20#endif
21#include <bit>
22#include <concepts>
23
24hi_warning_push();
25// C26472: Don't use a static_cast for arithmetic conversions. Use brace initialization, gsl::narrow_cast or gsl::narrow
26// (type.1).
27// static_cast are used to cheaply cast integers to unsigned and back, for byteswapping.
28hi_warning_ignore_msvc(26472);
29
30namespace hi::inline v1 {
31
32template<std::unsigned_integral T>
33[[nodiscard]] constexpr T byte_swap(T x) noexcept
34{
35 if (not std::is_constant_evaluated()) {
36#if HI_COMPILER == HI_CC_CLANG || HI_COMPILER == HI_CC_GCC
37 if constexpr (sizeof(T) == sizeof(uint64_t)) {
38 return static_cast<T>(__builtin_bswap64(static_cast<uint64_t>(x)));
39 } else if constexpr (sizeof(T) == sizeof(uint32_t)) {
40 return static_cast<T>(__builtin_bswap32(static_cast<uint32_t>(x)));
41 } else if constexpr (sizeof(T) == sizeof(uint16_t)) {
42 return static_cast<T>(__builtin_bswap16(static_cast<uint16_t>(x)));
43 }
44#elif HI_COMPILER == HI_CC_MSVC
45 if constexpr (sizeof(T) == sizeof(uint64_t)) {
46 return static_cast<T>(_byteswap_uint64(static_cast<uint64_t>(x)));
47 } else if constexpr (sizeof(T) == sizeof(unsigned long)) {
48 return static_cast<T>(_byteswap_ulong(static_cast<unsigned long>(x)));
49 } else if constexpr (sizeof(T) == sizeof(unsigned short)) {
50 return static_cast<T>(_byteswap_ushort(static_cast<unsigned short>(x)));
51 }
52#endif
53 }
54
55 if constexpr (sizeof(T) == 1) {
56 return x;
57 } else {
58 auto r = T{};
59 for (auto i = 0_uz; i != sizeof(T); ++i) {
60 r <<= 8;
61 r |= static_cast<uint8_t>(x);
62 x >>= 8;
63 }
64 return r;
65 }
66}
67
68template<std::signed_integral T>
69[[nodiscard]] constexpr T byte_swap(T x) noexcept
70{
71 return static_cast<T>(byte_swap(static_cast<std::make_unsigned_t<T>>(x)));
72}
73
74template<std::floating_point T>
75[[nodiscard]] constexpr T byte_swap(T x) noexcept
76{
77 if constexpr (std::is_same_v<T, float>) {
78 auto utmp = std::bit_cast<uint32_t>(x);
79 utmp = byte_swap(utmp);
80 return std::bit_cast<float>(x);
81 } else if constexpr (std::is_same_v<T, double>) {
82 auto utmp = std::bit_cast<uint64_t>(x);
83 utmp = byte_swap(utmp);
84 return std::bit_cast<double>(x);
85 } else {
87 }
88}
89
90template<std::integral T>
91[[nodiscard]] constexpr T little_to_native(T x)
92{
93 if constexpr (std::endian::native == std::endian::little) {
94 return x;
95 } else {
96 return byte_swap(x);
97 }
98}
99
100template<std::integral T>
101[[nodiscard]] constexpr T big_to_native(T x)
102{
103 if constexpr (std::endian::native == std::endian::big) {
104 return x;
105 } else {
106 return byte_swap(x);
107 }
108}
109
110template<std::integral T>
111[[nodiscard]] constexpr T native_to_little(T x)
112{
113 if constexpr (std::endian::native == std::endian::little) {
114 return x;
115 } else {
116 return byte_swap(x);
117 }
118}
119
120template<std::integral T>
121[[nodiscard]] constexpr T native_to_big(T x)
122{
123 if constexpr (std::endian::native == std::endian::big) {
124 return x;
125 } else {
126 return byte_swap(x);
127 }
128}
129
130template<numeric T, std::endian Endian = std::endian::native>
131[[nodiscard]] constexpr T load(T const *src) noexcept
132{
133 auto value = *src;
134 if constexpr (Endian != std::endian::native) {
135 value = byte_swap(value);
136 }
137 return value;
138}
139
140template<numeric T, std::endian Endian = std::endian::native, byte_like B>
141[[nodiscard]] constexpr T load(B const *src) noexcept
142{
143 auto value = unaligned_load<T>(src);
144 if constexpr (Endian != std::endian::native) {
145 value = byte_swap(value);
146 }
147 return value;
148}
149
150template<numeric T, std::endian Endian = std::endian::native>
151[[nodiscard]] inline T load(void const *src) noexcept
152{
153 auto value = unaligned_load<T>(src);
154 if constexpr (Endian != std::endian::native) {
155 value = byte_swap(value);
156 }
157 return value;
158}
159
160template<numeric T>
161[[nodiscard]] constexpr T load_le(T const *src) noexcept
162{
163 return load<T, std::endian::little>(src);
164}
165
166template<numeric T, byte_like B>
167[[nodiscard]] constexpr T load_le(B const *src) noexcept
168{
169 return load<T, std::endian::little>(src);
170}
171
172template<numeric T>
173[[nodiscard]] inline T load_le(void const *src) noexcept
174{
175 return load<T, std::endian::little>(src);
176}
177
178template<numeric T>
179[[nodiscard]] constexpr T load_be(T const *src) noexcept
180{
181 return load<T, std::endian::big>(src);
182}
183
184template<numeric T, byte_like B>
185[[nodiscard]] constexpr T load_be(B const *src) noexcept
186{
187 return load<T, std::endian::big>(src);
188}
189
190template<numeric T>
191[[nodiscard]] inline T load_be(void const *src) noexcept
192{
193 return load<T, std::endian::big>(src);
194}
195
196template<std::endian Endian = std::endian::native, numeric T, byte_like B>
197constexpr void store(T value, B const *dst) noexcept
198{
199 if constexpr (Endian != std::endian::native) {
200 value = byte_swap(value);
201 }
202 unaligned_store<T>(value, dst);
203}
204
205template<std::endian Endian = std::endian::native, numeric T>
206constexpr void store(T value, void const *dst) noexcept
207{
208 if constexpr (Endian != std::endian::native) {
209 value = byte_swap(value);
210 }
211 unaligned_store<T>(value, dst);
212}
213
214template<numeric T, byte_like B>
215constexpr void store_le(T value, B const *dst) noexcept
216{
217 store<std::endian::little>(value, dst);
218}
219
220template<numeric T>
221inline void store_le(T value, void const *dst) noexcept
222{
223 store<std::endian::little>(value, dst);
224}
225
226template<numeric T, byte_like B>
227constexpr void store_be(T value, B const *dst) noexcept
228{
229 store<std::endian::big>(value, dst);
230}
231
232template<numeric T>
233inline void store_be(T value, void const *dst) noexcept
234{
235 store<std::endian::big>(value, dst);
236}
237
238
239template<typename T, std::endian E, std::size_t A = alignof(T)>
241 using value_type = T;
242 constexpr static std::endian endian = E;
243 constexpr static std::size_t alignment = A;
244
245 alignas(A) std::byte _value[sizeof(T)];
246
247 [[nodiscard]] constexpr value_type operator*() const noexcept
248 {
249 return load<value_type, endian>(_value);
250 }
251
252 constexpr endian_buf_t& operator=(value_type x) noexcept
253 {
254 store<endian>(x, _value);
255 return *this;
256 }
257};
258
277
296
297} // namespace hi::inline v1
298
299hi_warning_pop();
#define hi_static_no_default(...)
This part of the code should not be reachable, unless a programming bug.
Definition assert.hpp:308
DOXYGEN BUG.
Definition algorithm.hpp:13
Horizontal/Vertical alignment combination.
Definition alignment.hpp:231
Definition endian.hpp:240