9#ifndef BOTAN_LOAD_STORE_H_
10#define BOTAN_LOAD_STORE_H_
12#include <botan/mem_ops.h>
13#include <botan/types.h>
14#include <botan/internal/bswap.h>
28 return static_cast<uint8_t
>(input >> (((~byte_num) & (
sizeof(
T) - 1)) << 3));
36template <
size_t B,
typename T>
38 requires(B <
sizeof(
T))
40 const size_t shift = ((~B) & (
sizeof(
T) - 1)) << 3;
41 return static_cast<uint8_t
>((input >> shift) & 0xFF);
50inline constexpr uint16_t
make_uint16(uint8_t i0, uint8_t i1) {
51 return static_cast<uint16_t
>((
static_cast<uint16_t
>(i0) << 8) | i1);
62inline constexpr uint32_t
make_uint32(uint8_t i0, uint8_t i1, uint8_t i2, uint8_t i3) {
63 return ((
static_cast<uint32_t
>(i0) << 24) | (
static_cast<uint32_t
>(i1) << 16) | (
static_cast<uint32_t
>(i2) << 8) |
64 (
static_cast<uint32_t
>(i3)));
80 uint8_t i0, uint8_t i1, uint8_t i2, uint8_t i3, uint8_t i4, uint8_t i5, uint8_t i6, uint8_t i7) {
81 return ((
static_cast<uint64_t
>(i0) << 56) | (
static_cast<uint64_t
>(i1) << 48) | (
static_cast<uint64_t
>(i2) << 40) |
82 (
static_cast<uint64_t
>(i3) << 32) | (
static_cast<uint64_t
>(i4) << 24) | (
static_cast<uint64_t
>(i5) << 16) |
83 (
static_cast<uint64_t
>(i6) << 8) | (
static_cast<uint64_t
>(i7)));
91template <std::
unsigned_
integral T, ranges::contiguous_range<u
int8_t> InR>
93 ranges::assert_exact_byte_length<sizeof(T)>(in_range);
94 std::span in{in_range};
95 if constexpr(
sizeof(
T) == 1) {
96 return static_cast<T>(in[0]);
98#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
99 return typecast_copy<T>(in);
100#elif defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
103 return [&]<
size_t... i>(std::index_sequence<i...>) {
104 return ((
static_cast<T>(in[i]) << ((
sizeof(
T) - i - 1) * 8)) | ...);
106 (std::make_index_sequence<sizeof(T)>());
116template <std::
unsigned_
integral T, ranges::contiguous_range<u
int8_t> InR>
118 ranges::assert_exact_byte_length<sizeof(T)>(in_range);
119 std::span in{in_range};
120 if constexpr(
sizeof(
T) == 1) {
121 return static_cast<T>(in[0]);
123#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
125#elif defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
126 return typecast_copy<T>(in);
128 return [&]<
size_t... i>(std::index_sequence<i...>) {
129 return ((
static_cast<T>(in[i]) << (i * 8)) | ...);
131 (std::make_index_sequence<sizeof(T)>());
143template <ranges::contiguous_range<u
int8_t> InR>
146 static_assert(
decltype(s)::extent != std::dynamic_extent,
147 "Cannot determine the output type based on a dynamically sized bytearray");
148 constexpr size_t e =
decltype(s)::extent;
152 std::conditional_t<e == 1, uint8_t,
153 std::conditional_t<e == 2, uint16_t,
154 std::conditional_t<e == 4, uint32_t,
155 std::conditional_t<e == 8, uint64_t, void>>>>;
159 !std::is_void_v<type>,
160 "Cannot determine the output type based on a statically sized bytearray with length other than those: 1, 2, 4, 8");
172template <ranges::contiguous_range<u
int8_t> InR>
173inline constexpr auto load_le(InR&& in_range) {
174 return load_le<decltype(details::default_load_type(in_range)), InR>(std::forward<InR>(in_range));
182template <ranges::contiguous_range<u
int8_t> InR>
183inline constexpr auto load_be(InR&& in_range) {
184 return load_be<decltype(details::default_load_type(in_range)), InR>(std::forward<InR>(in_range));
194inline constexpr T load_be(
const uint8_t in[],
size_t off) {
195 in += off *
sizeof(
T);
197 for(
size_t i = 0; i !=
sizeof(
T); ++i) {
198 out =
static_cast<T>((out << 8) | in[i]);
210inline constexpr T load_le(
const uint8_t in[],
size_t off) {
211 in += off *
sizeof(
T);
213 for(
size_t i = 0; i !=
sizeof(
T); ++i) {
214 out = (out << 8) | in[
sizeof(
T) - 1 - i];
225template <std::
unsigned_
integral T>
226inline constexpr T load_be(
const uint8_t in[],
size_t off) {
228 return load_be<T>(std::span<
const uint8_t,
sizeof(
T)>(in + off *
sizeof(
T),
sizeof(
T)));
237template <std::
unsigned_
integral T>
238inline constexpr T load_le(
const uint8_t in[],
size_t off) {
240 return load_le<T>(std::span<
const uint8_t,
sizeof(
T)>(in + off *
sizeof(
T),
sizeof(
T)));
248template <ranges::contiguous_range<u
int8_t> InR, std::
unsigned_
integral... Ts>
249 requires(
sizeof...(Ts) > 0) && all_same_v<Ts...>
250inline constexpr void load_be(InR&& in, Ts&... outs) {
252 auto load_one = [off = 0]<
typename T>(
auto i,
T& o)
mutable {
253 o = load_be<T>(i.subspan(off).template first<
sizeof(
T)>());
257 (load_one(std::span{in}, outs), ...);
265template <ranges::contiguous_range<u
int8_t> InR, std::
unsigned_
integral... Ts>
266 requires(
sizeof...(Ts) > 0) && all_same_v<Ts...>
267inline constexpr void load_le(InR&& in, Ts&... outs) {
269 auto load_one = [off = 0]<
typename T>(
auto i,
T& o)
mutable {
270 o = load_le<T>(i.subspan(off).template first<
sizeof(
T)>());
274 (load_one(std::span{in}, outs), ...);
282template <std::unsigned_integral... Ts>
283 requires(
sizeof...(Ts) > 0) && all_same_v<Ts...>
284inline constexpr void load_be(
const uint8_t in[], Ts&... outs) {
285 constexpr auto bytes = (
sizeof(outs) + ...);
287 load_be(std::span<const uint8_t, bytes>(in, bytes), outs...);
295template <std::unsigned_integral... Ts>
296 requires(
sizeof...(Ts) > 0) && all_same_v<Ts...>
297inline constexpr void load_le(
const uint8_t in[], Ts&... outs) {
298 constexpr auto bytes = (
sizeof(outs) + ...);
300 load_le(std::span<const uint8_t, bytes>(in, bytes), outs...);
310inline constexpr void load_le(
T out[],
const uint8_t in[],
size_t count) {
312#if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
315#elif defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
318 for(
size_t i = 0; i != count; ++i)
321 for(
size_t i = 0; i != count; ++i)
322 out[i] = load_le<T>(in, i);
334inline constexpr void load_be(
T out[],
const uint8_t in[],
size_t count) {
336#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
339#elif defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
342 for(
size_t i = 0; i != count; ++i) {
346 for(
size_t i = 0; i != count; ++i)
347 out[i] = load_be<T>(in, i);
357template <std::
unsigned_
integral T, ranges::contiguous_output_range<u
int8_t> OutR>
359 ranges::assert_exact_byte_length<sizeof(T)>(out_range);
360 std::span out{out_range};
361 if constexpr(
sizeof(
T) == 1) {
362 out[0] =
static_cast<uint8_t
>(in);
364#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
366#elif defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
369 [&]<
size_t... i>(std::index_sequence<i...>) {
370 ((out[i] = get_byte<i>(in)), ...);
372 (std::make_index_sequence<sizeof(T)>());
382template <std::
unsigned_
integral T, ranges::contiguous_output_range<u
int8_t> OutR>
384 ranges::assert_exact_byte_length<sizeof(T)>(out_range);
385 std::span out{out_range};
386 if constexpr(
sizeof(
T) == 1) {
387 out[0] =
static_cast<uint8_t
>(in);
389#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
391#elif defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
394 [&]<
size_t... i>(std::index_sequence<i...>) {
395 ((out[i] =
get_byte<
sizeof(
T) - i - 1>(in)), ...);
397 (std::make_index_sequence<sizeof(T)>());
407template <std::
unsigned_
integral T>
408inline constexpr void store_be(
T in, uint8_t out[
sizeof(
T)]) {
409 store_be(in, std::span<uint8_t,
sizeof(
T)>(out,
sizeof(
T)));
417template <std::
unsigned_
integral T>
418inline constexpr void store_le(
T in, uint8_t out[
sizeof(
T)]) {
419 store_le(in, std::span<uint8_t,
sizeof(
T)>(out,
sizeof(
T)));
427template <ranges::contiguous_output_range<u
int8_t> OutR, std::
unsigned_
integral... Ts>
428 requires(
sizeof...(Ts) > 0) && all_same_v<Ts...>
429inline constexpr void store_be(OutR&& out, Ts... ins) {
431 auto store_one = [off = 0]<
typename T>(
auto o,
T i)
mutable {
432 store_be<T>(i, o.subspan(off).template first<
sizeof(
T)>());
436 (store_one(std::span{out}, ins), ...);
444template <ranges::contiguous_output_range<u
int8_t> OutR, std::
unsigned_
integral... Ts>
445 requires(
sizeof...(Ts) > 0) && all_same_v<Ts...>
446inline constexpr void store_le(OutR&& out, Ts... ins) {
448 auto store_one = [off = 0]<
typename T>(
auto o,
T i)
mutable {
449 store_le<T>(i, o.subspan(off).template first<
sizeof(
T)>());
453 (store_one(std::span{out}, ins), ...);
461template <std::unsigned_integral... Ts>
462 requires(
sizeof...(Ts) > 0) && all_same_v<Ts...>
463inline constexpr void store_be(uint8_t out[], Ts... ins) {
464 constexpr auto bytes = (
sizeof(ins) + ...);
466 store_be(std::span<uint8_t, bytes>(out, bytes), ins...);
474template <std::unsigned_integral... Ts>
475 requires(
sizeof...(Ts) > 0) && all_same_v<Ts...>
476inline constexpr void store_le(uint8_t out[], Ts... ins) {
477 constexpr auto bytes = (
sizeof(ins) + ...);
479 store_le(std::span<uint8_t, bytes>(out, bytes), ins...);
487template <std::
unsigned_
integral T>
489 std::array<uint8_t,
sizeof(
T)> out;
499template <std::
unsigned_
integral T>
501 std::array<uint8_t,
sizeof(
T)> out;
508 while(out_bytes >=
sizeof(
T)) {
511 out_bytes -=
sizeof(
T);
515 for(
size_t i = 0; i != out_bytes; ++i) {
520template <
typename T,
typename Alloc>
521void copy_out_vec_be(uint8_t out[],
size_t out_bytes,
const std::vector<T, Alloc>& in) {
527 while(out_bytes >=
sizeof(
T)) {
530 out_bytes -=
sizeof(
T);
534 for(
size_t i = 0; i != out_bytes; ++i) {
539template <
typename T,
typename Alloc>
540void copy_out_vec_le(uint8_t out[],
size_t out_bytes,
const std::vector<T, Alloc>& in) {
consteval auto default_load_type(InR &&r)
constexpr void assert_exact_byte_length(R &&r)
constexpr uint8_t get_byte(T input)
void copy_out_le(uint8_t out[], size_t out_bytes, const T in[])
constexpr void store_be(T in, OutR &&out_range)
constexpr uint64_t make_uint64(uint8_t i0, uint8_t i1, uint8_t i2, uint8_t i3, uint8_t i4, uint8_t i5, uint8_t i6, uint8_t i7)
constexpr T load_le(InR &&in_range)
constexpr void typecast_copy(ToR &&out, FromR &&in)
void copy_out_vec_le(uint8_t out[], size_t out_bytes, const std::vector< T, Alloc > &in)
constexpr void store_le(T in, OutR &&out_range)
constexpr uint32_t make_uint32(uint8_t i0, uint8_t i1, uint8_t i2, uint8_t i3)
constexpr uint16_t reverse_bytes(uint16_t x)
constexpr uint8_t get_byte_var(size_t byte_num, T input)
constexpr T load_be(InR &&in_range)
void copy_out_be(uint8_t out[], size_t out_bytes, const T in[])
void copy_out_vec_be(uint8_t out[], size_t out_bytes, const std::vector< T, Alloc > &in)
constexpr uint16_t make_uint16(uint8_t i0, uint8_t i1)