/** * (C) 2023 Jack Lloyd * 2023 René Meusel - Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) */ #ifndef BOTAN_RANGE_CONCEPTS_H_ #define BOTAN_RANGE_CONCEPTS_H_ #include #include #include #include #include BOTAN_FUTURE_INTERNAL_HEADER(range_concepts.h) namespace Botan::ranges { /** * Models a std::ranges::contiguous_range that (optionally) restricts its * value_type to ValueT. In other words: a stretch of contiguous memory of * a certain type (optional ValueT). */ template > concept contiguous_range = std::ranges::contiguous_range && std::same_as>; /** * Models a std::ranges::contiguous_range that satisfies * std::ranges::output_range with an arbitrary value_type. In other words: a * stretch of contiguous memory of a certain type (optional ValueT) that can be * written to. */ template > concept contiguous_output_range = contiguous_range && std::ranges::output_range; /** * Models a range that can be turned into a std::span<>. Typically, this is some * form of ranges::contiguous_range. */ template concept spanable_range = std::constructible_from>, T>; /** * Models a range that can be turned into a std::span<> with a static extent. * Typically, this is a std::array or a std::span derived from an array. */ // clang-format off template concept statically_spanable_range = spanable_range && decltype(std::span{std::declval()})::extent != std::dynamic_extent; // clang-format on /** * Find the length in bytes of a given contiguous range @p r. */ inline constexpr size_t size_bytes(const spanable_range auto& r) { return std::span{r}.size_bytes(); } /** * Throws an exception indicating that the attempted read or write was invalid */ [[noreturn]] void BOTAN_UNSTABLE_API memory_region_size_violation(); /** * Check that a given range @p r has a certain statically-known byte length. If * the range's extent is known at compile time, this is a static check, * otherwise a runtime argument check will be added. * * @throws Invalid_Argument if range @p r has a dynamic extent and does not * feature the expected byte length. */ template inline constexpr void assert_exact_byte_length(const R& r) { const std::span s{r}; if constexpr(statically_spanable_range) { static_assert(s.size_bytes() == expected, "memory region does not have expected byte lengths"); } else { if(s.size_bytes() != expected) { memory_region_size_violation(); } } } /** * Check that a list of ranges (in @p r0 and @p rs) all have the same byte * lengths. If the first range's extent is known at compile time, this will be a * static check for all other ranges whose extents are known at compile time, * otherwise a runtime argument check will be added. * * @throws Invalid_Argument if any range has a dynamic extent and not all * ranges feature the same byte length. */ template inline constexpr void assert_equal_byte_lengths(const R0& r0, const Rs&... rs) requires(sizeof...(Rs) > 0) { const std::span s0{r0}; if constexpr(statically_spanable_range) { constexpr size_t expected_size = s0.size_bytes(); (assert_exact_byte_length(rs), ...); } else { const size_t expected_size = s0.size_bytes(); const bool correct_size = ((std::span>{rs}.size_bytes() == expected_size) && ...); if(!correct_size) { memory_region_size_violation(); } } } } // namespace Botan::ranges #endif