Botan 3.6.1
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 <ostream>
13#include <span>
14
15#include <botan/concepts.h>
16
17namespace Botan {
18
19/**
20 * Added as an additional "capability tag" to enable arithmetic operators with
21 * plain numbers for Strong<> types that wrap a number.
22 */
24
25namespace detail {
26
27/**
28 * Checks whether the @p CapabilityT is included in the @p Tags type pack.
29 */
30template <typename CapabilityT, typename... Tags>
31constexpr bool has_capability = (std::is_same_v<CapabilityT, Tags> || ...);
32
33template <typename T>
35 private:
36 T m_value;
37
38 public:
39 using wrapped_type = T;
40
41 public:
42 Strong_Base() = default;
43 Strong_Base(const Strong_Base&) = default;
44 Strong_Base(Strong_Base&&) noexcept = default;
45 Strong_Base& operator=(const Strong_Base&) = default;
46 Strong_Base& operator=(Strong_Base&&) noexcept = default;
47
48 constexpr explicit Strong_Base(T v) : m_value(std::move(v)) {}
49
50 constexpr T& get() & { return m_value; }
51
52 constexpr const T& get() const& { return m_value; }
53
54 constexpr T&& get() && { return std::move(m_value); }
55
56 constexpr const T&& get() const&& { return std::move(m_value); }
57};
58
59template <typename T>
60class Strong_Adapter : public Strong_Base<T> {
61 public:
63};
64
65template <std::integral T>
66class Strong_Adapter<T> : public Strong_Base<T> {
67 public:
69};
70
71template <concepts::container T>
72class Strong_Adapter<T> : public Strong_Base<T> {
73 public:
74 using value_type = typename T::value_type;
75 using size_type = typename T::size_type;
76 using iterator = typename T::iterator;
77 using const_iterator = typename T::const_iterator;
78 using pointer = typename T::pointer;
79 using const_pointer = typename T::const_pointer;
80
81 public:
83
84 explicit Strong_Adapter(std::span<const value_type> span)
86 : Strong_Adapter(T(span.begin(), span.end())) {}
87
88 explicit Strong_Adapter(size_t size)
90 : Strong_Adapter(T(size)) {}
91
92 template <typename InputIt>
93 Strong_Adapter(InputIt begin, InputIt end) : Strong_Adapter(T(begin, end)) {}
94
95 // Disambiguates the usage of string literals, otherwise:
96 // Strong_Adapter(std::span<>) and Strong_Adapter(const char*)
97 // would be ambiguous.
98 explicit Strong_Adapter(const char* str)
99 requires(std::same_as<T, std::string>)
100 : Strong_Adapter(std::string(str)) {}
101
102 public:
103 decltype(auto) begin() noexcept(noexcept(this->get().begin())) { return this->get().begin(); }
104
105 decltype(auto) begin() const noexcept(noexcept(this->get().begin())) { return this->get().begin(); }
106
107 decltype(auto) end() noexcept(noexcept(this->get().end())) { return this->get().end(); }
108
109 decltype(auto) end() const noexcept(noexcept(this->get().end())) { return this->get().end(); }
110
111 decltype(auto) cbegin() noexcept(noexcept(this->get().cbegin())) { return this->get().cbegin(); }
112
113 decltype(auto) cbegin() const noexcept(noexcept(this->get().cbegin())) { return this->get().cbegin(); }
114
115 decltype(auto) cend() noexcept(noexcept(this->get().cend())) { return this->get().cend(); }
116
117 decltype(auto) cend() const noexcept(noexcept(this->get().cend())) { return this->get().cend(); }
118
119 size_type size() const noexcept(noexcept(this->get().size())) { return this->get().size(); }
120
121 decltype(auto) data() noexcept(noexcept(this->get().data()))
123 {
124 return this->get().data();
125 }
126
127 decltype(auto) data() const noexcept(noexcept(this->get().data()))
129 {
130 return this->get().data();
131 }
132
133 bool empty() const noexcept(noexcept(this->get().empty()))
134 requires(concepts::has_empty<T>)
135 {
136 return this->get().empty();
137 }
138
139 void resize(size_type size) noexcept(noexcept(this->get().resize(size)))
141 {
142 this->get().resize(size);
143 }
144
145 void reserve(size_type size) noexcept(noexcept(this->get().reserve(size)))
147 {
148 this->get().reserve(size);
149 }
150
151 decltype(auto) operator[](size_type i) const noexcept(noexcept(this->get().operator[](i))) {
152 return this->get()[i];
153 }
154
155 decltype(auto) operator[](size_type i) noexcept(noexcept(this->get().operator[](i))) { return this->get()[i]; }
156};
157
158} // namespace detail
159
160/**
161 * Strong types can be used as wrappers around common types to provide
162 * compile time semantics. They usually contribute to more maintainable and
163 * less error-prone code especially when dealing with function parameters.
164 *
165 * Internally, this provides adapters so that the wrapping strong type behaves
166 * as much as the underlying type as possible and desirable.
167 *
168 * This implementation was inspired by:
169 * https://stackoverflow.com/a/69030899
170 */
171template <typename T, typename TagTypeT, typename... Capabilities>
173 public:
175
176 template <typename CapabilityT>
177 constexpr static bool has_capability() {
178 return (std::is_same_v<CapabilityT, Capabilities> || ...);
179 }
180
181 private:
182 using Tag = TagTypeT;
183};
184
185/**
186 * @brief Generically unwraps a strong type to its underlying type.
187 *
188 * If the provided type is not a strong type, it is returned as is.
189 *
190 * @note This is meant as a helper for generic code that needs to deal with both
191 * wrapped strong types and bare objects. Use the ordinary `get()` method
192 * if you know that you are dealing with a strong type.
193 *
194 * @param t value to be unwrapped
195 * @return the unwrapped value
196 */
197template <typename T>
198[[nodiscard]] constexpr decltype(auto) unwrap_strong_type(T&& t) {
200 // If the parameter type isn't a strong type, return it as is.
201 return std::forward<T>(t);
202 } else {
203 // Unwrap the strong type and return the underlying value.
204 return std::forward<T>(t).get();
205 }
206}
207
208/**
209 * @brief Wraps a value into a caller-defined (strong) type.
210 *
211 * If the provided object @p t is already of type @p T, it is returned as is.
212 *
213 * @note This is meant as a helper for generic code that needs to deal with both
214 * wrapped strong types and bare objects. Use the ordinary constructor if
215 * you know that you are dealing with a bare value type.
216 *
217 * @param t value to be wrapped
218 * @return the wrapped value
219 */
220template <typename T, typename ParamT>
221 requires std::constructible_from<T, ParamT> ||
222 (concepts::strong_type<T> && std::constructible_from<typename T::wrapped_type, ParamT>)
223[[nodiscard]] constexpr decltype(auto) wrap_strong_type(ParamT&& t) {
224 if constexpr(std::same_as<std::remove_cvref_t<ParamT>, T>) {
225 // Noop, if the parameter type already is the desired return type.
226 return std::forward<ParamT>(t);
227 } else if constexpr(std::constructible_from<T, ParamT>) {
228 // Implicit conversion from the parameter type to the return type.
229 return T{std::forward<ParamT>(t)};
230 } else {
231 // Explicitly calling the wrapped type's constructor to support
232 // implicit conversions on types that mark their constructors as explicit.
233 static_assert(concepts::strong_type<T> && std::constructible_from<typename T::wrapped_type, ParamT>);
234 return T{typename T::wrapped_type{std::forward<ParamT>(t)}};
235 }
236}
237
238namespace detail {
239
240template <typename T>
242 using type = T;
243};
244
245template <concepts::strong_type T>
247 using type = typename T::wrapped_type;
248};
249
250} // namespace detail
251
252/**
253 * @brief Extracts the wrapped type from a strong type.
254 *
255 * If the provided type is not a strong type, it is returned as is.
256 *
257 * @note This is meant as a helper for generic code that needs to deal with both
258 * wrapped strong types and bare objects. Use the ordinary `::wrapped_type`
259 * declaration if you know that you are dealing with a strong type.
260 */
261template <typename T>
263
264template <typename T, typename... Tags>
266decltype(auto) operator<<(std::ostream& os, const Strong<T, Tags...>& v) {
267 return os << v.get();
268}
269
270template <typename T, typename... Tags>
271 requires(std::equality_comparable<T>)
272bool operator==(const Strong<T, Tags...>& lhs, const Strong<T, Tags...>& rhs) {
273 return lhs.get() == rhs.get();
274}
275
276template <typename T, typename... Tags>
277 requires(std::three_way_comparable<T>)
279 return lhs.get() <=> rhs.get();
280}
281
282template <std::integral T1, std::integral T2, typename... Tags>
284 return a <=> b.get();
285}
286
287template <std::integral T1, std::integral T2, typename... Tags>
289 return a.get() <=> b;
290}
291
292template <std::integral T1, std::integral T2, typename... Tags>
294 return a == b.get();
295}
296
297template <std::integral T1, std::integral T2, typename... Tags>
299 return a.get() == b;
300}
301
302template <std::integral T1, std::integral T2, typename... Tags>
303 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
304constexpr decltype(auto) operator+(T1 a, Strong<T2, Tags...> b) {
305 return Strong<T2, Tags...>(a + b.get());
306}
307
308template <std::integral T1, std::integral T2, typename... Tags>
309 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
310constexpr decltype(auto) operator+(Strong<T1, Tags...> a, T2 b) {
311 return Strong<T1, Tags...>(a.get() + b);
312}
313
314template <std::integral T, typename... Tags>
315constexpr decltype(auto) operator+(Strong<T, Tags...> a, Strong<T, Tags...> b) {
316 return Strong<T, Tags...>(a.get() + b.get());
317}
318
319template <std::integral T1, std::integral T2, typename... Tags>
320 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
321constexpr decltype(auto) operator-(T1 a, Strong<T2, Tags...> b) {
322 return Strong<T2, Tags...>(a - b.get());
323}
324
325template <std::integral T1, std::integral T2, typename... Tags>
326 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
327constexpr decltype(auto) operator-(Strong<T1, Tags...> a, T2 b) {
328 return Strong<T1, Tags...>(a.get() - b);
329}
330
331template <std::integral T, typename... Tags>
332constexpr decltype(auto) operator-(Strong<T, Tags...> a, Strong<T, Tags...> b) {
333 return Strong<T, Tags...>(a.get() - b.get());
334}
335
336template <std::integral T1, std::integral T2, typename... Tags>
337 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
338constexpr decltype(auto) operator*(T1 a, Strong<T2, Tags...> b) {
339 return Strong<T2, Tags...>(a * b.get());
340}
341
342template <std::integral T1, std::integral T2, typename... Tags>
343 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
344constexpr decltype(auto) operator*(Strong<T1, Tags...> a, T2 b) {
345 return Strong<T1, Tags...>(a.get() * b);
346}
347
348template <std::integral T, typename... Tags>
349constexpr decltype(auto) operator*(Strong<T, Tags...> a, Strong<T, Tags...> b) {
350 return Strong<T, Tags...>(a.get() * b.get());
351}
352
353template <std::integral T1, std::integral T2, typename... Tags>
354 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
355constexpr decltype(auto) operator/(T1 a, Strong<T2, Tags...> b) {
356 return Strong<T2, Tags...>(a / b.get());
357}
358
359template <std::integral T1, std::integral T2, typename... Tags>
360 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
361constexpr decltype(auto) operator/(Strong<T1, Tags...> a, T2 b) {
362 return Strong<T1, Tags...>(a.get() / b);
363}
364
365template <std::integral T, typename... Tags>
366constexpr decltype(auto) operator/(Strong<T, Tags...> a, Strong<T, Tags...> b) {
367 return Strong<T, Tags...>(a.get() / b.get());
368}
369
370template <std::integral T1, std::integral T2, typename... Tags>
371 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
372constexpr decltype(auto) operator^(T1 a, Strong<T2, Tags...> b) {
373 return Strong<T2, Tags...>(a ^ b.get());
374}
375
376template <std::integral T1, std::integral T2, typename... Tags>
377 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
378constexpr decltype(auto) operator^(Strong<T1, Tags...> a, T2 b) {
379 return Strong<T1, Tags...>(a.get() ^ b);
380}
381
382template <std::integral T, typename... Tags>
383constexpr decltype(auto) operator^(Strong<T, Tags...> a, Strong<T, Tags...> b) {
384 return Strong<T, Tags...>(a.get() ^ b.get());
385}
386
387template <std::integral T1, std::integral T2, typename... Tags>
388 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
389constexpr decltype(auto) operator&(T1 a, Strong<T2, Tags...> b) {
390 return Strong<T2, Tags...>(a & b.get());
391}
392
393template <std::integral T1, std::integral T2, typename... Tags>
394 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
395constexpr decltype(auto) operator&(Strong<T1, Tags...> a, T2 b) {
396 return Strong<T1, Tags...>(a.get() & b);
397}
398
399template <std::integral T, typename... Tags>
400constexpr decltype(auto) operator&(Strong<T, Tags...> a, Strong<T, Tags...> b) {
401 return Strong<T, Tags...>(a.get() & b.get());
402}
403
404template <std::integral T1, std::integral T2, typename... Tags>
405 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
406constexpr decltype(auto) operator|(T1 a, Strong<T2, Tags...> b) {
407 return Strong<T2, Tags...>(a | b.get());
408}
409
410template <std::integral T1, std::integral T2, typename... Tags>
411 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
412constexpr decltype(auto) operator|(Strong<T1, Tags...> a, T2 b) {
413 return Strong<T1, Tags...>(a.get() | b);
414}
415
416template <std::integral T, typename... Tags>
417constexpr decltype(auto) operator|(Strong<T, Tags...> a, Strong<T, Tags...> b) {
418 return Strong<T, Tags...>(a.get() | b.get());
419}
420
421template <std::integral T1, std::integral T2, typename... Tags>
422 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
423constexpr decltype(auto) operator>>(T1 a, Strong<T2, Tags...> b) {
424 return Strong<T2, Tags...>(a >> b.get());
425}
426
427template <std::integral T1, std::integral T2, typename... Tags>
428 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
429constexpr decltype(auto) operator>>(Strong<T1, Tags...> a, T2 b) {
430 return Strong<T1, Tags...>(a.get() >> b);
431}
432
433template <std::integral T, typename... Tags>
434constexpr decltype(auto) operator>>(Strong<T, Tags...> a, Strong<T, Tags...> b) {
435 return Strong<T, Tags...>(a.get() >> b.get());
436}
437
438template <std::integral T1, std::integral T2, typename... Tags>
439 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
440constexpr decltype(auto) operator<<(T1 a, Strong<T2, Tags...> b) {
441 return Strong<T2, Tags...>(a << b.get());
442}
443
444template <std::integral T1, std::integral T2, typename... Tags>
445 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
446constexpr decltype(auto) operator<<(Strong<T1, Tags...> a, T2 b) {
447 return Strong<T1, Tags...>(a.get() << b);
448}
449
450template <std::integral T, typename... Tags>
451constexpr decltype(auto) operator<<(Strong<T, Tags...> a, Strong<T, Tags...> b) {
452 return Strong<T, Tags...>(a.get() << b.get());
453}
454
455template <std::integral T1, std::integral T2, typename... Tags>
456 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
457constexpr auto operator+=(Strong<T1, Tags...>& a, T2 b) {
458 a.get() += b;
459 return a;
460}
461
462template <std::integral T, typename... Tags>
464 a.get() += b.get();
465 return a;
466}
467
468template <std::integral T1, std::integral T2, typename... Tags>
469 requires(detail::has_capability<EnableArithmeticWithPlainNumber, Tags...>)
470constexpr auto operator-=(Strong<T1, Tags...>& a, T2 b) {
471 a.get() -= b;
472 return a;
473}
474
475template <std::integral T, typename... Tags>
477 a.get() -= b.get();
478 return a;
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 T, typename... Tags>
573constexpr auto operator++(Strong<T, Tags...>& a, int) {
574 auto tmp = a;
575 ++a.get();
576 return tmp;
577}
578
579template <std::integral T, typename... Tags>
580constexpr auto operator++(Strong<T, Tags...>& a) {
581 ++a.get();
582 return a;
583}
584
585template <std::integral T, typename... Tags>
586constexpr auto operator--(Strong<T, Tags...>& a, int) {
587 auto tmp = a;
588 --a.get();
589 return tmp;
590}
591
592template <std::integral T, typename... Tags>
593constexpr auto operator--(Strong<T, Tags...>& a) {
594 --a.get();
595 return a;
596}
597
598/**
599 * This mimmicks a std::span but keeps track of the strong-type information. Use
600 * this when you would want to use `const Strong<...>&` as a parameter
601 * declaration. In particular this allows assigning strong-type information to
602 * slices of a bigger buffer without copying the bytes. E.g:
603 *
604 * using Foo = Strong<std::vector<uint8_t>, Foo_>;
605 *
606 * void bar(StrongSpan<Foo> foo) { ... }
607 *
608 * std::vector<uint8_t> buffer;
609 * BufferSlicer slicer(buffer);
610 * bar(slicer.take<Foo>()); // This does not copy the data from buffer but
611 * // just annotates the 'Foo' strong-type info.
612 */
613template <concepts::contiguous_strong_type T>
615 using underlying_span = std::
616 conditional_t<std::is_const_v<T>, std::span<const typename T::value_type>, std::span<typename T::value_type>>;
617
618 public:
619 using value_type = typename underlying_span::value_type;
620 using size_type = typename underlying_span::size_type;
621 using iterator = typename underlying_span::iterator;
622 using pointer = typename underlying_span::pointer;
623 using const_pointer = typename underlying_span::const_pointer;
624
625 StrongSpan() = default;
626
627 explicit StrongSpan(underlying_span span) : m_span(span) {}
628
629 StrongSpan(T& strong) : m_span(strong) {}
630
631 // Allows implicit conversion from `StrongSpan<T>` to `StrongSpan<const T>`.
632 // Note that this is not bi-directional. Conversion from `StrongSpan<const T>`
633 // to `StrongSpan<T>` is not allowed.
634 //
635 // TODO: Technically, we should be able to phrase this with a `requires std::is_const_v<T>`
636 // instead of the `std::enable_if` constructions. clang-tidy (14 or 15) doesn't seem
637 // to pick up on that (yet?). As a result, for a non-const T it assumes this to be
638 // a declaration of an ordinary copy constructor. The existance of a copy constructor
639 // is interpreted as "not cheap to copy", setting off the `performance-unnecessary-value-param` check.
640 // See also: https://github.com/randombit/botan/issues/3591
642 typename = std::enable_if_t<std::is_same_v<T2, std::remove_const_t<T>>>>
643 StrongSpan(const StrongSpan<T2>& other) : m_span(other.get()) {}
644
645 StrongSpan(const StrongSpan& other) = default;
646
647 ~StrongSpan() = default;
648
649 /**
650 * @returns the underlying std::span without any type constraints
651 */
652 underlying_span get() const { return m_span; }
653
654 /**
655 * @returns the underlying std::span without any type constraints
656 */
657 underlying_span get() { return m_span; }
658
659 decltype(auto) data() noexcept(noexcept(this->m_span.data())) { return this->m_span.data(); }
660
661 decltype(auto) data() const noexcept(noexcept(this->m_span.data())) { return this->m_span.data(); }
662
663 decltype(auto) size() const noexcept(noexcept(this->m_span.size())) { return this->m_span.size(); }
664
665 bool empty() const noexcept(noexcept(this->m_span.empty())) { return this->m_span.empty(); }
666
667 decltype(auto) begin() noexcept(noexcept(this->m_span.begin())) { return this->m_span.begin(); }
668
669 decltype(auto) begin() const noexcept(noexcept(this->m_span.begin())) { return this->m_span.begin(); }
670
671 decltype(auto) end() noexcept(noexcept(this->m_span.end())) { return this->m_span.end(); }
672
673 decltype(auto) end() const noexcept(noexcept(this->m_span.end())) { return this->m_span.end(); }
674
675 decltype(auto) operator[](typename underlying_span::size_type i) const noexcept { return this->m_span[i]; }
676
677 private:
678 underlying_span m_span;
679};
680
681template <typename>
682struct is_strong_span : std::false_type {};
683
684template <typename T>
685struct is_strong_span<StrongSpan<T>> : std::true_type {};
686
687template <typename T>
689
690} // namespace Botan
691
692#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(const StrongSpan< T2 > &other)
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
decltype(auto) end() noexcept(noexcept(this->m_span.end()))
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()))
typename underlying_span::iterator iterator
decltype(auto) size() const noexcept(noexcept(this->m_span.size()))
static constexpr bool has_capability()
decltype(auto) data() const noexcept(noexcept(this->get().data()))
typename T::size_type size_type
Definition strong_type.h:75
decltype(auto) end() const noexcept(noexcept(this->get().end()))
void resize(size_type size) noexcept(noexcept(this->get().resize(size)))
typename T::iterator iterator
Definition strong_type.h:76
void reserve(size_type size) noexcept(noexcept(this->get().reserve(size)))
decltype(auto) begin() noexcept(noexcept(this->get().begin()))
size_type size() const noexcept(noexcept(this->get().size()))
decltype(auto) cbegin() noexcept(noexcept(this->get().cbegin()))
typename T::const_pointer const_pointer
Definition strong_type.h:79
typename T::value_type value_type
Definition strong_type.h:74
decltype(auto) begin() const noexcept(noexcept(this->get().begin()))
decltype(auto) cend() const noexcept(noexcept(this->get().cend()))
decltype(auto) end() noexcept(noexcept(this->get().end()))
typename T::const_iterator const_iterator
Definition strong_type.h:77
bool empty() const noexcept(noexcept(this->get().empty()))
decltype(auto) data() noexcept(noexcept(this->get().data()))
Strong_Adapter(std::span< const value_type > span)
Definition strong_type.h:84
decltype(auto) cend() noexcept(noexcept(this->get().cend()))
decltype(auto) cbegin() const noexcept(noexcept(this->get().cbegin()))
Strong_Adapter(InputIt begin, InputIt end)
Definition strong_type.h:93
constexpr const T & get() const &
Definition strong_type.h:52
Strong_Base(Strong_Base &&) noexcept=default
constexpr T & get() &
Definition strong_type.h:50
constexpr const T && get() const &&
Definition strong_type.h:56
constexpr T && get() &&
Definition strong_type.h:54
Strong_Base(const Strong_Base &)=default
FE_25519 T
Definition ge.cpp:34
constexpr bool has_capability
Definition strong_type.h:31
ASN1_Type operator|(ASN1_Type x, ASN1_Type y)
Definition asn1_obj.h:75
BigInt operator*(const BigInt &x, const BigInt &y)
Definition big_ops3.cpp:46
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:322
BigInt operator/(const BigInt &x, const BigInt &y)
Definition big_ops3.cpp:95
BigInt operator-(const BigInt &x, const BigInt &y)
Definition bigint.h:1094
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:54
std::vector< uint8_t, Alloc > & operator^=(std::vector< uint8_t, Alloc > &out, const std::vector< uint8_t, Alloc2 > &in)
Definition mem_ops.h:445
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:80
int operator>>(int fd, Pipe &pipe)
Definition fd_unix.cpp:39
constexpr auto operator-=(Strong< T1, Tags... > &a, T2 b)
const SIMD_8x32 & 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:50
constexpr auto operator*=(Strong< T1, Tags... > &a, T2 b)