Botan 3.9.0
Crypto and TLS for C&
strong_type.h
Go to the documentation of this file.
1/**
2 * A wrapper class to implement strong types
3 * (C) 2022 Jack Lloyd
4 * 2022 René Meusel - Rohde & Schwarz Cybersecurity
5 *
6 * Botan is released under the Simplified BSD License (see license.txt)
7 */
8
9#ifndef BOTAN_STRONG_TYPE_H_
10#define BOTAN_STRONG_TYPE_H_
11
12#include <botan/concepts.h>
13
14#include <iosfwd>
15#include <span>
16#include <string>
17
18namespace Botan {
19
20/**
21 * Added as an additional "capability tag" to enable arithmetic operators with
22 * plain numbers for Strong<> types that wrap a number.
23 */
25
26namespace detail {
27
28/**
29 * Checks whether the @p CapabilityT is included in the @p Tags type pack.
30 */
31template <typename CapabilityT, typename... Tags>
32constexpr bool has_capability = (std::is_same_v<CapabilityT, Tags> || ...);
33
34template <typename T>
36 private:
37 T m_value;
38
39 public:
40 using wrapped_type = T;
41
42 public:
43 Strong_Base() = default;
44 Strong_Base(const Strong_Base&) = default;
45 Strong_Base(Strong_Base&&) noexcept = default;
46 Strong_Base& operator=(const Strong_Base&) = default;
47 Strong_Base& operator=(Strong_Base&&) noexcept = default;
48 ~Strong_Base() = default;
49
50 constexpr explicit Strong_Base(T v) : m_value(std::move(v)) {}
51
52 constexpr T& get() & { return m_value; }
53
54 constexpr const T& get() const& { return m_value; }
55
56 constexpr T&& get() && { return std::move(m_value); }
57
58 constexpr const T&& get() const&& { return std::move(m_value); }
59};
60
61template <typename T>
62class Strong_Adapter : public Strong_Base<T> {
63 public:
65};
66
67template <std::integral T>
68class Strong_Adapter<T> : public Strong_Base<T> {
69 public:
71};
72
73template <concepts::container T>
75 public:
76 using value_type = typename T::value_type;
77 using size_type = typename T::size_type;
78 using iterator = typename T::iterator;
79 using const_iterator = typename T::const_iterator;
80
81 public:
83
87
88 template <typename InputIt>
90
91 public:
92 decltype(auto) begin() noexcept(noexcept(this->get().begin())) { return this->get().begin(); }
93
94 decltype(auto) begin() const noexcept(noexcept(this->get().begin())) { return this->get().begin(); }
95
96 decltype(auto) end() noexcept(noexcept(this->get().end())) { return this->get().end(); }
97
98 decltype(auto) end() const noexcept(noexcept(this->get().end())) { return this->get().end(); }
99
100 decltype(auto) cbegin() noexcept(noexcept(this->get().cbegin())) { return this->get().cbegin(); }
101
102 decltype(auto) cbegin() const noexcept(noexcept(this->get().cbegin())) { return this->get().cbegin(); }
103
104 decltype(auto) cend() noexcept(noexcept(this->get().cend())) { return this->get().cend(); }
105
106 decltype(auto) cend() const noexcept(noexcept(this->get().cend())) { return this->get().cend(); }
107
108 size_type size() const noexcept(noexcept(this->get().size())) { return this->get().size(); }
109
110 bool empty() const noexcept(noexcept(this->get().empty()))
111 requires(concepts::has_empty<T>)
112 {
113 return this->get().empty();
114 }
115
116 void resize(size_type size) noexcept(noexcept(this->get().resize(size)))
118 {
119 this->get().resize(size);
120 }
121
122 void reserve(size_type size) noexcept(noexcept(this->get().reserve(size)))
124 {
125 this->get().reserve(size);
126 }
127
128 template <typename U>
129 decltype(auto) operator[](U&& i) const noexcept(noexcept(this->get().operator[](i))) {
130 return this->get()[std::forward<U>(i)];
131 }
132
133 template <typename U>
134 decltype(auto) operator[](U&& i) noexcept(noexcept(this->get().operator[](i))) {
135 return this->get()[std::forward<U>(i)];
136 }
137
138 template <typename U>
139 decltype(auto) at(U&& i) const noexcept(noexcept(this->get().at(i)))
141 {
142 return this->get().at(std::forward<U>(i));
143 }
144
145 template <typename U>
146 decltype(auto) at(U&& i) noexcept(noexcept(this->get().at(i)))
148 {
149 return this->get().at(std::forward<U>(i));
150 }
151};
152
153template <concepts::container T>
154class Strong_Adapter<T> : public Container_Strong_Adapter_Base<T> {
155 public:
156 using Container_Strong_Adapter_Base<T>::Container_Strong_Adapter_Base;
157};
158
159template <concepts::contiguous_container T>
160class Strong_Adapter<T> : public Container_Strong_Adapter_Base<T> {
161 public:
162 using pointer = typename T::pointer;
163 using const_pointer = typename T::const_pointer;
164
165 public:
167
168 explicit Strong_Adapter(std::span<const typename Container_Strong_Adapter_Base<T>::value_type> span) :
169 Strong_Adapter(T(span.begin(), span.end())) {}
170
171 // Disambiguates the usage of string literals, otherwise:
172 // Strong_Adapter(std::span<>) and Strong_Adapter(const char*)
173 // would be ambiguous.
174 explicit Strong_Adapter(const char* str)
175 requires(std::same_as<T, std::string>)
176 : Strong_Adapter(std::string(str)) {}
177
178 public:
179 decltype(auto) data() noexcept(noexcept(this->get().data())) { return this->get().data(); }
180
181 decltype(auto) data() const noexcept(noexcept(this->get().data())) { return this->get().data(); }
182};
183
184} // namespace detail
185
186/**
187 * Strong types can be used as wrappers around common types to provide
188 * compile time semantics. They usually contribute to more maintainable and
189 * less error-prone code especially when dealing with function parameters.
190 *
191 * Internally, this provides adapters so that the wrapping strong type behaves
192 * as much as the underlying type as possible and desirable.
193 *
194 * This implementation was inspired by:
195 * https://stackoverflow.com/a/69030899
196 */
197template <typename T, typename TagTypeT, typename... Capabilities>
199 public:
201
202 template <typename CapabilityT>
203 constexpr static bool has_capability() {
204 return (std::is_same_v<CapabilityT, Capabilities> || ...);
205 }
206
207 private:
208 using Tag = TagTypeT;
209};
210
211/**
212 * @brief Generically unwraps a strong type to its underlying type.
213 *
214 * If the provided type is not a strong type, it is returned as is.
215 *
216 * @note This is meant as a helper for generic code that needs to deal with both
217 * wrapped strong types and bare objects. Use the ordinary `get()` method
218 * if you know that you are dealing with a strong type.
219 *
220 * @param t value to be unwrapped
221 * @return the unwrapped value
222 */
223template <typename T>
224[[nodiscard]] constexpr decltype(auto) unwrap_strong_type(T&& t) {
226 // If the parameter type isn't a strong type, return it as is.
227 return std::forward<T>(t);
228 } else {
229 // Unwrap the strong type and return the underlying value.
230 return std::forward<T>(t).get();
231 }
232}
233
234/**
235 * @brief Wraps a value into a caller-defined (strong) type.
236 *
237 * If the provided object @p t is already of type @p T, it is returned as is.
238 *
239 * @note This is meant as a helper for generic code that needs to deal with both
240 * wrapped strong types and bare objects. Use the ordinary constructor if
241 * you know that you are dealing with a bare value type.
242 *
243 * @param t value to be wrapped
244 * @return the wrapped value
245 */
246template <typename T, typename ParamT>
247 requires std::constructible_from<T, ParamT> ||
248 (concepts::strong_type<T> && std::constructible_from<typename T::wrapped_type, ParamT>)
249[[nodiscard]] constexpr decltype(auto) wrap_strong_type(ParamT&& t) {
250 if constexpr(std::same_as<std::remove_cvref_t<ParamT>, T>) {
251 // Noop, if the parameter type already is the desired return type.
252 return std::forward<ParamT>(t);
253 } else if constexpr(std::constructible_from<T, ParamT>) {
254 // Implicit conversion from the parameter type to the return type.
255 return T{std::forward<ParamT>(t)};
256 } else {
257 // Explicitly calling the wrapped type's constructor to support
258 // implicit conversions on types that mark their constructors as explicit.
259 static_assert(concepts::strong_type<T> && std::constructible_from<typename T::wrapped_type, ParamT>);
260 return T{typename T::wrapped_type{std::forward<ParamT>(t)}};
261 }
262}
263
264namespace detail {
265
266template <typename T>
268 using type = T;
269};
270
271template <concepts::strong_type T>
273 using type = typename T::wrapped_type;
274};
275
276} // namespace detail
277
278/**
279 * @brief Extracts the wrapped type from a strong type.
280 *
281 * If the provided type is not a strong type, it is returned as is.
282 *
283 * @note This is meant as a helper for generic code that needs to deal with both
284 * wrapped strong types and bare objects. Use the ordinary `::wrapped_type`
285 * declaration if you know that you are dealing with a strong type.
286 */
287template <typename T>
289
290template <typename T, typename... Tags>
292decltype(auto) operator<<(std::ostream& os, const Strong<T, Tags...>& v) {
293 return os << v.get();
294}
295
296template <typename T, typename... Tags>
297 requires(std::equality_comparable<T>)
298bool operator==(const Strong<T, Tags...>& lhs, const Strong<T, Tags...>& rhs) {
299 return lhs.get() == rhs.get();
300}
301
302template <typename T, typename... Tags>
303 requires(std::three_way_comparable<T>)
305 return lhs.get() <=> rhs.get();
306}
307
308template <std::integral T1, std::integral T2, typename... Tags>
310 return a <=> b.get();
311}
312
313template <std::integral T1, std::integral T2, typename... Tags>
315 return a.get() <=> b;
316}
317
318template <std::integral T1, std::integral T2, typename... Tags>
320 return a == b.get();
321}
322
323template <std::integral T1, std::integral T2, typename... Tags>
325 return a.get() == b;
326}
327
328template <std::integral T1, std::integral T2, typename... Tags>
329 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
330constexpr decltype(auto) operator+(T1 a, Strong<T2, Tags...> b) {
331 return Strong<T2, Tags...>(a + b.get());
332}
333
334template <std::integral T1, std::integral T2, typename... Tags>
335 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
336constexpr decltype(auto) operator+(Strong<T1, Tags...> a, T2 b) {
337 return Strong<T1, Tags...>(a.get() + b);
338}
339
340template <std::integral T, typename... Tags>
341constexpr decltype(auto) operator+(Strong<T, Tags...> a, Strong<T, Tags...> b) {
342 return Strong<T, Tags...>(a.get() + b.get());
343}
344
345template <std::integral T1, std::integral T2, typename... Tags>
346 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
347constexpr decltype(auto) operator-(T1 a, Strong<T2, Tags...> b) {
348 return Strong<T2, Tags...>(a - b.get());
349}
350
351template <std::integral T1, std::integral T2, typename... Tags>
352 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
353constexpr decltype(auto) operator-(Strong<T1, Tags...> a, T2 b) {
354 return Strong<T1, Tags...>(a.get() - b);
355}
356
357template <std::integral T, typename... Tags>
358constexpr decltype(auto) operator-(Strong<T, Tags...> a, Strong<T, Tags...> b) {
359 return Strong<T, Tags...>(a.get() - b.get());
360}
361
362template <std::integral T1, std::integral T2, typename... Tags>
363 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
364constexpr decltype(auto) operator*(T1 a, Strong<T2, Tags...> b) {
365 return Strong<T2, Tags...>(a * b.get());
366}
367
368template <std::integral T1, std::integral T2, typename... Tags>
369 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
370constexpr decltype(auto) operator*(Strong<T1, Tags...> a, T2 b) {
371 return Strong<T1, Tags...>(a.get() * b);
372}
373
374template <std::integral T, typename... Tags>
375constexpr decltype(auto) operator*(Strong<T, Tags...> a, Strong<T, Tags...> b) {
376 return Strong<T, Tags...>(a.get() * b.get());
377}
378
379template <std::integral T1, std::integral T2, typename... Tags>
380 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
381constexpr decltype(auto) operator/(T1 a, Strong<T2, Tags...> b) {
382 return Strong<T2, Tags...>(a / b.get());
383}
384
385template <std::integral T1, std::integral T2, typename... Tags>
386 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
387constexpr decltype(auto) operator/(Strong<T1, Tags...> a, T2 b) {
388 return Strong<T1, Tags...>(a.get() / b);
389}
390
391template <std::integral T, typename... Tags>
392constexpr decltype(auto) operator/(Strong<T, Tags...> a, Strong<T, Tags...> b) {
393 return Strong<T, Tags...>(a.get() / b.get());
394}
395
396template <std::integral T1, std::integral T2, typename... Tags>
397 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
398constexpr decltype(auto) operator^(T1 a, Strong<T2, Tags...> b) {
399 return Strong<T2, Tags...>(a ^ b.get());
400}
401
402template <std::integral T1, std::integral T2, typename... Tags>
403 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
404constexpr decltype(auto) operator^(Strong<T1, Tags...> a, T2 b) {
405 return Strong<T1, Tags...>(a.get() ^ b);
406}
407
408template <std::integral T, typename... Tags>
409constexpr decltype(auto) operator^(Strong<T, Tags...> a, Strong<T, Tags...> b) {
410 return Strong<T, Tags...>(a.get() ^ b.get());
411}
412
413template <std::integral T1, std::integral T2, typename... Tags>
414 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
415constexpr decltype(auto) operator&(T1 a, Strong<T2, Tags...> b) {
416 return Strong<T2, Tags...>(a & b.get());
417}
418
419template <std::integral T1, std::integral T2, typename... Tags>
420 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
421constexpr decltype(auto) operator&(Strong<T1, Tags...> a, T2 b) {
422 return Strong<T1, Tags...>(a.get() & b);
423}
424
425template <std::integral T, typename... Tags>
426constexpr decltype(auto) operator&(Strong<T, Tags...> a, Strong<T, Tags...> b) {
427 return Strong<T, Tags...>(a.get() & b.get());
428}
429
430template <std::integral T1, std::integral T2, typename... Tags>
431 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
432constexpr decltype(auto) operator|(T1 a, Strong<T2, Tags...> b) {
433 return Strong<T2, Tags...>(a | b.get());
434}
435
436template <std::integral T1, std::integral T2, typename... Tags>
437 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
438constexpr decltype(auto) operator|(Strong<T1, Tags...> a, T2 b) {
439 return Strong<T1, Tags...>(a.get() | b);
440}
441
442template <std::integral T, typename... Tags>
443constexpr decltype(auto) operator|(Strong<T, Tags...> a, Strong<T, Tags...> b) {
444 return Strong<T, Tags...>(a.get() | b.get());
445}
446
447template <std::integral T1, std::integral T2, typename... Tags>
448 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
449constexpr decltype(auto) operator>>(T1 a, Strong<T2, Tags...> b) {
450 return Strong<T2, Tags...>(a >> b.get());
451}
452
453template <std::integral T1, std::integral T2, typename... Tags>
454 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
455constexpr decltype(auto) operator>>(Strong<T1, Tags...> a, T2 b) {
456 return Strong<T1, Tags...>(a.get() >> b);
457}
458
459template <std::integral T, typename... Tags>
460constexpr decltype(auto) operator>>(Strong<T, Tags...> a, Strong<T, Tags...> b) {
461 return Strong<T, Tags...>(a.get() >> b.get());
462}
463
464template <std::integral T1, std::integral T2, typename... Tags>
465 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
466constexpr decltype(auto) operator<<(T1 a, Strong<T2, Tags...> b) {
467 return Strong<T2, Tags...>(a << b.get());
468}
469
470template <std::integral T1, std::integral T2, typename... Tags>
471 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
472constexpr decltype(auto) operator<<(Strong<T1, Tags...> a, T2 b) {
473 return Strong<T1, Tags...>(a.get() << b);
474}
475
476template <std::integral T, typename... Tags>
477constexpr decltype(auto) operator<<(Strong<T, Tags...> a, Strong<T, Tags...> b) {
478 return Strong<T, Tags...>(a.get() << b.get());
479}
480
481template <std::integral T1, std::integral T2, typename... Tags>
482 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
483constexpr auto operator+=(Strong<T1, Tags...>& a, T2 b) {
484 a.get() += b;
485 return a;
486}
487
488template <std::integral T, typename... Tags>
490 a.get() += b.get();
491 return a;
492}
493
494template <std::integral T1, std::integral T2, typename... Tags>
495 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
496constexpr auto operator-=(Strong<T1, Tags...>& a, T2 b) {
497 a.get() -= b;
498 return a;
499}
500
501template <std::integral T, typename... Tags>
503 a.get() -= b.get();
504 return a;
505}
506
507template <std::integral T1, std::integral T2, typename... Tags>
508 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
509constexpr auto operator*=(Strong<T1, Tags...>& a, T2 b) {
510 a.get() *= b;
511 return a;
512}
513
514template <std::integral T, typename... Tags>
516 a.get() *= b.get();
517 return a;
518}
519
520template <std::integral T1, std::integral T2, typename... Tags>
521 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
522constexpr auto operator/=(Strong<T1, Tags...>& a, T2 b) {
523 a.get() /= b;
524 return a;
525}
526
527template <std::integral T, typename... Tags>
529 a.get() /= b.get();
530 return a;
531}
532
533template <std::integral T1, std::integral T2, typename... Tags>
534 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
535constexpr auto operator^=(Strong<T1, Tags...>& a, T2 b) {
536 a.get() ^= b;
537 return a;
538}
539
540template <std::integral T, typename... Tags>
542 a.get() ^= b.get();
543 return a;
544}
545
546template <std::integral T1, std::integral T2, typename... Tags>
547 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
548constexpr auto operator&=(Strong<T1, Tags...>& a, T2 b) {
549 a.get() &= b;
550 return a;
551}
552
553template <std::integral T, typename... Tags>
555 a.get() &= b.get();
556 return a;
557}
558
559template <std::integral T1, std::integral T2, typename... Tags>
560 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
561constexpr auto operator|=(Strong<T1, Tags...>& a, T2 b) {
562 a.get() |= b;
563 return a;
564}
565
566template <std::integral T, typename... Tags>
568 a.get() |= b.get();
569 return a;
570}
571
572template <std::integral T1, std::integral T2, typename... Tags>
573 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
574constexpr auto operator>>=(Strong<T1, Tags...>& a, T2 b) {
575 a.get() >>= b;
576 return a;
577}
578
579template <std::integral T, typename... Tags>
581 a.get() >>= b.get();
582 return a;
583}
584
585template <std::integral T1, std::integral T2, typename... Tags>
586 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
587constexpr auto operator<<=(Strong<T1, Tags...>& a, T2 b) {
588 a.get() <<= b;
589 return a;
590}
591
592template <std::integral T, typename... Tags>
594 a.get() <<= b.get();
595 return a;
596}
597
598template <std::integral T, typename... Tags>
599constexpr auto operator++(Strong<T, Tags...>& a, int) {
600 auto tmp = a;
601 ++a.get();
602 return tmp;
603}
604
605template <std::integral T, typename... Tags>
606constexpr auto operator++(Strong<T, Tags...>& a) {
607 ++a.get();
608 return a;
609}
610
611template <std::integral T, typename... Tags>
612constexpr auto operator--(Strong<T, Tags...>& a, int) {
613 auto tmp = a;
614 --a.get();
615 return tmp;
616}
617
618template <std::integral T, typename... Tags>
619constexpr auto operator--(Strong<T, Tags...>& a) {
620 --a.get();
621 return a;
622}
623
624/**
625 * This mimmicks a std::span but keeps track of the strong-type information. Use
626 * this when you would want to use `const Strong<...>&` as a parameter
627 * declaration. In particular this allows assigning strong-type information to
628 * slices of a bigger buffer without copying the bytes. E.g:
629 *
630 * using Foo = Strong<std::vector<uint8_t>, Foo_>;
631 *
632 * void bar(StrongSpan<Foo> foo) { ... }
633 *
634 * std::vector<uint8_t> buffer;
635 * BufferSlicer slicer(buffer);
636 * bar(slicer.take<Foo>()); // This does not copy the data from buffer but
637 * // just annotates the 'Foo' strong-type info.
638 */
639template <concepts::contiguous_strong_type T>
641 using underlying_span = std::
642 conditional_t<std::is_const_v<T>, std::span<const typename T::value_type>, std::span<typename T::value_type>>;
643
644 public:
645 using value_type = typename underlying_span::value_type;
646 using size_type = typename underlying_span::size_type;
647 using iterator = typename underlying_span::iterator;
648 using pointer = typename underlying_span::pointer;
649 using const_pointer = typename underlying_span::const_pointer;
650
651 StrongSpan() = default;
652
653 explicit StrongSpan(underlying_span span) : m_span(span) {}
654
655 // NOLINTNEXTLINE(*-explicit-conversions)
656 StrongSpan(T& strong) : m_span(strong) {}
657
658 // Allows implicit conversion from `StrongSpan<T>` to `StrongSpan<const T>`.
659 // Note that this is not bi-directional. Conversion from `StrongSpan<const T>`
660 // to `StrongSpan<T>` is not allowed.
661 //
662 // TODO: Technically, we should be able to phrase this with a `requires std::is_const_v<T>`
663 // instead of the `std::enable_if` constructions. clang-tidy (14 or 15) doesn't seem
664 // to pick up on that (yet?). As a result, for a non-const T it assumes this to be
665 // a declaration of an ordinary copy constructor. The existance of a copy constructor
666 // is interpreted as "not cheap to copy", setting off the `performance-unnecessary-value-param` check.
667 // See also: https://github.com/randombit/botan/issues/3591
668 template <concepts::contiguous_strong_type T2>
669 // NOLINTNEXTLINE(*-explicit-conversions)
671 requires(std::is_same_v<T2, std::remove_const_t<T>>)
672 : m_span(other.get()) {}
673
674 StrongSpan(const StrongSpan& other) = default;
675 StrongSpan(StrongSpan&& other) = default;
676 StrongSpan& operator=(const StrongSpan& other) = default;
677 StrongSpan& operator=(StrongSpan&& other) = default;
678
679 ~StrongSpan() = default;
680
681 /**
682 * @returns the underlying std::span without any type constraints
683 */
684 underlying_span get() const { return m_span; }
685
686 /**
687 * @returns the underlying std::span without any type constraints
688 */
689 underlying_span get() { return m_span; }
690
691 decltype(auto) data() noexcept(noexcept(this->m_span.data())) { return this->m_span.data(); }
692
693 decltype(auto) data() const noexcept(noexcept(this->m_span.data())) { return this->m_span.data(); }
694
695 decltype(auto) size() const noexcept(noexcept(this->m_span.size())) { return this->m_span.size(); }
696
697 bool empty() const noexcept(noexcept(this->m_span.empty())) { return this->m_span.empty(); }
698
699 decltype(auto) begin() noexcept(noexcept(this->m_span.begin())) { return this->m_span.begin(); }
700
701 decltype(auto) begin() const noexcept(noexcept(this->m_span.begin())) { return this->m_span.begin(); }
702
703 decltype(auto) end() noexcept(noexcept(this->m_span.end())) { return this->m_span.end(); }
704
705 decltype(auto) end() const noexcept(noexcept(this->m_span.end())) { return this->m_span.end(); }
706
707 decltype(auto) operator[](typename underlying_span::size_type i) const noexcept { return this->m_span[i]; }
708
709 private:
710 underlying_span m_span;
711};
712
713template <typename>
714struct is_strong_span : std::false_type {};
715
716template <typename T>
717struct is_strong_span<StrongSpan<T>> : std::true_type {};
718
719template <typename T>
721
722} // namespace Botan
723
724#endif
typename underlying_span::size_type size_type
decltype(auto) begin() noexcept(noexcept(this->m_span.begin()))
StrongSpan()=default
decltype(auto) data() noexcept(noexcept(this->m_span.data()))
underlying_span get() const
StrongSpan(T &strong)
typename underlying_span::value_type value_type
~StrongSpan()=default
decltype(auto) begin() const noexcept(noexcept(this->m_span.begin()))
StrongSpan(const StrongSpan &other)=default
StrongSpan(const StrongSpan< T2 > &other)
decltype(auto) end() noexcept(noexcept(this->m_span.end()))
StrongSpan & operator=(StrongSpan &&other)=default
StrongSpan(underlying_span span)
typename underlying_span::const_pointer const_pointer
bool empty() const noexcept(noexcept(this->m_span.empty()))
underlying_span get()
decltype(auto) operator[](typename underlying_span::size_type i) const noexcept
typename underlying_span::pointer pointer
decltype(auto) data() const noexcept(noexcept(this->m_span.data()))
decltype(auto) end() const noexcept(noexcept(this->m_span.end()))
StrongSpan & operator=(const StrongSpan &other)=default
typename underlying_span::iterator iterator
StrongSpan(StrongSpan &&other)=default
decltype(auto) size() const noexcept(noexcept(this->m_span.size()))
static constexpr bool has_capability()
decltype(auto) cbegin() const noexcept(noexcept(this->get().cbegin()))
decltype(auto) begin() noexcept(noexcept(this->get().begin()))
Definition strong_type.h:92
Container_Strong_Adapter_Base(InputIt begin, InputIt end)
Definition strong_type.h:89
decltype(auto) cend() noexcept(noexcept(this->get().cend()))
decltype(auto) cend() const noexcept(noexcept(this->get().cend()))
decltype(auto) end() const noexcept(noexcept(this->get().end()))
Definition strong_type.h:98
void reserve(size_type size) noexcept(noexcept(this->get().reserve(size)))
size_type size() const noexcept(noexcept(this->get().size()))
decltype(auto) at(U &&i) noexcept(noexcept(this->get().at(i)))
decltype(auto) end() noexcept(noexcept(this->get().end()))
Definition strong_type.h:96
bool empty() const noexcept(noexcept(this->get().empty()))
decltype(auto) begin() const noexcept(noexcept(this->get().begin()))
Definition strong_type.h:94
void resize(size_type size) noexcept(noexcept(this->get().resize(size)))
typename T::const_iterator const_iterator
Definition strong_type.h:79
decltype(auto) at(U &&i) const noexcept(noexcept(this->get().at(i)))
decltype(auto) cbegin() noexcept(noexcept(this->get().cbegin()))
decltype(auto) data() const noexcept(noexcept(this->get().data()))
decltype(auto) data() noexcept(noexcept(this->get().data()))
typename T::const_pointer const_pointer
Strong_Adapter(std::span< const typename Container_Strong_Adapter_Base< T >::value_type > span)
constexpr const T & get() const &
Definition strong_type.h:54
Strong_Base(Strong_Base &&) noexcept=default
constexpr T & get() &
Definition strong_type.h:52
constexpr const T && get() const &&
Definition strong_type.h:58
constexpr T && get() &&
Definition strong_type.h:56
Strong_Base(const Strong_Base &)=default
constexpr bool has_capability
Definition strong_type.h:32
ASN1_Type operator|(ASN1_Type x, ASN1_Type y)
Definition asn1_obj.h:74
BigInt operator*(const BigInt &x, const BigInt &y)
Definition big_ops3.cpp:56
constexpr auto operator>>=(Strong< T1, Tags... > &a, T2 b)
OctetString operator^(const OctetString &k1, const OctetString &k2)
Definition symkey.cpp:109
OctetString operator+(const OctetString &k1, const OctetString &k2)
Definition symkey.cpp:99
constexpr auto operator++(Strong< T, Tags... > &a, int)
std::ostream & operator<<(std::ostream &out, const OID &oid)
Definition asn1_obj.h:334
BigInt operator/(const BigInt &x, const BigInt &y)
Definition big_ops3.cpp:105
BigInt operator-(const BigInt &x, const BigInt &y)
Definition bigint.h:1095
constexpr auto operator/=(Strong< T1, Tags... > &a, T2 b)
constexpr auto operator|=(Strong< T1, Tags... > &a, T2 b)
constexpr decltype(auto) unwrap_strong_type(T &&t)
Generically unwraps a strong type to its underlying type.
constexpr auto operator<<=(Strong< T1, Tags... > &a, T2 b)
constexpr auto operator&=(Strong< T1, Tags... > &a, T2 b)
typename detail::wrapped_type_helper< std::remove_cvref_t< T > >::type strong_type_wrapped_type
Extracts the wrapped type from a strong type.
bool operator==(const AlgorithmIdentifier &a1, const AlgorithmIdentifier &a2)
Definition alg_id.cpp:53
std::vector< uint8_t, Alloc > & operator^=(std::vector< uint8_t, Alloc > &out, const std::vector< uint8_t, Alloc2 > &in)
Definition mem_ops.h:446
constexpr decltype(auto) wrap_strong_type(ParamT &&t)
Wraps a value into a caller-defined (strong) type.
constexpr bool is_strong_span_v
std::vector< T, Alloc > & operator+=(std::vector< T, Alloc > &out, const std::vector< T, Alloc2 > &in)
Definition secmem.h:91
int operator>>(int fd, Pipe &pipe)
Definition fd_unix.cpp:39
constexpr auto operator-=(Strong< T1, Tags... > &a, T2 b)
constexpr auto operator--(Strong< T, Tags... > &a, int)
auto operator<=>(const Strong< T, Tags... > &lhs, const Strong< T, Tags... > &rhs)
ECIES_Flags operator&(ECIES_Flags a, ECIES_Flags b)
Definition ecies.h:70
constexpr auto operator*=(Strong< T1, Tags... > &a, T2 b)