header_utils
Loading...
Searching...
No Matches
bytes.h
1
4
5#pragma once
6
7#include <cstddef>
8#include <span>
9#include <string_view>
10#include <array>
11#include <bit>
12#include <span>
13
14namespace ghassanpl
15{
16
18 template <typename T>
19 concept bytelike = (alignof(T) == alignof(std::byte) && sizeof(T) == sizeof(std::byte) && std::is_trivial_v<T>);
20
21 template <typename T>
22 concept bytelike_range = std::ranges::range<T> && bytelike<std::ranges::range_value_t<T>>;
23
25 template <bytelike TO, typename FROM, size_t N = std::dynamic_extent>
26 requires std::is_trivially_copyable_v<FROM>
27 std::span<TO> as_bytelikes(std::span<FROM, N> bytes) noexcept
28 {
29 return { reinterpret_cast<TO*>(bytes.data()), bytes.size() * sizeof(FROM) };
30 }
31
33 template <bytelike TO, typename T>
34 requires std::is_trivially_copyable_v<T>
35 std::span<TO const> as_bytelikes(T const& pod) noexcept
36 {
37 return { reinterpret_cast<TO const*>(std::addressof(pod)), sizeof(pod) };
38 }
39
40 template <bytelike FROM> constexpr auto to_u8(FROM byte) noexcept { return std::bit_cast<uint8_t>(byte); }
41 template <bytelike FROM> constexpr auto to_char(FROM byte) noexcept { return std::bit_cast<char>(byte); }
42 template <bytelike FROM> constexpr auto to_byte(FROM byte) noexcept { return std::bit_cast<std::byte>(byte); }
43 template <bytelike FROM> constexpr auto to_uchar(FROM byte) noexcept { return std::bit_cast<unsigned char>(byte); }
44 template <bytelike FROM> constexpr auto to_char8(FROM byte) noexcept { return std::bit_cast<char8_t>(byte); }
45
46 template<typename S, typename D>
47 using copy_const_t = std::conditional_t<std::is_const_v<S>, std::add_const_t<D>, std::remove_const_t<D>>;
48
49 template <bytelike FROM, size_t N = std::dynamic_extent> auto as_chars(std::span<FROM, N> bytes) noexcept { return as_bytelikes<copy_const_t<FROM, char>>(bytes); }
50 template <bytelike FROM, size_t N = std::dynamic_extent> auto as_bytes(std::span<FROM, N> bytes) noexcept { return as_bytelikes<copy_const_t<FROM, std::byte>>(bytes); }
51 template <bytelike FROM, size_t N = std::dynamic_extent> auto as_uchars(std::span<FROM, N> bytes) noexcept { return as_bytelikes<copy_const_t<FROM, unsigned char>>(bytes); }
52 template <bytelike FROM, size_t N = std::dynamic_extent> auto as_u8s(std::span<FROM, N> bytes) noexcept { return as_bytelikes<copy_const_t<FROM, uint8_t>>(bytes); }
53 template <bytelike FROM, size_t N = std::dynamic_extent> auto as_char8s(std::span<FROM, N> bytes) noexcept { return as_bytelikes<copy_const_t<FROM, char8_t>>(bytes); }
54
55 template <typename T> requires std::is_trivial_v<T> auto as_chars(T const& data) noexcept { return as_bytelikes<char>(data); }
56 template <typename T> requires std::is_trivial_v<T> auto as_bytes(T const& data) noexcept { return as_bytelikes<std::byte>(data); }
57 template <typename T> requires std::is_trivial_v<T> auto as_uchars(T const& data) noexcept { return as_bytelikes<unsigned char>(data); }
58 template <typename T> requires std::is_trivial_v<T> auto as_u8s(T const& data) noexcept { return as_bytelikes<uint8_t>(data); }
59 template <typename T> requires std::is_trivial_v<T> auto as_char8s(T const& data) noexcept { return as_bytelikes<char8_t>(data); }
60
61
62 template <bytelike B, size_t N = std::dynamic_extent>
63 bool nth_bit(std::span<B const, N> range, size_t n) noexcept
64 {
65 if (n >= u8range.size() * CHAR_BIT)
66 return false;
67 const auto u8range = as_u8s(range);
68 const auto byte = u8range[n / CHAR_BIT];
69 return byte & (1 << (n % CHAR_BIT));
70 }
71
72 template <bytelike B, size_t N = std::dynamic_extent>
73 void set_nth_bit(std::span<B, N> range, size_t n, bool value) noexcept
74 {
75 if (n >= u8range.size() * CHAR_BIT)
76 return;
77 auto u8range = as_u8s(range);
78 auto byte = u8range[n / CHAR_BIT];
79 if (value)
80 byte |= (1 << (n % CHAR_BIT));
81 else
82 byte &= ~(1 << (n % CHAR_BIT));
83 }
84
85 template <typename T>
86 requires std::is_trivially_copyable_v<T>
87 bool nth_bit(T const& pod, size_t n) noexcept
88 {
89 return nth_bit(as_u8s(pod), n);
90 }
91
92 template <typename T>
93 requires std::is_trivially_copyable_v<T>
94 void set_nth_bit(T& pod, size_t n, bool value) noexcept
95 {
96 set_nth_bit(as_u8s(pod), n, value);
97 }
98
99 template <size_t N, bytelike B, size_t SN = std::dynamic_extent>
100 bool nth_bit(std::span<B const, SN> range) noexcept
101 {
102 if (N >= u8range.size() * CHAR_BIT)
103 return false;
104 const auto u8range = as_u8s(range);
105 const auto byte = u8range[N / CHAR_BIT];
106 return byte & (1 << (N % CHAR_BIT));
107 }
108
109 template <size_t N, bytelike B, size_t SN = std::dynamic_extent>
110 void set_nth_bit(std::span<B, SN> range, bool value) noexcept
111 {
112 if (N >= u8range.size() * CHAR_BIT)
113 return;
114 auto u8range = as_u8s(range);
115 auto byte = u8range[N / CHAR_BIT];
116 if (value)
117 byte |= (1 << (N % CHAR_BIT));
118 else
119 byte &= ~(1 << (N % CHAR_BIT));
120 }
121
122 template <size_t N, typename T>
123 requires std::is_trivially_copyable_v<T>
124 bool nth_bit(T const& pod) noexcept
125 {
126 return nth_bit<N>(as_u8s(pod));
127 }
128
129 template <size_t N, typename T>
130 requires std::is_trivially_copyable_v<T>
131 void set_nth_bit(T& pod, bool value) noexcept
132 {
133 set_nth_bit<N>(as_u8s(pod), value);
134 }
135
138 template <bytelike B, std::integral T>
139 constexpr auto to_bytelike_array(T value)
140 {
141 value = std::bit_cast<std::make_unsigned_t<T>>(value);
142 std::array<B, sizeof(T)> result;
143 for (size_t i = 0; i < sizeof(T); ++i)
144 {
145 result[i] = static_cast<B>(value & 0xFF);
146 value >>= 8;
147 }
148 return result;
149 }
150
151 template <std::integral T> constexpr auto to_u8_array(T value) { return to_bytelike_array<uint8_t>(value); }
152
153 template <bytelike T>
154 struct align_front_to_result
155 {
156 std::span<T> prefix;
157 std::span<T> aligned;
158 };
159
161 template <size_t ALIGN, bytelike T, size_t N = std::dynamic_extent>
162 auto align_front_to(std::span<T, N> bytes) noexcept -> align_front_to_result<T>
163 {
164 static_assert(ALIGN >= 1, "Alignment must be greater or equal to 1");
165 if constexpr (ALIGN == 1)
166 {
167 return bytes;
168 }
169 else
170 {
171 void* ptr = const_cast<std::remove_const_t<T>*>(bytes.data());
172 size_t size = bytes.size();
173 ptr = std::align(ALIGN, ALIGN, ptr, size);
174 if (!ptr)
175 return { bytes, {} };
176
177 return { { bytes.data(), bytes.size() - size}, { const_cast<T*>(reinterpret_cast<std::remove_const_t<T>*>(ptr)), size }};
178 }
179 }
180
181 template <bytelike T>
182 struct align_back_to_result
183 {
184 std::span<T> aligned;
185 std::span<T> suffix;
186 };
187
190 template <size_t ALIGN, bytelike T, size_t N = std::dynamic_extent>
191 constexpr auto align_back_to(std::span<T, N> bytes) noexcept -> align_back_to_result<T>
192 {
193 static_assert(ALIGN >= 1, "Alignment must be greater or equal to 1");
194 if constexpr (ALIGN == 1)
195 {
196 return bytes;
197 }
198 else
199 {
200 const auto size = bytes.size();
201
202 if (size < ALIGN)
203 return { {}, bytes };
204
205 const auto aligned_size = size - (size % ALIGN);
206 return { bytes.subspan(0, aligned_size), bytes.subspan(aligned_size, size % ALIGN) };
207 }
208 }
209
210 template <bytelike T, typename MIDDLE = T>
211 struct align_to_result
212 {
213 std::span<T> prefix;
214 std::span<MIDDLE> aligned;
215 std::span<T> suffix;
216 };
217
220 template <size_t ALIGN, bytelike T, size_t N = std::dynamic_extent>
221 auto align_to(std::span<T, N> bytes) noexcept -> align_to_result<T>
222 {
223 static_assert(ALIGN >= 1, "Alignment must be greater or equal to 1");
224 if constexpr (ALIGN == 1)
225 {
226 return bytes;
227 }
228 else
229 {
230 void* ptr = const_cast<std::remove_const_t<T>*>(bytes.data());
231 size_t size = bytes.size();
232 ptr = std::align(ALIGN, ALIGN, ptr, size);
233 if (!ptr)
234 return { bytes, {}, {} };
235
236 const auto aligned_size = size - (size % ALIGN);
237 return {
238 { bytes.data(), bytes.size() - size},
239 { const_cast<T*>(reinterpret_cast<std::remove_const_t<T>*>(ptr)), aligned_size },
240 { const_cast<T*>(reinterpret_cast<std::remove_const_t<T>*>(ptr)) + aligned_size, size % ALIGN }
241 };
242 }
243 }
244
245 template <typename TO, bytelike B, size_t N = std::dynamic_extent>
246 auto aligned_span_cast(std::span<B, N> bytes) noexcept -> align_to_result<B, TO>
247 {
248 const auto [prefix, aligned, suffix] = align_to<std::max(alignof(TO), sizeof(TO))>(bytes);
249 const auto std::span<TO> aligned_cast{
250 reinterpret_cast<TO*>(aligned.data()),
251 reinterpret_cast<TO*>(aligned.data() + aligned.size())
252 };
253 return { prefix, aligned_cast, suffix };
254 }
255
256 template <typename TO, bytelike B, size_t N = std::dynamic_extent>
257 auto aligned_span_cast_and_construct(std::span<B, N> bytes) noexcept -> align_to_result<B, TO>
258 {
259 const auto result = aligned_span_cast<TO>(bytes);
260 std::uninitialized_default_construct_n(result.aligned.data(), result.aligned.size());
261 return result;
262 }
263
265}
Represents any trivially copyable type that is trivially castable to an internal object representatio...
Definition bytes.h:19
constexpr auto bit_count
Equal to the number of bits in the type.
Definition bits.h:33
std::string_view suffix(std::string_view str, size_t count) noexcept
Returns a substring containing the count rightmost characters of str. Always valid,...
Definition string_ops.h:581
std::string_view prefix(std::string_view str, size_t count) noexcept
Returns a substring containing the count leftmost characters of str. Always valid,...
Definition string_ops.h:571
Primary namespace for everything in this library.
Definition align+rec2.h:10
auto align_front_to(std::span< T, N > bytes) noexcept -> align_front_to_result< T >
Splits the argument span into two spans, the first one being the prefix, the second one having its da...
Definition bytes.h:162
constexpr auto to_bytelike_array(T value)
A constexpr function that converts an integral value to its constituent bytelikes TODO: This is NOT l...
Definition bytes.h:139
auto align_to(std::span< T, N > bytes) noexcept -> align_to_result< T >
Splits the argument span into three spans, the first one being the prefix, the second one having its ...
Definition bytes.h:221
std::span< TO > as_bytelikes(std::span< FROM, N > bytes) noexcept
Converts a span of trivial values to a span of bytelike s.
Definition bytes.h:27
constexpr auto align_back_to(std::span< T, N > bytes) noexcept -> align_back_to_result< T >
Splits the argument span into two spans, the first one having its size aligned to the given alignment...
Definition bytes.h:191