HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
endian.hpp
1// Copyright Take Vos 2019-2020.
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 "architecture.hpp"
8#include "memory.hpp"
9#include "assert.hpp"
10
11#if HI_COMPILER == HI_CC_MSVC
12#include <stdlib.h>
13#endif
14#include <bit>
15#include <concepts>
16
17namespace hi::inline v1 {
18
19template<std::unsigned_integral T>
20[[nodiscard]] T byte_swap(T x) noexcept
21{
22#if HI_COMPILER == HI_CC_CLANG || HI_COMPILER == HI_CC_GCC
23 if constexpr (sizeof(T) == sizeof(uint64_t)) {
24 return static_cast<T>(__builtin_bswap64(static_cast<uint64_t>(x)));
25 } else if constexpr (sizeof(T) == sizeof(uint32_t)) {
26 return static_cast<T>(__builtin_bswap32(static_cast<uint32_t>(x)));
27 } else if constexpr (sizeof(T) == sizeof(uint16_t)) {
28 return static_cast<T>(__builtin_bswap16(static_cast<uint16_t>(x)));
29 } else {
30 hi_no_default();
31 }
32#elif HI_COMPILER == HI_CC_MSVC
33 if constexpr (sizeof(T) == sizeof(uint64_t)) {
34 return static_cast<T>(_byteswap_uint64(static_cast<uint64_t>(x)));
35 } else if constexpr (sizeof(T) == sizeof(unsigned long)) {
36 return static_cast<T>(_byteswap_ulong(static_cast<unsigned long>(x)));
37 } else if constexpr (sizeof(T) == sizeof(unsigned short)) {
38 return static_cast<T>(_byteswap_ushort(static_cast<unsigned short>(x)));
39 } else {
40 hi_no_default();
41 }
42#else
43#error "Byteswap not implemented for this compiler."
44#endif
45}
46
47template<std::signed_integral T>
48[[nodiscard]] T byte_swap(T x) noexcept
49{
50 return static_cast<T>(byte_swap(static_cast<std::make_unsigned_t<T>>(x)));
51}
52
53template<std::floating_point T>
54[[nodiscard]] T byte_swap(T x) noexcept
55{
56 if constexpr (std::is_same_v<T, float>) {
57 auto utmp = std::bit_cast<uint32_t>(x);
58 utmp = byte_swap(utmp);
59 return std::bit_cast<float>(x);
60 } else if constexpr (std::is_same_v<T, double>) {
61 auto utmp = std::bit_cast<uint64_t>(x);
62 utmp = byte_swap(utmp);
63 return std::bit_cast<double>(x);
64 } else {
65 hi_no_default();
66 }
67}
68
69template<std::integral T>
70[[nodiscard]] T little_to_native(T x)
71{
72 if constexpr (std::endian::native == std::endian::little) {
73 return x;
74 } else {
75 return byte_swap(x);
76 }
77}
78
79template<std::integral T>
80[[nodiscard]] T big_to_native(T x)
81{
82 if constexpr (std::endian::native == std::endian::big) {
83 return x;
84 } else {
85 return byte_swap(x);
86 }
87}
88
89template<std::integral T>
90[[nodiscard]] T native_to_little(T x)
91{
92 if constexpr (std::endian::native == std::endian::little) {
93 return x;
94 } else {
95 return byte_swap(x);
96 }
97}
98
99template<std::integral T>
100[[nodiscard]] T native_to_big(T x)
101{
102 if constexpr (std::endian::native == std::endian::big) {
103 return x;
104 } else {
105 return byte_swap(x);
106 }
107}
108
109template<typename T, std::endian E, std::size_t A = alignof(T)>
111 alignas(A) std::byte _value[sizeof(T)];
112
113 [[nodiscard]] T value() const noexcept
114 {
115 T x;
116 std::memcpy(&x, &_value[0], sizeof(T));
117
118 return E == std::endian::native ? x : byte_swap(x);
119 }
120
121 endian_buf_t &set_value(T x) noexcept
122 {
123 if constexpr (E != std::endian::native) {
124 x = byte_swap(x);
125 }
126
127 std::memcpy(&_value[0], &x, sizeof(T));
128 return *this;
129 }
130
131 endian_buf_t &operator=(T x) noexcept
132 {
133 return set_value(x);
134 }
135
136 operator T() const noexcept
137 {
138 return value();
139 }
140};
141
160
179
180} // namespace hi::inline v1
Functions and macros for handling architectural difference between compilers, CPUs and operating syst...
Definition endian.hpp:110
T memcpy(T... args)