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