10#ifndef BOTAN_STL_UTIL_H_
11#define BOTAN_STL_UTIL_H_
22#include <botan/concepts.h>
23#include <botan/secmem.h>
24#include <botan/strong_type.h>
28template <concepts::contiguous_container T = std::vector<u
int8_t>>
30 return T(s.cbegin(), s.cend());
33inline std::string
to_string(std::span<const uint8_t> bytes) {
34 return std::string(bytes.begin(), bytes.end());
46template <
typename RetT,
typename KeyT,
typename ReducerT>
47RetT
reduce(
const std::vector<KeyT>& keys, RetT acc, ReducerT reducer)
48 requires std::is_convertible_v<ReducerT, std::function<RetT(RetT,
const KeyT&)>>
50 for(
const KeyT& key : keys) {
51 acc = reducer(std::move(acc), key);
59template <
typename T,
typename OT>
61 for(
size_t i = 0; i != vec.size(); ++i) {
69template <
typename T,
typename Pred>
71 auto i = assoc.begin();
72 while(i != assoc.end()) {
86 BufferSlicer(std::span<const uint8_t> buffer) : m_remaining(buffer) {}
88 template <concepts::contiguous_container ContainerT>
89 auto copy(
const size_t count) {
90 const auto result =
take(count);
91 return ContainerT(result.begin(), result.end());
98 std::span<const uint8_t>
take(
const size_t count) {
100 auto result = m_remaining.first(count);
101 m_remaining = m_remaining.subspan(count);
105 template <
size_t count>
106 std::span<const uint8_t, count>
take() {
108 auto result = m_remaining.first<count>();
109 m_remaining = m_remaining.subspan(count);
113 template <concepts::contiguous_strong_type T>
121 const auto data =
take(sink.size());
122 std::copy(data.begin(), data.end(), sink.begin());
129 bool empty()
const {
return m_remaining.empty(); }
132 std::span<const uint8_t> m_remaining;
150 constexpr std::span<uint8_t>
next(
size_t bytes) {
153 auto result = m_buffer.first(bytes);
154 m_buffer = m_buffer.subspan(bytes);
158 template <
size_t bytes>
159 constexpr std::span<uint8_t, bytes>
next() {
162 auto result = m_buffer.first<bytes>();
163 m_buffer = m_buffer.subspan(bytes);
167 template <concepts::contiguous_strong_type StrongT>
177 constexpr void append(std::span<const uint8_t> buffer) {
178 auto sink =
next(buffer.size());
179 std::copy(buffer.begin(), buffer.end(), sink.begin());
182 constexpr void append(uint8_t
b,
size_t repeat = 1) {
183 auto sink =
next(repeat);
184 std::fill(sink.begin(), sink.end(),
b);
187 constexpr bool full()
const {
return m_buffer.empty(); }
192 std::span<uint8_t> m_buffer;
203template <ranges::spanable_range OutR, ranges::spanable_range... Rs>
212 [[maybe_unused]]
auto fill_fn = [&] {
215 const size_t total_size = (ranges.size() + ... + 0);
216 result.reserve(total_size);
219 return [&result](
auto&& range) {
221 std::ranges::begin(range), std::ranges::end(range), std::back_inserter(
unwrap_strong_type(result)));
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");
231 const size_t total_size = (ranges.size() + ... + 0);
233 "result buffer has static extent that does not match the sum of input buffers");
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));
245 (fill_fn(std::forward<Rs>(ranges)), ...);
262template <
typename OutR = detail::AutoDetect, ranges::spanable_range... Rs>
264 requires(all_same_v<std::ranges::range_value_t<Rs>...>)
266 if constexpr(std::same_as<detail::AutoDetect, OutR>) {
268 static_assert(
sizeof...(Rs) > 0,
"Cannot auto-detect the output type if not a single input range is provided.");
269 using candidate_result_t = std::remove_cvref_t<std::tuple_element_t<0, std::tuple<Rs...>>>;
270 using result_range_value_t = std::remove_cvref_t<std::ranges::range_value_t<candidate_result_t>>;
275 constexpr size_t total_size = (
decltype(std::span{ranges})::extent + ... + 0);
276 using out_array_t = std::array<result_range_value_t, total_size>;
283 "First input range has static extent, but a dynamically allocated output range is required. Please explicitly specify a dynamically allocatable output type.");
292template <
typename... Alts,
typename... Ts>
294 return (std::holds_alternative<Alts>(v) || ...);
297template <
typename GeneralVariantT,
typename SpecialT>
299 return std::is_constructible_v<GeneralVariantT, SpecialT>;
302template <
typename GeneralVariantT,
typename... SpecialTs>
304 return (std::is_constructible_v<GeneralVariantT, SpecialTs> && ...);
314template <
typename GeneralVariantT,
typename SpecialT>
316 requires(std::is_constructible_v<GeneralVariantT, std::decay_t<SpecialT>>)
318 return std::forward<SpecialT>(specific);
328template <
typename GeneralVariantT,
typename... SpecialTs>
329constexpr GeneralVariantT
generalize_to(std::variant<SpecialTs...> specific)
noexcept {
332 "Desired general type must be implicitly constructible by all types of the specialized std::variant<>");
333 return std::visit([](
auto s) -> GeneralVariantT {
return s; }, std::move(specific));
338template <
class... Ts>
340 using Ts::operator()...;
343template <
class... Ts>
353template <std::invocable FunT>
365 m_cleanup = std::move(other.m_cleanup);
372 if(m_cleanup.has_value()) {
383 std::optional<FunT> m_cleanup;
390T assert_is_some(std::optional<T> v,
const char* expr,
const char* func,
const char* file,
int line) {
398#define BOTAN_ASSERT_IS_SOME(v) assert_is_some(v, #v, __func__, __FILE__, __LINE__)
413 requires std::is_enum_v<T>
415 return static_cast<std::underlying_type_t<T>
>(e);
420[[nodiscard]]
constexpr auto out_ptr(
T& outptr)
noexcept {
423 constexpr ~out_ptr_t()
noexcept {
424 m_ptr.reset(m_rawptr);
428 constexpr out_ptr_t(
T& outptr) noexcept : m_ptr(outptr), m_rawptr(
nullptr) {}
430 out_ptr_t(
const out_ptr_t&) =
delete;
431 out_ptr_t(out_ptr_t&&) =
delete;
432 out_ptr_t& operator=(
const out_ptr_t&) =
delete;
433 out_ptr_t& operator=(out_ptr_t&&) =
delete;
435 [[nodiscard]]
constexpr operator typename T::element_type **() &&
noexcept {
return &m_rawptr; }
439 typename T::element_type* m_rawptr;
442 return out_ptr_t{outptr};
446 requires std::is_default_constructible_v<T>
447[[nodiscard]]
constexpr auto out_opt(std::optional<T>& outopt)
noexcept {
450 constexpr ~out_opt_t()
noexcept { m_opt = m_raw; }
452 constexpr out_opt_t(std::optional<T>& outopt) noexcept : m_opt(outopt) {}
454 out_opt_t(
const out_opt_t&) =
delete;
455 out_opt_t(out_opt_t&&) =
delete;
456 out_opt_t& operator=(
const out_opt_t&) =
delete;
457 out_opt_t& operator=(out_opt_t&&) =
delete;
459 [[nodiscard]]
constexpr operator T*() &&
noexcept {
return &m_raw; }
462 std::optional<T>& m_opt;
466 return out_opt_t{outopt};
#define BOTAN_STATE_CHECK(expr)
#define BOTAN_ARG_CHECK(expr, msg)
void skip(const size_t count)
auto copy_as_secure_vector(const size_t count)
void copy_into(std::span< uint8_t > sink)
BufferSlicer(std::span< const uint8_t > buffer)
std::span< const uint8_t, count > take()
auto copy(const size_t count)
std::span< const uint8_t > take(const size_t count)
StrongSpan< const T > take(const size_t count)
auto copy_as_vector(const size_t count)
Helper class to ease in-place marshalling of concatenated fixed-length values.
constexpr void append(std::span< const uint8_t > buffer)
constexpr void append(uint8_t b, size_t repeat=1)
constexpr size_t remaining_capacity() const
StrongSpan< StrongT > next(size_t bytes)
constexpr std::span< uint8_t > next(size_t bytes)
constexpr std::span< uint8_t, bytes > next()
constexpr uint8_t & next_byte()
constexpr BufferStuffer(std::span< uint8_t > buffer)
constexpr bool full() const
constexpr StringLiteral(const char(&str)[N])
Helper class to create a RAII-style cleanup callback.
scoped_cleanup(const scoped_cleanup &)=delete
scoped_cleanup & operator=(const scoped_cleanup &)=delete
scoped_cleanup(FunT cleanup)
scoped_cleanup & operator=(scoped_cleanup &&other)
scoped_cleanup(scoped_cleanup &&other)
int(* final)(unsigned char *, CTX *)
constexpr OutR concatenate(Rs &&... ranges)
constexpr GeneralVariantT generalize_to(SpecialT &&specific) noexcept
Converts a given variant into another variant-ish whose type states are a super set of the given vari...
void map_remove_if(Pred pred, T &assoc)
T to_byte_vector(std::string_view s)
constexpr auto out_ptr(T &outptr) noexcept
constexpr bool holds_any_of(const std::variant< Ts... > &v) noexcept
RetT reduce(const std::vector< KeyT > &keys, RetT acc, ReducerT reducer)
constexpr decltype(auto) unwrap_strong_type(T &&t)
Generically unwraps a strong type to its underlying type.
constexpr auto out_opt(std::optional< T > &outopt) noexcept
T assert_is_some(std::optional< T > v, const char *expr, const char *func, const char *file, int line)
constexpr auto concat(Rs &&... ranges)
bool value_exists(const std::vector< T > &vec, const OT &val)
constexpr bool is_generalizable_to(const SpecialT &) noexcept
std::string to_string(ErrorType type)
Convert an ErrorType to string.
auto to_underlying(T e) noexcept
void assertion_failure(const char *expr_str, const char *assertion_made, const char *func, const char *file, int line)
overloaded(Ts...) -> overloaded< Ts... >