17 template<
typename S,
typename D>
18 using copy_const_t = std::conditional_t<std::is_const_v<S>, std::add_const_t<D>, std::remove_const_t<D>>;
26 concept bytelike = (
alignof(T) ==
alignof(std::byte) &&
sizeof(T) ==
sizeof(std::byte) && std::is_trivial_v<T>);
38 template <
bytelike TO,
typename FROM,
size_t N = std::dynamic_extent>
39 requires std::is_trivially_copyable_v<FROM>
40 [[nodiscard]] std::span<TO>
as_bytelikes(std::span<FROM, N> elements)
noexcept
42 return {
reinterpret_cast<TO*
>(elements.data()), elements.size() *
sizeof(FROM) };
46 template <
typename TO,
bytelike FROM>
47 requires std::is_trivially_copyable_v<TO>
51 if (from.size() <
sizeof(TO))
52 throw std::invalid_argument(
"from span must be at least the size of the object");
54 std::memcpy(std::addressof(result), from.data(),
sizeof(TO));
59 template <
typename TO,
bytelike FROM>
60 requires std::is_trivially_copyable_v<TO>
63 const auto size = from.size() /
sizeof(TO);
64 return std::span<TO>{
reinterpret_cast<TO*
>(from.data()), size };
69 template <
bytelike TO,
typename T>
70 requires std::is_trivially_copyable_v<T>
73 if constexpr (std::is_const_v<T>)
74 return std::span{
reinterpret_cast<TO const*
>(std::addressof(pod)),
sizeof(pod) };
76 return std::span{
reinterpret_cast<TO*
>(std::addressof(pod)),
sizeof(pod) };
80 template <
bytelike FROM> [[nodiscard]]
constexpr auto to_u8(FROM
byte)
noexcept {
return std::bit_cast<uint8_t>(
byte); }
82 template <
bytelike FROM> [[nodiscard]]
constexpr auto to_char(FROM
byte)
noexcept {
return std::bit_cast<char>(
byte); }
84 template <
bytelike FROM> [[nodiscard]]
constexpr auto to_byte(FROM
byte)
noexcept {
return std::bit_cast<std::byte>(
byte); }
86 template <
bytelike FROM> [[nodiscard]]
constexpr auto to_uchar(FROM
byte)
noexcept {
return std::bit_cast<unsigned char>(
byte); }
88 template <
bytelike FROM> [[nodiscard]]
constexpr auto to_char8(FROM
byte)
noexcept {
return std::bit_cast<char8_t>(
byte); }
91 template <
bytelike FROM,
size_t N = std::dynamic_extent>
94 template <
bytelike FROM,
size_t N = std::dynamic_extent>
97 template <
bytelike FROM,
size_t N = std::dynamic_extent>
100 template <
bytelike FROM,
size_t N = std::dynamic_extent>
103 template <
bytelike FROM,
size_t N = std::dynamic_extent>
118 template <
bytelike B,
size_t N = std::dynamic_extent>
119 [[nodiscard]]
bool nth_bit(std::span<B const, N> range,
size_t n)
noexcept
121 if (n >= range.size() * CHAR_BIT)
123 const auto u8range =
as_u8s(range);
124 const auto byte = u8range[n / CHAR_BIT];
125 return byte & (1 << (n % CHAR_BIT));
129 template <
bytelike B,
size_t N = std::dynamic_extent>
130 void set_nth_bit(std::span<B, N> range,
size_t n,
bool value)
noexcept
132 if (n >= range.size() * CHAR_BIT)
134 auto u8range =
as_u8s(range);
135 auto byte = u8range[n / CHAR_BIT];
137 byte |= (1 << (n % CHAR_BIT));
139 byte &= ~(1 << (n % CHAR_BIT));
143 template <
typename T>
144 requires std::is_trivially_copyable_v<T>
145 [[nodiscard]]
bool nth_bit(T
const& pod,
size_t n)
noexcept
151 template <
typename T>
152 requires std::is_trivially_copyable_v<T>
159 template <
size_t N,
bytelike B,
size_t SN = std::dynamic_extent>
160 [[nodiscard]]
bool nth_bit(std::span<B const, SN> range)
noexcept
162 if (N >= range.size() * CHAR_BIT)
164 const auto u8range =
as_u8s(range);
165 const auto byte = u8range[N / CHAR_BIT];
166 return byte & (1 << (N % CHAR_BIT));
170 template <
size_t N,
bytelike B,
size_t SN = std::dynamic_extent>
173 if (N >= range.size() * CHAR_BIT)
175 auto u8range =
as_u8s(range);
176 auto byte = u8range[N / CHAR_BIT];
178 byte |= (1 << (N % CHAR_BIT));
180 byte &= ~(1 << (N % CHAR_BIT));
184 template <
size_t N,
typename T>
185 requires std::is_trivially_copyable_v<T>
186 [[nodiscard]]
bool nth_bit(T
const& pod)
noexcept
192 template <
size_t N,
typename T>
193 requires std::is_trivially_copyable_v<T>
201 template <
bytelike B, std::
integral T>
204 auto value = std::bit_cast<std::make_unsigned_t<T>>(value_);
205 std::array<B,
sizeof(T)> result;
206 for (
size_t i = 0; i <
sizeof(T); ++i)
208 result[i] =
static_cast<B
>(value & 0xFF);
216 template <
bytelike T>
217 struct align_front_to_result
220 std::span<T> aligned;
224 template <
size_t ALIGN,
bytelike T,
size_t N = std::dynamic_extent>
225 [[nodiscard]]
auto align_front_to(std::span<T, N> bytes)
noexcept -> align_front_to_result<T>
227 static_assert(ALIGN >= 1,
"Alignment must be greater or equal to 1");
228 if constexpr (ALIGN == 1)
234 void* ptr =
const_cast<std::remove_const_t<T>*
>(bytes.data());
235 size_t size = bytes.size();
236 ptr = std::align(ALIGN, ALIGN, ptr, size);
238 return { bytes, {} };
240 return { { bytes.data(), bytes.size() - size}, {
const_cast<T*
>(
reinterpret_cast<std::remove_const_t<T>*
>(ptr)), size }};
244 template <
bytelike T>
245 struct align_back_to_result
247 std::span<T> aligned;
253 template <
size_t ALIGN,
bytelike T,
size_t N = std::dynamic_extent>
254 [[nodiscard]]
constexpr auto align_back_to(std::span<T, N> bytes)
noexcept -> align_back_to_result<T>
256 static_assert(ALIGN >= 1,
"Alignment must be greater or equal to 1");
257 if constexpr (ALIGN == 1)
263 const auto size = bytes.size();
266 return { {}, bytes };
268 const auto aligned_size = size - (size % ALIGN);
269 return { bytes.subspan(0, aligned_size), bytes.subspan(aligned_size, size % ALIGN) };
273 template <
bytelike T,
typename MIDDLE = T>
274 struct align_to_result
277 std::span<MIDDLE> aligned;
283 template <
size_t ALIGN,
bytelike T,
size_t N = std::dynamic_extent>
284 [[nodiscard]]
auto align_to(std::span<T, N> bytes)
noexcept -> align_to_result<T>
286 static_assert(ALIGN >= 1,
"Alignment must be greater or equal to 1");
287 if constexpr (ALIGN == 1)
293 void* ptr =
const_cast<std::remove_const_t<T>*
>(bytes.data());
294 size_t size = bytes.size();
295 ptr = std::align(ALIGN, ALIGN, ptr, size);
297 return { bytes, {}, {} };
299 const auto aligned_size = size - (size % ALIGN);
301 { bytes.data(), bytes.size() - size},
302 {
const_cast<T*
>(
reinterpret_cast<std::remove_const_t<T>*
>(ptr)), aligned_size },
303 {
const_cast<T*
>(
reinterpret_cast<std::remove_const_t<T>*
>(ptr)) + aligned_size, size % ALIGN }
310 template <
typename TO,
bytelike B,
size_t N = std::dynamic_extent>
314 const std::span<TO> aligned {
315 reinterpret_cast<TO*
>(aligned_original.data()),
316 reinterpret_cast<TO*
>(aligned_original.data() + aligned_original.size())
318 return { prefix, aligned, suffix };
322 template <
typename TO,
bytelike B,
size_t N = std::dynamic_extent>
326 std::uninitialized_default_construct_n(result.aligned.data(), result.aligned.size());
Represents any trivially copyable type that is trivially castable to an internal object representatio...
std::span< TO > as_bytelikes(std::span< FROM, N > elements) noexcept
Converts a span of trivial values to a span of bytelike s.
constexpr auto to_u8(FROM byte) noexcept
Bit-casts the given bytelike to a uint8_t.
std::span< TO > span_from_bytelikes(std::span< FROM > from)
Returns an object whose internal representation is initialized from the argument.
void set_nth_bit(std::span< B, N > range, size_t n, bool value) noexcept
Sets the value of the nth bit in the range of bytelikes.
auto aligned_span_cast_and_construct(std::span< B, N > bytes) noexcept -> align_to_result< B, TO >
Does the same as aligned_span_cast but then default-constructs the elements of the of middle span.
constexpr auto to_char8(FROM byte) noexcept
Bit-casts the given bytelike to a char8_t.
constexpr auto to_bytelike_array(T value_)
A constexpr function that converts an integral value to its constituent bytelikes TODO: This is NOT l...
constexpr auto to_char(FROM byte) noexcept
Bit-casts the given bytelike to a char.
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...
auto as_u8s(std::span< FROM, N > bytes) noexcept
Returns a span of uint8_ts that represents the bytelikes in bytes.
auto as_chars(std::span< FROM, N > bytes) noexcept
Returns a span of chars that represents the bytelikes in bytes.
TO from_bytelikes(std::span< FROM const > from)
Returns an object whose internal representation is initialized from the argument.
constexpr auto to_byte(FROM byte) noexcept
Bit-casts the given bytelike to a std::byte.
auto as_char8s(std::span< FROM, N > bytes) noexcept
Returns a span of char8_ts that represents the bytelikes in bytes.
auto aligned_span_cast(std::span< B, N > bytes) noexcept -> align_to_result< B, TO >
Splits the argument span into three spans, the first one being the prefix, the second one capable of ...
bool nth_bit(std::span< B const, N > range, size_t n) noexcept
Returns the value of the nth bit in the range of bytelikes.
auto as_bytes(std::span< FROM, N > bytes) noexcept
Returns a span of std::bytes that represents the bytelikes in bytes.
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 ...
auto as_uchars(std::span< FROM, N > bytes) noexcept
Returns a span of unsigned chars that represents the bytelikes in bytes.
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...
constexpr auto to_uchar(FROM byte) noexcept
Bit-casts the given bytelike to a unsigned char.
Primary namespace for everything in this library.