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

Classes

struct  AutoDetect
 
class  Bounded_XOF
 
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  custom_loadable
 
concept  custom_storable
 
concept  unsigned_integralish
 

Typedefs

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

Enumerations

enum class  Endianness : bool { Big , Little }
 

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<Endianness endianness, unsigned_integralish T>
size_t copy_out_any_word_aligned_portion (std::span< uint8_t > &out, std::span< const T > &in)
 
template<Endianness endianness, std::unsigned_integral OutT, ranges::contiguous_range< uint8_t > InR>
constexpr OutT fallback_load_any (InR &&in_range)
 
template<Endianness endianness, std::unsigned_integral InT, ranges::contiguous_output_range< uint8_t > OutR>
constexpr void fallback_store_any (InT in, OutR &&out_range)
 
constexpr bool is_native (Endianness endianness)
 
constexpr bool is_opposite (Endianness endianness)
 
template<Endianness endianness, unsigned_integralish OutT>
constexpr OutT load_any (const uint8_t in[], size_t off)
 
template<Endianness 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<Endianness 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 (InR &&in, Ts &... outs)
 
template<Endianness 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<Endianness 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<Endianness 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<Endianness 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, InR &&in)
 
template<Endianness 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)
 
template<Endianness endianness>
constexpr bool native_endianness_is_unknown ()
 
template<Endianness 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<Endianness 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, InR &&in)
 
template<Endianness 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<Endianness 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<Endianness 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<Endianness endianness, typename OutR , unsigned_integralish... Ts>
requires all_same_v<Ts...>
constexpr auto store_any (Ts... ins)
 
template<Endianness 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<Endianness 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<Endianness 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

◆ wrapped_type

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

Definition at line 211 of file loadstor.h.

Enumeration Type Documentation

◆ Endianness

enum class Botan::detail::Endianness : bool
strong
Enumerator
Big 
Little 

Definition at line 126 of file loadstor.h.

126 : bool {
127 Big,
128 Little,
129};

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 204 of file stl_util.h.

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

template<Endianness 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 780 of file loadstor.h.

780 {
781 const size_t full_words = out.size() / sizeof(T);
782 const size_t full_word_bytes = full_words * sizeof(T);
783 const size_t remaining_bytes = out.size() - full_word_bytes;
784 BOTAN_ASSERT_NOMSG(in.size_bytes() >= full_word_bytes + remaining_bytes);
785
786 // copy full words
787 store_any<endianness, T>(out.first(full_word_bytes), in.first(full_words));
788 out = out.subspan(full_word_bytes);
789 in = in.subspan(full_words);
790
791 return remaining_bytes;
792}
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:59
FE_25519 T
Definition ge.cpp:34

References BOTAN_ASSERT_NOMSG, store_any(), and T.

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

◆ fallback_load_any()

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

Manually load a word from a range in either big or little endian byte order. This will be used only if the endianness of the target platform is unknown at compile time.

Definition at line 238 of file loadstor.h.

238 {
239 std::span in{in_range};
240 // clang-format off
241 if constexpr(endianness == Endianness::Big) {
242 return [&]<size_t... i>(std::index_sequence<i...>) {
243 return static_cast<OutT>(((static_cast<OutT>(in[i]) << ((sizeof(OutT) - i - 1) * 8)) | ...));
244 } (std::make_index_sequence<sizeof(OutT)>());
245 } else {
246 static_assert(endianness == Endianness::Little);
247 return [&]<size_t... i>(std::index_sequence<i...>) {
248 return static_cast<OutT>(((static_cast<OutT>(in[i]) << (i * 8)) | ...));
249 } (std::make_index_sequence<sizeof(OutT)>());
250 }
251 // clang-format on
252}

References Big, and Little.

Referenced by load_any().

◆ fallback_store_any()

template<Endianness 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 if the endianness of the target platform is unknown at compile time.

Definition at line 260 of file loadstor.h.

260 {
261 std::span out{out_range};
262 // clang-format off
263 if constexpr(endianness == Endianness::Big) {
264 [&]<size_t... i>(std::index_sequence<i...>) {
265 ((out[i] = get_byte<i>(in)), ...);
266 } (std::make_index_sequence<sizeof(InT)>());
267 } else {
268 static_assert(endianness == Endianness::Little);
269 [&]<size_t... i>(std::index_sequence<i...>) {
270 ((out[i] = get_byte<sizeof(InT) - i - 1>(in)), ...);
271 } (std::make_index_sequence<sizeof(InT)>());
272 }
273 // clang-format on
274}
constexpr uint8_t get_byte(T input)
Definition loadstor.h:75

References Big, Botan::get_byte(), and Little.

Referenced by store_any().

◆ is_native()

bool Botan::detail::is_native ( Endianness endianness)
constexpr
Warning
This function may return false if the native endianness is unknown
Returns
true iff the native endianness matches the given endianness

Definition at line 135 of file loadstor.h.

135 {
136#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
137 return endianness == Endianness::Big;
138#elif defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
139 return endianness == Endianness::Little;
140#else
141 BOTAN_UNUSED(endianness);
142 return false;
143#endif
144}
#define BOTAN_UNUSED
Definition assert.h:118

References Big, BOTAN_UNUSED, and Little.

Referenced by load_any(), load_any(), store_any(), and store_any().

◆ is_opposite()

bool Botan::detail::is_opposite ( Endianness endianness)
constexpr
Warning
This function may return false if the native endianness is unknown
Returns
true iff the native endianness does not match the given endianness

Definition at line 150 of file loadstor.h.

150 {
151#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
152 return endianness == Endianness::Little;
153#elif defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
154 return endianness == Endianness::Big;
155#else
156 BOTAN_UNUSED(endianness);
157 return false;
158#endif
159}

References Big, BOTAN_UNUSED, and Little.

Referenced by load_any(), and store_any().

◆ load_any() [1/8]

template<Endianness 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 480 of file loadstor.h.

480 {
481 // asserts that *in points to enough bytes to read at offset off
482 constexpr size_t out_size = sizeof(OutT);
483 return load_any<endianness, OutT>(std::span<const uint8_t, out_size>(in + off * out_size, out_size));
484}

References load_any().

◆ load_any() [2/8]

template<Endianness 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 495 of file loadstor.h.

495 {
496 constexpr auto bytes = (sizeof(outs) + ...);
497 // asserts that *in points to the correct amount of memory
498 load_any<endianness, OutT>(std::span<const uint8_t, bytes>(in, bytes), outs...);
499}

References load_any().

◆ load_any() [3/8]

template<Endianness 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 ( 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 358 of file loadstor.h.

358 {
359 ranges::assert_exact_byte_length<(sizeof(Ts) + ...)>(in);
360 auto load_one = [off = 0]<typename T>(auto i, T& o) mutable {
361 o = load_any<endianness, T>(i.subspan(off).template first<sizeof(T)>());
362 off += sizeof(T);
363 };
364
365 (load_one(std::span{in}, outs), ...);
366}

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

◆ load_any() [4/8]

template<Endianness 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. Endianness Either Endianness::Big or Endianness::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 302 of file loadstor.h.

302 {
304 ranges::assert_exact_byte_length<sizeof(OutT)>(in_range);
305
306 return detail::wrap_strong_type_or_enum<WrappedOutT>([&]() -> OutT {
307 // At compile time we cannot use `typecast_copy` as it uses `std::memcpy`
308 // internally to copy ranges on a byte-by-byte basis, which is not allowed
309 // in a `constexpr` context.
310 if(std::is_constant_evaluated()) /* TODO: C++23: if consteval {} */ {
311 return fallback_load_any<endianness, OutT>(std::forward<InR>(in_range));
312 } else {
313 std::span in{in_range};
314 if constexpr(sizeof(OutT) == 1) {
315 return static_cast<OutT>(in[0]);
316 } else if constexpr(is_native(endianness)) {
317 return typecast_copy<OutT>(in);
318 } else if constexpr(is_opposite(endianness)) {
319 return reverse_bytes(typecast_copy<OutT>(in));
320 } else {
321 static_assert(native_endianness_is_unknown<endianness>());
322 return fallback_load_any<endianness, OutT>(std::forward<InR>(in_range));
323 }
324 }
325 }());
326}
constexpr bool is_opposite(Endianness endianness)
Definition loadstor.h:150
constexpr bool is_native(Endianness endianness)
Definition loadstor.h:135
typename wrapped_type_helper_with_enum< T >::type wrapped_type
Definition loadstor.h:211
constexpr T reverse_bytes(T x)
Definition bswap.h:24

References Botan::ranges::assert_exact_byte_length(), fallback_load_any(), is_native(), is_opposite(), native_endianness_is_unknown(), 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() [5/8]

template<Endianness 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 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 339 of file loadstor.h.

339 {
341 ranges::assert_exact_byte_length<sizeof(OutT)>(in_range);
342 std::span<const uint8_t, sizeof(OutT)> ins{in_range};
343 if constexpr(endianness == Endianness::Big) {
344 return wrap_strong_type<WrappedOutT>(OutT::load_be(ins));
345 } else {
346 return wrap_strong_type<WrappedOutT>(OutT::load_le(ins));
347 }
348}

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

◆ load_any() [6/8]

template<Endianness 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 423 of file loadstor.h.

423 {
424 auto out = []([[maybe_unused]] const auto& in) {
425 if constexpr(std::same_as<AutoDetect, OutT>) {
427 constexpr size_t extent = decltype(std::span{in})::extent;
428
429 // clang-format off
430 using type =
431 std::conditional_t<extent == 1, uint8_t,
432 std::conditional_t<extent == 2, uint16_t,
433 std::conditional_t<extent == 4, uint32_t,
434 std::conditional_t<extent == 8, uint64_t, void>>>>;
435 // clang-format on
436
437 static_assert(
438 !std::is_void_v<type>,
439 "Cannot determine the output type based on a statically sized bytearray with length other than those: 1, 2, 4, 8");
440
441 return type{};
442 } else {
443 static_assert(
444 !std::same_as<AutoDetect, OutT>,
445 "cannot infer return type from a dynamic range at compile time, please specify it explicitly");
446 }
447 } else if constexpr(concepts::resizable_container<OutT>) {
448 const size_t in_bytes = std::span{in}.size_bytes();
449 constexpr size_t out_elem_bytes = sizeof(typename OutT::value_type);
450 BOTAN_ARG_CHECK(in_bytes % out_elem_bytes == 0,
451 "Input range is not word-aligned with the requested output range");
452 return OutT(in_bytes / out_elem_bytes);
453 } else {
454 return OutT{};
455 }
456 }(in_range);
457
458 using out_type = decltype(out);
459 if constexpr(unsigned_integralish<out_type>) {
460 out = load_any<endianness, out_type>(std::forward<InR>(in_range));
461 } else {
462 static_assert(ranges::contiguous_range<out_type>);
463 using out_range_type = std::ranges::range_value_t<out_type>;
464 load_any<endianness, out_range_type>(out, std::forward<InR>(in_range));
465 }
466 return out;
467}

References BOTAN_ARG_CHECK, and load_any().

◆ load_any() [7/8]

template<Endianness 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,
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 381 of file loadstor.h.

381 {
382 ranges::assert_equal_byte_lengths(out, in);
383 using element_type = std::ranges::range_value_t<OutR>;
384
385 auto load_elementwise = [&] {
386 constexpr size_t bytes_per_element = sizeof(element_type);
387 std::span<const uint8_t> in_s(in);
388 for(auto& out_elem : out) {
389 out_elem = load_any<endianness, element_type>(in_s.template first<bytes_per_element>());
390 in_s = in_s.subspan(bytes_per_element);
391 }
392 };
393
394 // At compile time we cannot use `typecast_copy` as it uses `std::memcpy`
395 // internally to copy ranges on a byte-by-byte basis, which is not allowed
396 // in a `constexpr` context.
397 if(std::is_constant_evaluated()) /* TODO: C++23: if consteval {} */ {
398 load_elementwise();
399 } else {
400 if constexpr(is_native(endianness) && !custom_loadable<element_type>) {
401 typecast_copy(out, in);
402 } else {
403 load_elementwise();
404 }
405 }
406}
constexpr void typecast_copy(ToR &&out, FromR &&in)
Definition mem_ops.h:178

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

◆ load_any() [8/8]

template<Endianness 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 509 of file loadstor.h.

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

References load_any(), and T.

◆ native_endianness_is_unknown()

template<Endianness endianness>
bool Botan::detail::native_endianness_is_unknown ( )
constexpr

Definition at line 162 of file loadstor.h.

162 {
163#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN) || defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
164 return false;
165#else
166 return true;
167#endif
168}

Referenced by load_any(), and store_any().

◆ store_any() [1/9]

template<Endianness 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 691 of file loadstor.h.

691 {
692 auto out = []([[maybe_unused]] const auto& in) {
693 if constexpr(std::same_as<AutoDetect, OutR>) {
695 constexpr size_t bytes = decltype(std::span{in})::extent * sizeof(std::ranges::range_value_t<InR>);
696 return std::array<uint8_t, bytes>();
697 } else {
698 static_assert(
699 !std::same_as<AutoDetect, OutR>,
700 "cannot infer a suitable result container type from the given parameters at compile time, please specify it explicitly");
701 }
702 } else if constexpr(concepts::resizable_byte_buffer<OutR>) {
703 return OutR(std::span{in}.size_bytes());
704 } else {
705 return OutR{};
706 }
707 }(in_range);
708
709 store_any<endianness, std::ranges::range_value_t<InR>>(out, std::forward<InR>(in_range));
710 return out;
711}

References store_any().

◆ store_any() [2/9]

template<Endianness 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,
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 631 of file loadstor.h.

631 {
632 ranges::assert_equal_byte_lengths(out, in);
633 using element_type = std::ranges::range_value_t<InR>;
634
635 auto store_elementwise = [&] {
636 constexpr size_t bytes_per_element = sizeof(element_type);
637 std::span<uint8_t> out_s(out);
638 for(auto in_elem : in) {
639 store_any<endianness, element_type>(out_s.template first<bytes_per_element>(), in_elem);
640 out_s = out_s.subspan(bytes_per_element);
641 }
642 };
643
644 // At compile time we cannot use `typecast_copy` as it uses `std::memcpy`
645 // internally to copy ranges on a byte-by-byte basis, which is not allowed
646 // in a `constexpr` context.
647 if(std::is_constant_evaluated()) /* TODO: C++23: if consteval {} */ {
648 store_elementwise();
649 } else {
650 if constexpr(is_native(endianness) && !custom_storable<element_type>) {
651 typecast_copy(out, in);
652 } else {
653 store_elementwise();
654 }
655 }
656}

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

◆ store_any() [3/9]

template<Endianness 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 610 of file loadstor.h.

610 {
611 ranges::assert_exact_byte_length<(sizeof(Ts) + ...)>(out);
612 auto store_one = [off = 0]<typename T>(auto o, T i) mutable {
613 store_any<endianness, T>(i, o.subspan(off).template first<sizeof(T)>());
614 off += sizeof(T);
615 };
616
617 (store_one(std::span{out}, ins), ...);
618}

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

◆ store_any() [4/9]

template<Endianness 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 674 of file loadstor.h.

674 {
675 store_any<endianness, T>(in, std::forward<OutR>(out_range));
676}

References store_any().

◆ store_any() [5/9]

template<Endianness 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 739 of file loadstor.h.

739 {
740 // asserts that *out points to enough bytes to write into
741 store_any<endianness, InT>(in, std::span<uint8_t, sizeof(T)>(out, sizeof(T)));
742}

References store_any(), and T.

◆ store_any() [6/9]

template<Endianness 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 724 of file loadstor.h.

724 {
725 return store_any<endianness, OutR>(std::array{ins...});
726}

References store_any().

◆ store_any() [7/9]

template<Endianness 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 751 of file loadstor.h.

751 {
752 constexpr auto bytes = sizeof(in0) + (sizeof(ins) + ... + 0);
753 // asserts that *out points to the correct amount of memory
754 store_any<endianness, T0>(std::span<uint8_t, bytes>(out, bytes), in0, ins...);
755}

References store_any().

◆ store_any() [8/9]

template<Endianness 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 551 of file loadstor.h.

551 {
552 const auto in = detail::unwrap_strong_type_or_enum(wrapped_in);
553 using InT = decltype(in);
554 ranges::assert_exact_byte_length<sizeof(in)>(out_range);
555 std::span out{out_range};
556
557 // At compile time we cannot use `typecast_copy` as it uses `std::memcpy`
558 // internally to copy ranges on a byte-by-byte basis, which is not allowed
559 // in a `constexpr` context.
560 if(std::is_constant_evaluated()) /* TODO: C++23: if consteval {} */ {
561 return fallback_store_any<endianness, InT>(in, std::forward<OutR>(out_range));
562 } else {
563 if constexpr(sizeof(InT) == 1) {
564 out[0] = static_cast<uint8_t>(in);
565 } else if constexpr(is_native(endianness)) {
566 typecast_copy(out, in);
567 } else if constexpr(is_opposite(endianness)) {
569 } else {
570 static_assert(native_endianness_is_unknown<endianness>());
571 return fallback_store_any<endianness, InT>(in, std::forward<OutR>(out_range));
572 }
573 }
574}

References Botan::ranges::assert_exact_byte_length(), fallback_store_any(), is_native(), is_opposite(), native_endianness_is_unknown(), 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().

◆ store_any() [9/9]

template<Endianness 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 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 587 of file loadstor.h.

587 {
588 const auto in = detail::unwrap_strong_type_or_enum(wrapped_in);
589 using InT = decltype(in);
590 ranges::assert_exact_byte_length<sizeof(in)>(out_range);
591 std::span<uint8_t, sizeof(InT)> outs{out_range};
592 if constexpr(endianness == Endianness::Big) {
593 in.store_be(outs);
594 } else {
595 in.store_le(outs);
596 }
597}

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

◆ unwrap_strong_type_or_enum()

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

Definition at line 214 of file loadstor.h.

214 {
215 if constexpr(std::is_enum_v<InT>) {
216 // TODO: C++23: use std::to_underlying(in) instead
217 return static_cast<std::underlying_type_t<InT>>(t);
218 } else {
220 }
221}

References Botan::unwrap_strong_type().

Referenced by 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 224 of file loadstor.h.

224 {
225 if constexpr(std::is_enum_v<OutT>) {
226 return static_cast<OutT>(t);
227 } else {
229 }
230}
constexpr decltype(auto) wrap_strong_type(ParamT &&t)
Wraps a value into a caller-defined (strong) type.

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 31 of file strong_type.h.