Botan 3.9.0
Crypto and TLS for C&
Botan::detail Namespace Reference

Classes

struct  AutoDetect
class  bitvector_iterator
class  Bounded_XOF
class  Container_Strong_Adapter_Base
struct  first_type
class  Strong_Adapter
class  Strong_Adapter< T >
class  Strong_Base
struct  wrapped_type_helper
struct  wrapped_type_helper< T >
struct  wrapped_type_helper_with_enum
struct  wrapped_type_helper_with_enum< T >

Concepts

concept  is_blockwise_processing_callback_return_type
concept  blockwise_processing_callback_without_mask
concept  blockwise_processing_callback_with_mask
concept  blockwise_processing_callback
concept  manipulating_blockwise_processing_callback
concept  predicate_blockwise_processing_callback
concept  custom_loadable
concept  custom_storable
concept  unsigned_integralish

Typedefs

template<typename OutT, typename>
using as = OutT
template<typename FnT, std::unsigned_integral BlockT, typename... ParamTs>
using blockwise_processing_callback_return_type = std::invoke_result_t<FnT, as<BlockT, ParamTs>...>
template<typename... Ts>
using first_t = typename first_type<Ts...>::type
template<unsigned_integralish T>
using wrapped_type = typename wrapped_type_helper_with_enum<T>::type

Functions

template<ranges::spanable_range OutR, ranges::spanable_range... Rs>
requires (concepts::reservable_container<OutR> || ranges::statically_spanable_range<OutR>)
constexpr OutR concatenate (Rs &&... ranges)
template<bitvectorish T1, bitvectorish T2>
constexpr auto copy_lhs_allocator_aware (const T1 &lhs, const T2 &)
template<std::endian endianness, unsigned_integralish T>
size_t copy_out_any_word_aligned_portion (std::span< uint8_t > &out, std::span< const T > &in)
template<std::endian endianness, std::unsigned_integral OutT, ranges::contiguous_range< uint8_t > InR>
constexpr OutT fallback_load_any (const InR &in_range)
template<std::endian endianness, std::unsigned_integral InT, ranges::contiguous_output_range< uint8_t > OutR>
constexpr void fallback_store_any (InT in, OutR &&out_range)
template<std::endian endianness, typename OutT, ranges::contiguous_range< uint8_t > InR, unsigned_integralish... Ts>
requires (sizeof...(Ts) > 0) && ((std::same_as<AutoDetect, OutT> && all_same_v<Ts...>) || (unsigned_integralish<OutT> && all_same_v<OutT, Ts...>))
constexpr void load_any (const InR &in, Ts &... outs)
template<std::endian endianness, unsigned_integralish WrappedOutT, ranges::contiguous_range< uint8_t > InR>
requires (custom_loadable<strong_type_wrapped_type<WrappedOutT>>)
constexpr WrappedOutT load_any (const InR &in_range)
template<std::endian endianness, unsigned_integralish OutT>
constexpr OutT load_any (const uint8_t in[], size_t off)
template<std::endian endianness, typename OutT, unsigned_integralish... Ts>
requires (sizeof...(Ts) > 0 && all_same_v<Ts...> && ((std::same_as<AutoDetect, OutT> && all_same_v<Ts...>) || (unsigned_integralish<OutT> && all_same_v<OutT, Ts...>)))
constexpr void load_any (const uint8_t in[], Ts &... outs)
template<std::endian endianness, unsigned_integralish WrappedOutT, ranges::contiguous_range< uint8_t > InR>
requires (!custom_loadable<strong_type_wrapped_type<WrappedOutT>>)
constexpr WrappedOutT load_any (InR &&in_range)
template<std::endian endianness, typename OutT, ranges::contiguous_range< uint8_t > InR>
requires (std::same_as<AutoDetect, OutT> || ((ranges::statically_spanable_range<OutT> || concepts::resizable_container<OutT>) && unsigned_integralish<typename OutT::value_type>))
constexpr auto load_any (InR &&in_range)
template<std::endian endianness, typename OutT, ranges::contiguous_output_range OutR, ranges::contiguous_range< uint8_t > InR>
requires (unsigned_integralish<std::ranges::range_value_t<OutR>> && (std::same_as<AutoDetect, OutT> || std::same_as<OutT, std::ranges::range_value_t<OutR>>))
constexpr void load_any (OutR &&out, const InR &in)
template<std::endian endianness, typename OutT, unsigned_integralish T>
requires (std::same_as<AutoDetect, OutT> || std::same_as<T, OutT>)
constexpr void load_any (T out[], const uint8_t in[], size_t count)
consteval std::endian opposite (std::endian endianness)
template<std::endian endianness, typename OutR, ranges::spanable_range InR>
requires (std::same_as<AutoDetect, OutR> || (ranges::statically_spanable_range<OutR> && std::default_initializable<OutR>) || concepts::resizable_byte_buffer<OutR>)
constexpr auto store_any (InR &&in_range)
template<std::endian endianness, typename InT, ranges::contiguous_output_range< uint8_t > OutR, ranges::spanable_range InR>
requires (std::same_as<AutoDetect, InT> || std::same_as<InT, std::ranges::range_value_t<InR>>)
constexpr void store_any (OutR &&out, const InR &in)
template<std::endian endianness, typename InT, ranges::contiguous_output_range< uint8_t > OutR, unsigned_integralish... Ts>
requires (sizeof...(Ts) > 0) && ((std::same_as<AutoDetect, InT> && all_same_v<Ts...>) || (unsigned_integralish<InT> && all_same_v<InT, Ts...>))
constexpr void store_any (OutR &&out, Ts... ins)
template<std::endian endianness, typename InT, unsigned_integralish T, ranges::contiguous_output_range< uint8_t > OutR>
requires std::same_as<AutoDetect, InT>
constexpr void store_any (T in, OutR &&out_range)
template<std::endian endianness, typename InT, unsigned_integralish T>
requires (std::same_as<AutoDetect, InT> || std::same_as<T, InT>)
constexpr void store_any (T in, uint8_t out[])
template<std::endian endianness, typename OutR, unsigned_integralish... Ts>
requires all_same_v<Ts...>
constexpr auto store_any (Ts... ins)
template<std::endian endianness, typename InT, unsigned_integralish T0, unsigned_integralish... Ts>
requires (std::same_as<AutoDetect, InT> || std::same_as<T0, InT>) && all_same_v<T0, Ts...>
constexpr void store_any (uint8_t out[], T0 in0, Ts... ins)
template<std::endian endianness, unsigned_integralish WrappedInT, ranges::contiguous_output_range< uint8_t > OutR>
requires (custom_storable<strong_type_wrapped_type<WrappedInT>>)
constexpr void store_any (WrappedInT wrapped_in, const OutR &out_range)
template<std::endian endianness, unsigned_integralish WrappedInT, ranges::contiguous_output_range< uint8_t > OutR>
requires (!custom_storable<strong_type_wrapped_type<WrappedInT>>)
constexpr void store_any (WrappedInT wrapped_in, OutR &&out_range)
template<unsigned_integralish InT>
constexpr auto unwrap_strong_type_or_enum (InT t)
template<unsigned_integralish OutT, std::unsigned_integral T>
constexpr auto wrap_strong_type_or_enum (T t)

Variables

template<typename CapabilityT, typename... Tags>
constexpr bool has_capability = (std::is_same_v<CapabilityT, Tags> || ...)

Typedef Documentation

◆ as

template<typename OutT, typename>
using Botan::detail::as = OutT

Definition at line 74 of file bitvector.h.

◆ blockwise_processing_callback_return_type

template<typename FnT, std::unsigned_integral BlockT, typename... ParamTs>
using Botan::detail::blockwise_processing_callback_return_type = std::invoke_result_t<FnT, as<BlockT, ParamTs>...>

Definition at line 77 of file bitvector.h.

◆ first_t

template<typename... Ts>
using Botan::detail::first_t = typename first_type<Ts...>::type

Definition at line 63 of file bitvector.h.

◆ wrapped_type

template<unsigned_integralish T>
using Botan::detail::wrapped_type = typename wrapped_type_helper_with_enum<T>::type

Definition at line 187 of file loadstor.h.

Function Documentation

◆ concatenate()

template<ranges::spanable_range OutR, ranges::spanable_range... Rs>
requires (concepts::reservable_container<OutR> || ranges::statically_spanable_range<OutR>)
OutR Botan::detail::concatenate ( Rs &&... ranges)
constexpr

Helper function that performs range size-checks as required given the selected output and input range types. If all lengths are known at compile time, this check will be performed at compile time as well. It will then instantiate an output range and concatenate the input ranges' contents.

Definition at line 196 of file stl_util.h.

198{
199 OutR result{};
200
201 // Prepare and validate the output range and construct a lambda that does the
202 // actual filling of the result buffer.
203 // (if no input ranges are given, GCC claims that fill_fn is unused)
204 [[maybe_unused]] auto fill_fn = [&] {
206 // dynamically allocate the correct result byte length
207 const size_t total_size = (ranges.size() + ... + 0);
208 result.reserve(total_size);
209
210 // fill the result buffer using a back-inserter
211 return [&result](auto&& range) {
212 std::copy(
213 std::ranges::begin(range), std::ranges::end(range), std::back_inserter(unwrap_strong_type(result)));
214 };
215 } else {
216 if constexpr((ranges::statically_spanable_range<Rs> && ... && true)) {
217 // all input ranges have a static extent, so check the total size at compile time
218 // (work around an issue in MSVC that warns `total_size` is unused)
219 [[maybe_unused]] constexpr size_t total_size = (decltype(std::span{ranges})::extent + ... + 0);
220 static_assert(result.size() == total_size, "size of result buffer does not match the sum of input buffers");
221 } else {
222 // at least one input range has a dynamic extent, so check the total size at runtime
223 const size_t total_size = (ranges.size() + ... + 0);
224 BOTAN_ARG_CHECK(result.size() == total_size,
225 "result buffer has static extent that does not match the sum of input buffers");
226 }
227
228 // fill the result buffer and hold the current output-iterator position
229 return [itr = std::ranges::begin(result)](auto&& range) mutable {
230 std::copy(std::ranges::begin(range), std::ranges::end(range), itr);
231 std::advance(itr, std::ranges::size(range));
232 };
233 }
234 }();
235
236 // perform the actual concatenation
237 (fill_fn(std::forward<Rs>(ranges)), ...);
238
239 return result;
240}
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:33
constexpr decltype(auto) unwrap_strong_type(T &&t)
Generically unwraps a strong type to its underlying type.

References BOTAN_ARG_CHECK, and Botan::unwrap_strong_type().

Referenced by Botan::concat().

◆ copy_lhs_allocator_aware()

template<bitvectorish T1, bitvectorish T2>
auto Botan::detail::copy_lhs_allocator_aware ( const T1 & lhs,
const T2 &  )
constexpr

If one of the allocators is a Botan::secure_allocator, this will always prefer it. Otherwise, the allocator of lhs will be used as a default.

Definition at line 1313 of file bitvector.h.

1313 {
1314 constexpr bool needs_secure_allocator =
1316
1317 if constexpr(needs_secure_allocator) {
1318 return lhs.template as<secure_bitvector>();
1319 } else {
1320 return lhs.template as<bitvector>();
1321 }
1322}
typename detail::wrapped_type_helper< std::remove_cvref_t< T > >::type strong_type_wrapped_type
Extracts the wrapped type from a strong type.

Referenced by Botan::operator&(), Botan::operator^(), and Botan::operator|().

◆ copy_out_any_word_aligned_portion()

template<std::endian endianness, unsigned_integralish T>
size_t Botan::detail::copy_out_any_word_aligned_portion ( std::span< uint8_t > & out,
std::span< const T > & in )
inline

Definition at line 752 of file loadstor.h.

752 {
753 const size_t full_words = out.size() / sizeof(T);
754 const size_t full_word_bytes = full_words * sizeof(T);
755 const size_t remaining_bytes = out.size() - full_word_bytes;
756 BOTAN_ASSERT_NOMSG(in.size_bytes() >= full_word_bytes + remaining_bytes);
757
758 // copy full words
759 store_any<endianness, T>(out.first(full_word_bytes), in.first(full_words));
760 out = out.subspan(full_word_bytes);
761 in = in.subspan(full_words);
762
763 return remaining_bytes;
764}
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
constexpr void store_any(WrappedInT wrapped_in, OutR &&out_range)
Definition loadstor.h:525

References BOTAN_ASSERT_NOMSG, and store_any().

Referenced by Botan::copy_out_be(), and Botan::copy_out_le().

◆ fallback_load_any()

template<std::endian endianness, std::unsigned_integral OutT, ranges::contiguous_range< uint8_t > InR>
OutT Botan::detail::fallback_load_any ( const InR & in_range)
inlineconstexpr

Manually load a word from a range in either big or little endian byte order.

This is only used at compile time.

Definition at line 214 of file loadstor.h.

214 {
215 std::span in{in_range};
216 // clang-format off
217 if constexpr(endianness == std::endian::big) {
218 return [&]<size_t... i>(std::index_sequence<i...>) {
219 return static_cast<OutT>(((static_cast<OutT>(in[i]) << ((sizeof(OutT) - i - 1) * 8)) | ...));
220 } (std::make_index_sequence<sizeof(OutT)>());
221 } else {
222 static_assert(endianness == std::endian::little);
223 return [&]<size_t... i>(std::index_sequence<i...>) {
224 return static_cast<OutT>(((static_cast<OutT>(in[i]) << (i * 8)) | ...));
225 } (std::make_index_sequence<sizeof(OutT)>());
226 }
227 // clang-format on
228}

Referenced by load_any().

◆ fallback_store_any()

template<std::endian endianness, std::unsigned_integral InT, ranges::contiguous_output_range< uint8_t > OutR>
void Botan::detail::fallback_store_any ( InT in,
OutR && out_range )
inlineconstexpr

Manually store a word into a range in either big or little endian byte order.

This will be used only at compile time.

Definition at line 236 of file loadstor.h.

236 {
237 std::span out{out_range};
238 // clang-format off
239 if constexpr(endianness == std::endian::big) {
240 [&]<size_t... i>(std::index_sequence<i...>) {
241 ((out[i] = get_byte<i>(in)), ...);
242 } (std::make_index_sequence<sizeof(InT)>());
243 } else {
244 static_assert(endianness == std::endian::little);
245 [&]<size_t... i>(std::index_sequence<i...>) {
246 ((out[i] = get_byte<sizeof(InT) - i - 1>(in)), ...);
247 } (std::make_index_sequence<sizeof(InT)>());
248 }
249 // clang-format on
250}
constexpr uint8_t get_byte(T input)
Definition loadstor.h:79

References Botan::get_byte().

Referenced by store_any().

◆ load_any() [1/8]

template<std::endian endianness, typename OutT, ranges::contiguous_range< uint8_t > InR, unsigned_integralish... Ts>
requires (sizeof...(Ts) > 0) && ((std::same_as<AutoDetect, OutT> && all_same_v<Ts...>) || (unsigned_integralish<OutT> && all_same_v<OutT, Ts...>))
void Botan::detail::load_any ( const InR & in,
Ts &... outs )
inlineconstexpr

Load many unsigned integers

Parameters
ina fixed-length span to some bytes
outsa arbitrary-length parameter list of unsigned integers to be loaded

Definition at line 332 of file loadstor.h.

332 {
333 ranges::assert_exact_byte_length<(sizeof(Ts) + ...)>(in);
334 auto load_one = [off = 0]<typename T>(auto i, T& o) mutable {
335 o = load_any<endianness, T>(i.subspan(off).template first<sizeof(T)>());
336 off += sizeof(T);
337 };
338
339 (load_one(std::span{in}, outs), ...);
340}
constexpr WrappedOutT load_any(InR &&in_range)
Definition loadstor.h:278
constexpr void assert_exact_byte_length(const R &r)
Definition concepts.h:107

References Botan::ranges::assert_exact_byte_length(), and load_any().

◆ load_any() [2/8]

template<std::endian endianness, unsigned_integralish WrappedOutT, ranges::contiguous_range< uint8_t > InR>
requires (custom_loadable<strong_type_wrapped_type<WrappedOutT>>)
WrappedOutT Botan::detail::load_any ( const InR & in_range)
inlineconstexpr

Load a custom object from a range in either big or little endian byte order

This is the base implementation for custom objects (e.g. SIMD type wrappres), all other overloads are just convenience overloads.

Parameters
in_rangea fixed-length byte range
Returns
T loaded from in_range, as a big-endian value

Definition at line 313 of file loadstor.h.

313 {
316 std::span<const uint8_t, sizeof(OutT)> ins{in_range};
317 if constexpr(endianness == std::endian::big) {
318 return wrap_strong_type<WrappedOutT>(OutT::load_be(ins));
319 } else {
320 return wrap_strong_type<WrappedOutT>(OutT::load_le(ins));
321 }
322}
typename wrapped_type_helper_with_enum< T >::type wrapped_type
Definition loadstor.h:187
constexpr decltype(auto) wrap_strong_type(ParamT &&t)
Wraps a value into a caller-defined (strong) type.

References Botan::ranges::assert_exact_byte_length(), and Botan::wrap_strong_type().

◆ load_any() [3/8]

template<std::endian endianness, unsigned_integralish OutT>
OutT Botan::detail::load_any ( const uint8_t in[],
size_t off )
inlineconstexpr

Load a word from in at some offset off

Parameters
ina pointer to some bytes
offan offset into the array
Returns
off'th T of in, as a big-endian value

Definition at line 454 of file loadstor.h.

454 {
455 // asserts that *in points to enough bytes to read at offset off
456 constexpr size_t out_size = sizeof(OutT);
457 return load_any<endianness, OutT>(std::span<const uint8_t, out_size>(in + off * out_size, out_size));
458}

References load_any().

◆ load_any() [4/8]

template<std::endian endianness, typename OutT, unsigned_integralish... Ts>
requires (sizeof...(Ts) > 0 && all_same_v<Ts...> && ((std::same_as<AutoDetect, OutT> && all_same_v<Ts...>) || (unsigned_integralish<OutT> && all_same_v<OutT, Ts...>)))
void Botan::detail::load_any ( const uint8_t in[],
Ts &... outs )
inlineconstexpr

Load many words from in

Parameters
ina pointer to some bytes
outsa arbitrary-length parameter list of unsigned integers to be loaded

Definition at line 469 of file loadstor.h.

469 {
470 constexpr auto bytes = (sizeof(outs) + ...);
471 // asserts that *in points to the correct amount of memory
472 load_any<endianness, OutT>(std::span<const uint8_t, bytes>(in, bytes), outs...);
473}

References load_any().

◆ load_any() [5/8]

template<std::endian endianness, unsigned_integralish WrappedOutT, ranges::contiguous_range< uint8_t > InR>
requires (!custom_loadable<strong_type_wrapped_type<WrappedOutT>>)
WrappedOutT Botan::detail::load_any ( InR && in_range)
inlineconstexpr

Load a word from a range in either big or little endian byte order

This is the base implementation, all other overloads are just convenience wrappers. It is assumed that the range has the correct size for the word.

Template arguments of all overloads of load_any() share the same semantics:

  1. std::endian Either std::endian::big or std::endian::little, that will eventually select the byte order translation mode implemented in this base function.
  2. Output type Either AutoDetect, an unsigned integer or a container holding an unsigned integer type. AutoDetect means that the caller did not explicitly specify the type and expects the type to be inferred from the input.

3+. Argument types Typically, those are input and output ranges of bytes or unsigned integers. Or one or more unsigned integers acting as output parameters.

Parameters
in_rangea fixed-length byte range
Returns
T loaded from in_range, as a big-endian value

Definition at line 278 of file loadstor.h.

278 {
281
283 // At compile time we cannot use `typecast_copy` as it uses `std::memcpy`
284 // internally to copy ranges on a byte-by-byte basis, which is not allowed
285 // in a `constexpr` context.
286 if(std::is_constant_evaluated()) /* TODO: C++23: if consteval {} */ {
287 return fallback_load_any<endianness, OutT>(std::forward<InR>(in_range));
288 } else {
289 std::span in{in_range};
290 if constexpr(sizeof(OutT) == 1) {
291 return static_cast<OutT>(in[0]);
292 } else if constexpr(endianness == std::endian::native) {
293 return typecast_copy<OutT>(in);
294 } else {
295 static_assert(opposite(endianness) == std::endian::native);
297 }
298 }
299 }());
300}
consteval std::endian opposite(std::endian endianness)
Definition loadstor.h:136
constexpr OutT fallback_load_any(const InR &in_range)
Definition loadstor.h:214
constexpr auto wrap_strong_type_or_enum(T t)
Definition loadstor.h:200
constexpr T reverse_bytes(T x)
Definition bswap.h:27
constexpr void typecast_copy(ToR &&out, const FromR &in)
Definition mem_ops.h:177

References Botan::ranges::assert_exact_byte_length(), fallback_load_any(), opposite(), Botan::reverse_bytes(), Botan::typecast_copy(), and wrap_strong_type_or_enum().

Referenced by load_any(), load_any(), load_any(), load_any(), load_any(), load_any(), Botan::load_be(), and Botan::load_le().

◆ load_any() [6/8]

template<std::endian endianness, typename OutT, ranges::contiguous_range< uint8_t > InR>
requires (std::same_as<AutoDetect, OutT> || ((ranges::statically_spanable_range<OutT> || concepts::resizable_container<OutT>) && unsigned_integralish<typename OutT::value_type>))
auto Botan::detail::load_any ( InR && in_range)
inlineconstexpr

Load one or more unsigned integers, auto-detect the output type if possible. Otherwise, use the specified integer or integer container type.

Parameters
in_rangea statically-sized range with some bytes
Returns
T loaded from in

Definition at line 397 of file loadstor.h.

397 {
398 auto out = []([[maybe_unused]] const auto& in) {
399 if constexpr(std::same_as<AutoDetect, OutT>) {
401 constexpr size_t extent = decltype(std::span{in})::extent;
402
403 // clang-format off
404 using type =
405 std::conditional_t<extent == 1, uint8_t,
406 std::conditional_t<extent == 2, uint16_t,
407 std::conditional_t<extent == 4, uint32_t,
408 std::conditional_t<extent == 8, uint64_t, void>>>>;
409 // clang-format on
410
411 static_assert(
412 !std::is_void_v<type>,
413 "Cannot determine the output type based on a statically sized bytearray with length other than those: 1, 2, 4, 8");
414
415 return type{};
416 } else {
417 static_assert(
418 !std::same_as<AutoDetect, OutT>,
419 "cannot infer return type from a dynamic range at compile time, please specify it explicitly");
420 }
421 } else if constexpr(concepts::resizable_container<OutT>) {
422 const size_t in_bytes = std::span{in}.size_bytes();
423 constexpr size_t out_elem_bytes = sizeof(typename OutT::value_type);
424 BOTAN_ARG_CHECK(in_bytes % out_elem_bytes == 0,
425 "Input range is not word-aligned with the requested output range");
426 return OutT(in_bytes / out_elem_bytes);
427 } else {
428 return OutT{};
429 }
430 }(in_range);
431
432 using out_type = decltype(out);
433 if constexpr(unsigned_integralish<out_type>) {
434 out = load_any<endianness, out_type>(std::forward<InR>(in_range));
435 } else {
436 static_assert(ranges::contiguous_range<out_type>);
437 using out_range_type = std::ranges::range_value_t<out_type>;
438 load_any<endianness, out_range_type>(out, std::forward<InR>(in_range));
439 }
440 return out;
441}

References BOTAN_ARG_CHECK, and load_any().

◆ load_any() [7/8]

template<std::endian endianness, typename OutT, ranges::contiguous_output_range OutR, ranges::contiguous_range< uint8_t > InR>
requires (unsigned_integralish<std::ranges::range_value_t<OutR>> && (std::same_as<AutoDetect, OutT> || std::same_as<OutT, std::ranges::range_value_t<OutR>>))
void Botan::detail::load_any ( OutR && out,
const InR & in )
inlineconstexpr

Load a variable number of words from in into out. The byte length of the out and in ranges must match.

Parameters
outthe output range of words
inthe input range of bytes

Definition at line 355 of file loadstor.h.

355 {
357 using element_type = std::ranges::range_value_t<OutR>;
358
359 auto load_elementwise = [&] {
360 constexpr size_t bytes_per_element = sizeof(element_type);
361 std::span<const uint8_t> in_s(in);
362 for(auto& out_elem : out) {
363 out_elem = load_any<endianness, element_type>(in_s.template first<bytes_per_element>());
364 in_s = in_s.subspan(bytes_per_element);
365 }
366 };
367
368 // At compile time we cannot use `typecast_copy` as it uses `std::memcpy`
369 // internally to copy ranges on a byte-by-byte basis, which is not allowed
370 // in a `constexpr` context.
371 if(std::is_constant_evaluated()) /* TODO: C++23: if consteval {} */ {
372 load_elementwise();
373 } else {
374 if constexpr(endianness == std::endian::native && !custom_loadable<element_type>) {
375 typecast_copy(out, in);
376 } else {
377 load_elementwise();
378 }
379 }
380}
constexpr void assert_equal_byte_lengths(const R0 &r0, const Rs &... rs)
Definition concepts.h:128

References Botan::ranges::assert_equal_byte_lengths(), load_any(), and Botan::typecast_copy().

◆ load_any() [8/8]

template<std::endian endianness, typename OutT, unsigned_integralish T>
requires (std::same_as<AutoDetect, OutT> || std::same_as<T, OutT>)
void Botan::detail::load_any ( T out[],
const uint8_t in[],
size_t count )
inlineconstexpr

Load a variable number of words from in into out.

Parameters
outthe output array of words
inthe input array of bytes
counthow many words are in in

Definition at line 483 of file loadstor.h.

483 {
484 // asserts that *in and *out point to the correct amount of memory
485 load_any<endianness, OutT>(std::span<T>(out, count), std::span<const uint8_t>(in, count * sizeof(T)));
486}

References load_any().

◆ opposite()

std::endian Botan::detail::opposite ( std::endian endianness)
consteval
Returns
the opposite endianness of the specified endianness

Note this assumes that there are only two endian orderings; we do not supported mixed endian systems

Definition at line 136 of file loadstor.h.

136 {
137 if(endianness == std::endian::big) {
138 return std::endian::little;
139 } else {
140 // We already verified via static assert earlier in this file that we are
141 // running on either a big endian or little endian system
142 return std::endian::big;
143 }
144}

Referenced by load_any(), and store_any().

◆ store_any() [1/9]

template<std::endian endianness, typename OutR, ranges::spanable_range InR>
requires (std::same_as<AutoDetect, OutR> || (ranges::statically_spanable_range<OutR> && std::default_initializable<OutR>) || concepts::resizable_byte_buffer<OutR>)
auto Botan::detail::store_any ( InR && in_range)
inlineconstexpr

The caller provided some integer values in a collection but did not provide the output container. Let's create one for them, fill it with one of the overloads above and return it. This will default to a std::array if the caller did not specify the desired output container type.

Parameters
in_rangea range of words that should be stored
Returns
a container of bytes that contains the stored words

Definition at line 663 of file loadstor.h.

663 {
664 auto out = []([[maybe_unused]] const auto& in) {
665 if constexpr(std::same_as<AutoDetect, OutR>) {
667 constexpr size_t bytes = decltype(std::span{in})::extent * sizeof(std::ranges::range_value_t<InR>);
668 return std::array<uint8_t, bytes>();
669 } else {
670 static_assert(
671 !std::same_as<AutoDetect, OutR>,
672 "cannot infer a suitable result container type from the given parameters at compile time, please specify it explicitly");
673 }
674 } else if constexpr(concepts::resizable_byte_buffer<OutR>) {
675 return OutR(std::span{in}.size_bytes());
676 } else {
677 return OutR{};
678 }
679 }(in_range);
680
681 store_any<endianness, std::ranges::range_value_t<InR>>(out, std::forward<InR>(in_range));
682 return out;
683}

References store_any().

◆ store_any() [2/9]

template<std::endian endianness, typename InT, ranges::contiguous_output_range< uint8_t > OutR, ranges::spanable_range InR>
requires (std::same_as<AutoDetect, InT> || std::same_as<InT, std::ranges::range_value_t<InR>>)
void Botan::detail::store_any ( OutR && out,
const InR & in )
inlineconstexpr

Store a variable number of words given in in into out. The byte lengths of in and out must be consistent.

Parameters
outthe output range of bytes
inthe input range of words

Definition at line 603 of file loadstor.h.

603 {
605 using element_type = std::ranges::range_value_t<InR>;
606
607 auto store_elementwise = [&] {
608 constexpr size_t bytes_per_element = sizeof(element_type);
609 std::span<uint8_t> out_s(out);
610 for(auto in_elem : in) {
611 store_any<endianness, element_type>(out_s.template first<bytes_per_element>(), in_elem);
612 out_s = out_s.subspan(bytes_per_element);
613 }
614 };
615
616 // At compile time we cannot use `typecast_copy` as it uses `std::memcpy`
617 // internally to copy ranges on a byte-by-byte basis, which is not allowed
618 // in a `constexpr` context.
619 if(std::is_constant_evaluated()) /* TODO: C++23: if consteval {} */ {
620 store_elementwise();
621 } else {
622 if constexpr(endianness == std::endian::native && !custom_storable<element_type>) {
623 typecast_copy(out, in);
624 } else {
625 store_elementwise();
626 }
627 }
628}

References Botan::ranges::assert_equal_byte_lengths(), store_any(), and Botan::typecast_copy().

◆ store_any() [3/9]

template<std::endian endianness, typename InT, ranges::contiguous_output_range< uint8_t > OutR, unsigned_integralish... Ts>
requires (sizeof...(Ts) > 0) && ((std::same_as<AutoDetect, InT> && all_same_v<Ts...>) || (unsigned_integralish<InT> && all_same_v<InT, Ts...>))
void Botan::detail::store_any ( OutR && out,
Ts... ins )
inlineconstexpr

Store many unsigned integers words into a byte range

Parameters
outa sized range of some bytes
insa arbitrary-length parameter list of unsigned integers to be stored

Definition at line 582 of file loadstor.h.

582 {
583 ranges::assert_exact_byte_length<(sizeof(Ts) + ...)>(out);
584 auto store_one = [off = 0]<typename T>(auto o, T i) mutable {
585 store_any<endianness, T>(i, o.subspan(off).template first<sizeof(T)>());
586 off += sizeof(T);
587 };
588
589 (store_one(std::span{out}, ins), ...);
590}

References Botan::ranges::assert_exact_byte_length(), and store_any().

◆ store_any() [4/9]

template<std::endian endianness, typename InT, unsigned_integralish T, ranges::contiguous_output_range< uint8_t > OutR>
requires std::same_as<AutoDetect, InT>
void Botan::detail::store_any ( T in,
OutR && out_range )
inlineconstexpr

Infer InT from a single unsigned integer input parameter.

TODO: we might consider dropping this overload (i.e. out-range as second parameter) and make this a "special case" of the overload below, that takes a variadic number of input parameters.

Parameters
inan unsigned integer to be stored
out_rangea range of bytes to store the word into

Definition at line 646 of file loadstor.h.

646 {
647 store_any<endianness, T>(in, std::forward<OutR>(out_range));
648}

References store_any().

◆ store_any() [5/9]

template<std::endian endianness, typename InT, unsigned_integralish T>
requires (std::same_as<AutoDetect, InT> || std::same_as<T, InT>)
void Botan::detail::store_any ( T in,
uint8_t out[] )
inlineconstexpr

Store a single unsigned integer into a raw pointer

Parameters
inthe input unsigned integer
outthe byte array to write to

Definition at line 711 of file loadstor.h.

711 {
712 // asserts that *out points to enough bytes to write into
713 store_any<endianness, InT>(in, std::span<uint8_t, sizeof(T)>(out, sizeof(T)));
714}

References store_any().

◆ store_any() [6/9]

template<std::endian endianness, typename OutR, unsigned_integralish... Ts>
requires all_same_v<Ts...>
auto Botan::detail::store_any ( Ts... ins)
inlineconstexpr

The caller provided some integer values but did not provide the output container. Let's create one for them, fill it with one of the overloads above and return it. This will default to a std::array if the caller did not specify the desired output container type.

Parameters
inssome words that should be stored
Returns
a container of bytes that contains the stored words

Definition at line 696 of file loadstor.h.

696 {
697 return store_any<endianness, OutR>(std::array{ins...});
698}

References store_any().

◆ store_any() [7/9]

template<std::endian endianness, typename InT, unsigned_integralish T0, unsigned_integralish... Ts>
requires (std::same_as<AutoDetect, InT> || std::same_as<T0, InT>) && all_same_v<T0, Ts...>
void Botan::detail::store_any ( uint8_t out[],
T0 in0,
Ts... ins )
inlineconstexpr

Store many unsigned integers words into a raw pointer

Parameters
insa arbitrary-length parameter list of unsigned integers to be stored
outthe byte array to write to

Definition at line 723 of file loadstor.h.

723 {
724 constexpr auto bytes = sizeof(in0) + (sizeof(ins) + ... + 0);
725 // asserts that *out points to the correct amount of memory
726 store_any<endianness, T0>(std::span<uint8_t, bytes>(out, bytes), in0, ins...);
727}

References store_any().

◆ store_any() [8/9]

template<std::endian endianness, unsigned_integralish WrappedInT, ranges::contiguous_output_range< uint8_t > OutR>
requires (custom_storable<strong_type_wrapped_type<WrappedInT>>)
void Botan::detail::store_any ( WrappedInT wrapped_in,
const OutR & out_range )
inlineconstexpr

Store a custom word in either big or little endian byte order into a range

This is the base implementation for storing custom objects, all other overloads are just convenience overloads.

Parameters
wrapped_ina custom object to be stored
out_rangea byte range to store the word into

Definition at line 559 of file loadstor.h.

559 {
560 const auto in = detail::unwrap_strong_type_or_enum(wrapped_in);
561 using InT = decltype(in);
563 std::span<uint8_t, sizeof(InT)> outs{out_range};
564 if constexpr(endianness == std::endian::big) {
565 in.store_be(outs);
566 } else {
567 in.store_le(outs);
568 }
569}
constexpr auto unwrap_strong_type_or_enum(InT t)
Definition loadstor.h:190

References Botan::ranges::assert_exact_byte_length(), and unwrap_strong_type_or_enum().

◆ store_any() [9/9]

template<std::endian endianness, unsigned_integralish WrappedInT, ranges::contiguous_output_range< uint8_t > OutR>
requires (!custom_storable<strong_type_wrapped_type<WrappedInT>>)
void Botan::detail::store_any ( WrappedInT wrapped_in,
OutR && out_range )
inlineconstexpr

Store a word in either big or little endian byte order into a range

This is the base implementation, all other overloads are just convenience wrappers. It is assumed that the range has the correct size for the word.

Template arguments of all overloads of store_any() share the same semantics as those of load_any(). See the documentation of this function for more details.

Parameters
wrapped_inan unsigned integral to be stored
out_rangea byte range to store the word into

Definition at line 525 of file loadstor.h.

525 {
526 const auto in = detail::unwrap_strong_type_or_enum(wrapped_in);
527 using InT = decltype(in);
529 std::span out{out_range};
530
531 // At compile time we cannot use `typecast_copy` as it uses `std::memcpy`
532 // internally to copy ranges on a byte-by-byte basis, which is not allowed
533 // in a `constexpr` context.
534 if(std::is_constant_evaluated()) /* TODO: C++23: if consteval {} */ {
535 return fallback_store_any<endianness, InT>(in, std::forward<OutR>(out_range));
536 } else {
537 if constexpr(sizeof(InT) == 1) {
538 out[0] = static_cast<uint8_t>(in);
539 } else if constexpr(endianness == std::endian::native) {
540 typecast_copy(out, in);
541 } else {
542 static_assert(opposite(endianness) == std::endian::native);
544 }
545 }
546}
constexpr void fallback_store_any(InT in, OutR &&out_range)
Definition loadstor.h:236

References Botan::ranges::assert_exact_byte_length(), fallback_store_any(), opposite(), Botan::reverse_bytes(), Botan::typecast_copy(), and unwrap_strong_type_or_enum().

Referenced by copy_out_any_word_aligned_portion(), store_any(), store_any(), store_any(), store_any(), store_any(), store_any(), store_any(), Botan::store_be(), and Botan::store_le().

◆ unwrap_strong_type_or_enum()

template<unsigned_integralish InT>
auto Botan::detail::unwrap_strong_type_or_enum ( InT t)
constexpr

Definition at line 190 of file loadstor.h.

190 {
191 if constexpr(std::is_enum_v<InT>) {
192 // TODO: C++23: use std::to_underlying(in) instead
193 return static_cast<std::underlying_type_t<InT>>(t);
194 } else {
196 }
197}

References Botan::unwrap_strong_type().

Referenced by store_any(), and store_any().

◆ wrap_strong_type_or_enum()

template<unsigned_integralish OutT, std::unsigned_integral T>
auto Botan::detail::wrap_strong_type_or_enum ( T t)
constexpr

Definition at line 200 of file loadstor.h.

200 {
201 if constexpr(std::is_enum_v<OutT>) {
202 return static_cast<OutT>(t);
203 } else {
205 }
206}

References Botan::wrap_strong_type().

Referenced by load_any().

Variable Documentation

◆ has_capability

template<typename CapabilityT, typename... Tags>
bool Botan::detail::has_capability = (std::is_same_v<CapabilityT, Tags> || ...)
constexpr

Checks whether the CapabilityT is included in the Tags type pack.

Definition at line 32 of file strong_type.h.