From a6b9ed7b4c4630024dbf082812d733ff3ba7866f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Meusel?= Date: Mon, 1 Jul 2024 17:04:27 +0200 Subject: [PATCH] use new wrap()/unwrap() in loadstor.h --- src/lib/utils/loadstor.h | 126 ++++++++++++++++++--------------------- 1 file changed, 58 insertions(+), 68 deletions(-) diff --git a/src/lib/utils/loadstor.h b/src/lib/utils/loadstor.h index 36f9dc09d67..9dcad41b70a 100644 --- a/src/lib/utils/loadstor.h +++ b/src/lib/utils/loadstor.h @@ -12,9 +12,9 @@ #include #include +#include #include #include -#include /** * @file loadstor.h @@ -169,9 +169,37 @@ constexpr bool native_endianness_is_unknown() { * Models a type that can be loaded/stored from/to a byte range. */ template -concept unsigned_integralish = std::unsigned_integral || concepts::unsigned_integral_strong_type || +concept unsigned_integralish = std::unsigned_integral> || (std::is_enum_v && std::unsigned_integral>); +template +using wrapped_type = decltype([] { + if constexpr(std::is_enum_v) { + return std::underlying_type_t{}; + } else { + return Botan::strong_type_wrapped_type{}; + } +}()); + +template +constexpr auto unwrap_strong_type_or_enum(InT t) { + if constexpr(std::is_enum_v) { + // TODO: C++23: use std::to_underlying(in) instead + return static_cast>(t); + } else { + return Botan::unwrap_strong_type(t); + } +} + +template +constexpr auto wrap_strong_type_or_enum(T t) { + if constexpr(std::is_enum_v) { + return static_cast(t); + } else { + return Botan::wrap_strong_type(t); + } +} + /** * 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 @@ -240,48 +268,31 @@ inline constexpr void fallback_store_any(InT in, OutR&& out_range) { * @param in_range a fixed-length byte range * @return T loaded from @p in_range, as a big-endian value */ -template InR> -inline constexpr OutT load_any(InR&& in_range) { +template InR> +inline constexpr WrappedOutT load_any(InR&& in_range) { + using OutT = detail::wrapped_type; ranges::assert_exact_byte_length(in_range); - std::span in{in_range}; - // At compile time we cannot use `typecast_copy` as it uses `std::memcpy` - // internally to copy ranges on a byte-by-byte basis, which is not allowed - // in a `constexpr` context. - if(std::is_constant_evaluated()) /* TODO: C++23: if consteval {} */ { - return fallback_load_any(std::forward(in_range)); - } else { - if constexpr(sizeof(OutT) == 1) { - return static_cast(in[0]); - } else if constexpr(is_native(endianness)) { - return typecast_copy(in); - } else if constexpr(is_opposite(endianness)) { - return reverse_bytes(typecast_copy(in)); - } else { - static_assert(native_endianness_is_unknown()); + return detail::wrap_strong_type_or_enum([&]() -> OutT { + // At compile time we cannot use `typecast_copy` as it uses `std::memcpy` + // internally to copy ranges on a byte-by-byte basis, which is not allowed + // in a `constexpr` context. + if(std::is_constant_evaluated()) /* TODO: C++23: if consteval {} */ { return fallback_load_any(std::forward(in_range)); + } else { + std::span in{in_range}; + if constexpr(sizeof(OutT) == 1) { + return static_cast(in[0]); + } else if constexpr(is_native(endianness)) { + return typecast_copy(in); + } else if constexpr(is_opposite(endianness)) { + return reverse_bytes(typecast_copy(in)); + } else { + static_assert(native_endianness_is_unknown()); + return fallback_load_any(std::forward(in_range)); + } } - } -} - -/** - * Overload for loading into a strong type holding an unsigned integer - */ -template InR> -inline constexpr OutT load_any(InR&& in_range) { - using underlying_type = typename OutT::wrapped_type; - return OutT{load_any(std::forward(in_range))}; -} - -/** - * Overload for loading into an enum type that uses an unsigned integer as its - * underlying type. - */ -template InR> - requires(std::is_enum_v && std::unsigned_integral>) -inline constexpr OutT load_any(InR&& in_range) { - using underlying_type = std::underlying_type_t; - return static_cast(load_any(std::forward(in_range))); + }()); } /** @@ -480,12 +491,14 @@ namespace detail { * as those of load_any(). See the documentation of this function for more * details. * - * @param in an unsigned integral to be stored - * @param out_range a byte range to store the word into + * @param wrapped_in an unsigned integral to be stored + * @param out_range a byte range to store the word into */ -template OutR> -inline constexpr void store_any(InT in, OutR&& out_range) { - ranges::assert_exact_byte_length(out_range); +template OutR> +inline constexpr void store_any(WrappedInT wrapped_in, OutR&& out_range) { + const auto in = detail::unwrap_strong_type_or_enum(wrapped_in); + using InT = decltype(in); + ranges::assert_exact_byte_length(out_range); std::span out{out_range}; // At compile time we cannot use `typecast_copy` as it uses `std::memcpy` @@ -507,29 +520,6 @@ inline constexpr void store_any(InT in, OutR&& out_range) { } } -/** - * Overload for loading into a strong type holding an unsigned integer - */ -template OutR> -inline constexpr void store_any(InT in, OutR&& out_range) { - using underlying_type = typename InT::wrapped_type; - store_any(in.get(), std::forward(out_range)); -} - -/** - * Overload for storing an enum type that uses an unsigned integer as its - * underlying type. - */ -template OutR> - requires(std::is_enum_v && std::unsigned_integral>) -inline constexpr void store_any(InT in, OutR&& out_range) { - using underlying_type = std::underlying_type_t; - // TODO: C++23: use std::to_underlying(in) instead - store_any(static_cast(in), std::forward(out_range)); -} - /** * Store many unsigned integers words into a byte range * @param out a sized range of some bytes