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