gw  1.0.0
A bunch of small C++ utilities
Loading...
Searching...
No Matches
named_type.hpp
1// Copyright (c) 2023 Martin Stump
2// SPDX-License-Identifier: BSL-1.0
3
4#pragma once
5
6#include <algorithm>
7#include <compare>
8#include <concepts>
9#include <cstddef>
10#include <format>
11#include <functional>
12#include <initializer_list>
13#include <iostream>
14#include <ranges>
15#include <string_view>
16#include <type_traits>
17#include <utility>
18
19#include "gw/concepts.hpp"
20#include "gw/inplace_string.hpp"
21
23namespace gw {
24
25namespace detail {
26
27struct named_type_empty_base {
28 constexpr auto operator<=>(const named_type_empty_base&) const noexcept -> std::strong_ordering = default;
29};
30
31} // namespace detail
32
34//
36//
43//
44template <typename T, basic_inplace_string Name>
45class named_type final
46 : public std::conditional_t<std::ranges::range<T>, std::ranges::view_interface<named_type<T, Name>>,
47 detail::named_type_empty_base> {
48 public:
49 //
50 // Public types
51 //
52
53 using value_type = T;
55 using const_reference = const value_type&;
57 using const_pointer = const value_type*;
58
59 //
60 // Constructors
61 //
62
64 template <typename... Args>
65 constexpr explicit named_type(Args&&... args) noexcept(std::is_nothrow_constructible_v<value_type, Args...>)
66 requires std::constructible_from<value_type, Args...>
67 : m_value(value_type{std::forward<Args>(args)...}) {}
68
70 template <typename U, typename... Args>
71 constexpr named_type(std::initializer_list<U> ilist, Args&&... args) noexcept(
72 std::is_nothrow_constructible_v<value_type, std::initializer_list<U>&, Args...>)
73 requires std::constructible_from<value_type, std::initializer_list<U>&, Args...>
74 : m_value(value_type{ilist, std::forward<Args>(args)...}) {}
75
76 //
77 // Destructor
78 //
79
81 ~named_type() noexcept(std::is_nothrow_destructible_v<value_type>) = default;
82
83 //
84 // Static functions
85 //
86
88 static constexpr auto name() noexcept { return Name.view(); }
89
90 //
91 // Observers
92 //
93
95 constexpr auto operator->() const noexcept -> const_pointer { return &m_value; }
96
98 constexpr auto operator->() noexcept -> pointer { return &m_value; }
99
101 constexpr auto operator*() const& noexcept -> const_reference { return m_value; }
102
104 constexpr auto operator*() & noexcept -> reference { return m_value; }
105
107 constexpr auto operator*() const&& noexcept -> const value_type&& { return std::move(m_value); }
108
110 constexpr auto operator*() && noexcept -> value_type&& { return std::move(m_value); }
111
113 constexpr auto value() const& noexcept -> const_reference { return m_value; }
114
116 constexpr auto value() & noexcept -> reference { return m_value; }
117
119 constexpr auto value() const&& noexcept -> const value_type&& { return std::move(m_value); }
120
122 constexpr auto value() && noexcept -> value_type&& { return std::move(m_value); }
123
124 //
125 // Monadic operations
126 //
127
129 template <typename F>
130 constexpr auto transform(F&& func) const& noexcept(noexcept(func(m_value))) -> named_type
131 requires std::invocable<F, const_reference>
132 {
134 }
135
137 template <typename F>
138 constexpr auto transform(F&& func) & noexcept(noexcept(func(m_value))) -> named_type
139 requires std::invocable<F, reference>
140 {
142 }
143
145 template <typename F>
146 constexpr auto transform(F&& func) const&& noexcept(noexcept(func(m_value))) -> named_type
147 requires std::invocable<F, const value_type&&>
148 {
150 }
151
153 template <typename F>
154 constexpr auto transform(F&& func) && noexcept(noexcept(func(m_value))) -> named_type
155 requires std::invocable<F, value_type&&>
156 {
157 return named_type<std::remove_cv_t<std::invoke_result_t<F, value_type&&>>, Name>{func(std::move(m_value))};
158 }
159
160 //
161 // Modifiers
162 //
163
165 constexpr void swap(named_type& rhs) noexcept(std::is_nothrow_swappable_v<value_type>)
166 requires std::swappable<value_type>
167 {
168 using std::swap;
169 swap(m_value, rhs.m_value);
170 }
171
173 constexpr void reset() noexcept(std::is_nothrow_default_constructible_v<value_type>)
174 requires std::default_initializable<value_type>
175 {
176 m_value = value_type{};
177 }
178
180 template <typename... Args>
181 constexpr auto emplace(Args&&... args) noexcept(std::is_nothrow_constructible_v<value_type, Args...>) -> reference
182 requires std::constructible_from<value_type, Args...>
183 {
184 m_value = value_type{std::forward<Args>(args)...};
185 return m_value;
186 }
187
188 //
189 // Comparison operators
190 //
191
193 constexpr auto operator==(const named_type& rhs) const& noexcept(noexcept(m_value == rhs.m_value)) -> bool
194 requires std::equality_comparable<value_type>
195 {
196 return m_value == rhs.m_value;
197 }
198
200 constexpr auto operator!=(const named_type& rhs) const& noexcept(noexcept(m_value != rhs.m_value)) -> bool
201 requires std::equality_comparable<value_type>
202 {
203 return m_value != rhs.m_value;
204 }
205
207 constexpr auto operator<(const named_type& rhs) const& noexcept(noexcept(m_value < rhs.m_value)) -> bool
208 requires std::totally_ordered<value_type>
209 {
210 return m_value < rhs.m_value;
211 }
212
214 constexpr auto operator>(const named_type& rhs) const& noexcept(noexcept(m_value > rhs.m_value)) -> bool
215 requires std::totally_ordered<value_type>
216 {
217 return m_value > rhs.m_value;
218 }
219
221 constexpr auto operator<=(const named_type& rhs) const& noexcept(noexcept(m_value <= rhs.m_value)) -> bool
222 requires std::totally_ordered<value_type>
223 {
224 return m_value <= rhs.m_value;
225 }
226
228 constexpr auto operator>=(const named_type& rhs) const& noexcept(noexcept(m_value >= rhs.m_value)) -> bool
229 requires std::totally_ordered<value_type>
230 {
231 return m_value >= rhs.m_value;
232 }
233
235 constexpr auto operator<=>(const named_type& rhs) const& noexcept(noexcept(m_value <=>
236 rhs.m_value)) -> std::strong_ordering
237 requires std::three_way_comparable<value_type>
238 {
239 return m_value <=> rhs.m_value;
240 }
241
242 //
243 // Conversion operators
244 //
245
247 constexpr explicit operator const_reference() const& noexcept { return m_value; }
248
250 constexpr explicit operator reference() & noexcept { return m_value; }
251
253 constexpr explicit operator const value_type&&() const&& noexcept { return std::move(m_value); }
254
256 constexpr explicit operator value_type&&() && noexcept { return std::move(m_value); }
257
258 //
259 // Increment and decrement operators
260 //
261
263 constexpr auto operator++() & noexcept(noexcept(++m_value)) -> named_type&
265 {
266 ++m_value;
267 return *this;
268 }
269
271 constexpr auto operator++() && noexcept(noexcept(++m_value)) -> named_type&&
273 {
274 ++m_value;
275 return std::move(*this);
276 }
277
279 constexpr auto operator++(int) & noexcept(noexcept(m_value++)) -> named_type
281 {
282 return named_type{m_value++};
283 }
284
286 constexpr auto operator++(int) && noexcept(noexcept(m_value++)) -> named_type
288 {
289 return named_type{m_value++};
290 }
291
293 constexpr auto operator--() & noexcept(noexcept(--m_value)) -> named_type&
295 {
296 --m_value;
297 return *this;
298 }
299
301 constexpr auto operator--() && noexcept(noexcept(--m_value)) -> named_type&&
303 {
304 --m_value;
305 return std::move(*this);
306 }
307
309 constexpr auto operator--(int) & noexcept(noexcept(m_value--)) -> named_type
311 {
312 return named_type{m_value--};
313 }
314
316 constexpr auto operator--(int) && noexcept(noexcept(m_value--)) -> named_type
318 {
319 return named_type{m_value--};
320 }
321
322 //
323 // Arithmetic operators
324 //
325
327 constexpr auto operator+() const& noexcept(noexcept(+m_value)) -> named_type
328 requires std::signed_integral<value_type>
329 {
330 return named_type{+m_value};
331 }
332
334 constexpr auto operator+() && noexcept(noexcept(+m_value)) -> named_type
335 requires std::signed_integral<value_type>
336 {
337 return named_type{+m_value};
338 }
339
341 constexpr auto operator-() const& noexcept(noexcept(-m_value)) -> named_type
342 requires std::signed_integral<value_type>
343 {
344 return named_type{-m_value};
345 }
346
348 constexpr auto operator-() && noexcept(noexcept(-m_value)) -> named_type
349 requires std::signed_integral<value_type>
350 {
351 return named_type{-m_value};
352 }
353
355 constexpr auto operator+(const named_type& rhs) const& noexcept(noexcept(m_value + rhs.m_value)) -> named_type
357 {
358 return named_type{m_value + rhs.m_value};
359 }
360
362 constexpr auto operator+(named_type&& rhs) const& noexcept(noexcept(m_value + rhs.m_value)) -> named_type
364 {
365 return named_type{m_value + rhs.m_value};
366 }
367
369 constexpr auto operator+(const named_type& rhs) && noexcept(noexcept(m_value + rhs.m_value)) -> named_type
371 {
372 return named_type{m_value + rhs.m_value};
373 }
374
376 constexpr auto operator+(named_type&& rhs) && noexcept(noexcept(m_value + rhs.m_value)) -> named_type
378 {
379 return named_type{m_value + rhs.m_value};
380 }
381
383 constexpr auto operator-(const named_type& rhs) const& noexcept(noexcept(m_value - rhs.m_value)) -> named_type
385 {
386 return named_type{m_value - rhs.m_value};
387 }
388
390 constexpr auto operator-(named_type&& rhs) const& noexcept(noexcept(m_value - rhs.m_value)) -> named_type
392 {
393 return named_type{m_value - rhs.m_value};
394 }
395
397 constexpr auto operator-(const named_type& rhs) && noexcept(noexcept(m_value - rhs.m_value)) -> named_type
399 {
400 return named_type{m_value - rhs.m_value};
401 }
402
404 constexpr auto operator-(named_type&& rhs) && noexcept(noexcept(m_value - rhs.m_value)) -> named_type
406 {
407 return named_type{m_value - rhs.m_value};
408 }
409
411 constexpr auto operator*(const named_type& rhs) const& noexcept(noexcept(m_value * rhs.m_value)) -> named_type
413 {
414 return named_type{m_value * rhs.m_value};
415 }
416
418 constexpr auto operator*(named_type&& rhs) const& noexcept(noexcept(m_value * rhs.m_value)) -> named_type
420 {
421 return named_type{m_value * rhs.m_value};
422 }
423
425 constexpr auto operator*(const named_type& rhs) && noexcept(noexcept(m_value * rhs.m_value)) -> named_type
427 {
428 return named_type{m_value * rhs.m_value};
429 }
430
432 constexpr auto operator*(named_type&& rhs) && noexcept(noexcept(m_value * rhs.m_value)) -> named_type
434 {
435 return named_type{m_value * rhs.m_value};
436 }
437
439 constexpr auto operator/(const named_type& rhs) const& noexcept(noexcept(m_value / rhs.m_value)) -> named_type
441 {
442 return named_type{m_value / rhs.m_value};
443 }
444
446 constexpr auto operator/(named_type&& rhs) const& noexcept(noexcept(m_value / rhs.m_value)) -> named_type
448 {
449 return named_type{m_value / rhs.m_value};
450 }
451
453 constexpr auto operator/(const named_type& rhs) && noexcept(noexcept(m_value / rhs.m_value)) -> named_type
455 {
456 return named_type{m_value / rhs.m_value};
457 }
458
460 constexpr auto operator/(named_type&& rhs) && noexcept(noexcept(m_value / rhs.m_value)) -> named_type
462 {
463 return named_type{m_value / rhs.m_value};
464 }
465
467 constexpr auto operator%(const named_type& rhs) const& noexcept(noexcept(m_value % rhs.m_value)) -> named_type
469 {
470 return named_type{m_value % rhs.m_value};
471 }
472
474 constexpr auto operator%(named_type&& rhs) const& noexcept(noexcept(m_value % rhs.m_value)) -> named_type
476 {
477 return named_type{m_value % rhs.m_value};
478 }
479
481 constexpr auto operator%(const named_type& rhs) && noexcept(noexcept(m_value % rhs.m_value)) -> named_type
483 {
484 return named_type{m_value % rhs.m_value};
485 }
486
488 constexpr auto operator%(named_type&& rhs) && noexcept(noexcept(m_value % rhs.m_value)) -> named_type
490 {
491 return named_type{m_value % rhs.m_value};
492 }
493
495 constexpr auto operator+=(const named_type& rhs) & noexcept(noexcept(m_value += rhs.m_value)) -> named_type&
497 {
498 m_value += rhs.m_value;
499 return *this;
500 }
501
503 constexpr auto operator+=(named_type&& rhs) & noexcept(noexcept(m_value += rhs.m_value)) -> named_type&
504 requires arithmetic<value_type>
505 {
506 m_value += rhs.m_value;
507 return *this;
508 }
509
511 constexpr auto operator-=(const named_type& rhs) & noexcept(noexcept(m_value -= rhs.m_value)) -> named_type&
512 requires arithmetic<value_type>
513 {
514 m_value -= rhs.m_value;
515 return *this;
516 }
517
519 constexpr auto operator-=(named_type&& rhs) & noexcept(noexcept(m_value -= rhs.m_value)) -> named_type&
520 requires arithmetic<value_type>
521 {
522 m_value -= rhs.m_value;
523 return *this;
524 }
525
527 constexpr auto operator*=(const named_type& rhs) & noexcept(noexcept(m_value *= rhs.m_value)) -> named_type&
528 requires arithmetic<value_type>
529 {
530 m_value *= rhs.m_value;
531 return *this;
532 }
533
535 constexpr auto operator*=(named_type&& rhs) & noexcept(noexcept(m_value *= rhs.m_value)) -> named_type&
536 requires arithmetic<value_type>
537 {
538 m_value *= rhs.m_value;
539 return *this;
540 }
541
543 constexpr auto operator/=(const named_type& rhs) & noexcept(noexcept(m_value /= rhs.m_value)) -> named_type&
544 requires arithmetic<value_type>
545 {
546 m_value /= rhs.m_value;
547 return *this;
548 }
549
551 constexpr auto operator/=(named_type&& rhs) & noexcept(noexcept(m_value /= rhs.m_value)) -> named_type&
552 requires arithmetic<value_type>
553 {
554 m_value /= rhs.m_value;
555 return *this;
556 }
557
559 constexpr auto operator%=(const named_type& rhs) & noexcept(noexcept(m_value %= rhs.m_value)) -> named_type&
560 requires arithmetic<value_type>
561 {
562 m_value %= rhs.m_value;
563 return *this;
564 }
565
567 constexpr auto operator%=(named_type&& rhs) & noexcept(noexcept(m_value %= rhs.m_value)) -> named_type&
568 requires arithmetic<value_type>
569 {
570 m_value %= rhs.m_value;
571 return *this;
572 }
573
574 //
575 // Bitwise operators
576 //
577
579 constexpr auto operator~() const& noexcept(noexcept(~m_value)) -> named_type
580 requires std::unsigned_integral<value_type>
581 {
582 return named_type{~m_value};
583 }
584
586 constexpr auto operator&(const named_type& rhs) const& noexcept(noexcept(m_value & rhs.m_value)) -> named_type
587 requires std::unsigned_integral<value_type>
588 {
589 return named_type{m_value & rhs.m_value};
590 }
591
593 constexpr auto operator&(named_type&& rhs) const& noexcept(noexcept(m_value & rhs.m_value)) -> named_type
594 requires std::unsigned_integral<value_type>
595 {
596 return named_type{m_value & rhs.m_value};
597 }
598
600 constexpr auto operator&(const named_type& rhs) && noexcept(noexcept(m_value & rhs.m_value)) -> named_type
601 requires std::unsigned_integral<value_type>
602 {
603 return named_type{m_value & rhs.m_value};
604 }
605
607 constexpr auto operator&(named_type&& rhs) && noexcept(noexcept(m_value & rhs.m_value)) -> named_type
608 requires std::unsigned_integral<value_type>
609 {
610 return named_type{m_value & rhs.m_value};
611 }
612
614 constexpr auto operator|(const named_type& rhs) const& noexcept(noexcept(m_value | rhs.m_value)) -> named_type
615 requires std::unsigned_integral<value_type>
616 {
617 return named_type{m_value | rhs.m_value};
618 }
619
621 constexpr auto operator|(named_type&& rhs) const& noexcept(noexcept(m_value | rhs.m_value)) -> named_type
622 requires std::unsigned_integral<value_type>
623 {
624 return named_type{m_value | rhs.m_value};
625 }
626
628 constexpr auto operator|(const named_type& rhs) && noexcept(noexcept(m_value | rhs.m_value)) -> named_type
629 requires std::unsigned_integral<value_type>
630 {
631 return named_type{m_value | rhs.m_value};
632 }
633
635 constexpr auto operator|(named_type&& rhs) && noexcept(noexcept(m_value | rhs.m_value)) -> named_type
636 requires std::unsigned_integral<value_type>
637 {
638 return named_type{m_value | rhs.m_value};
639 }
640
642 constexpr auto operator^(const named_type& rhs) const& noexcept(noexcept(m_value ^ rhs.m_value)) -> named_type
643 requires std::unsigned_integral<value_type>
644 {
645 return named_type{m_value ^ rhs.m_value};
646 }
647
649 constexpr auto operator^(named_type&& rhs) const& noexcept(noexcept(m_value ^ rhs.m_value)) -> named_type
650 requires std::unsigned_integral<value_type>
651 {
652 return named_type{m_value ^ rhs.m_value};
653 }
654
656 constexpr auto operator^(const named_type& rhs) && noexcept(noexcept(m_value ^ rhs.m_value)) -> named_type
657 requires std::unsigned_integral<value_type>
658 {
659 return named_type{m_value ^ rhs.m_value};
660 }
661
663 constexpr auto operator^(named_type&& rhs) && noexcept(noexcept(m_value ^ rhs.m_value)) -> named_type
664 requires std::unsigned_integral<value_type>
665 {
666 return named_type{m_value ^ rhs.m_value};
667 }
668
670 constexpr auto operator<<(const named_type& rhs) const& noexcept(noexcept(m_value << rhs.m_value)) -> named_type
671 requires std::unsigned_integral<value_type>
672 {
673 return named_type{m_value << rhs.m_value};
674 }
675
677 constexpr auto operator<<(named_type&& rhs) const& noexcept(noexcept(m_value << rhs.m_value)) -> named_type
678 requires std::unsigned_integral<value_type>
679 {
680 return named_type{m_value << rhs.m_value};
681 }
682
684 constexpr auto operator<<(const named_type& rhs) && noexcept(noexcept(m_value << rhs.m_value)) -> named_type
685 requires std::unsigned_integral<value_type>
686 {
687 return named_type{m_value << rhs.m_value};
688 }
689
691 constexpr auto operator<<(named_type&& rhs) && noexcept(noexcept(m_value << rhs.m_value)) -> named_type
692 requires std::unsigned_integral<value_type>
693 {
694 return named_type{m_value << rhs.m_value};
695 }
696
698 constexpr auto operator>>(const named_type& rhs) const& noexcept(noexcept(m_value >> rhs.m_value)) -> named_type
699 requires std::unsigned_integral<value_type>
700 {
701 return named_type{m_value >> rhs.m_value};
702 }
703
705 constexpr auto operator>>(named_type&& rhs) const& noexcept(noexcept(m_value >> rhs.m_value)) -> named_type
706 requires std::unsigned_integral<value_type>
707 {
708 return named_type{m_value >> rhs.m_value};
709 }
710
712 constexpr auto operator>>(const named_type& rhs) && noexcept(noexcept(m_value >> rhs.m_value)) -> named_type
713 requires std::unsigned_integral<value_type>
714 {
715 return named_type{m_value >> rhs.m_value};
716 }
717
719 constexpr auto operator>>(named_type&& rhs) && noexcept(noexcept(m_value >> rhs.m_value)) -> named_type
720 requires std::unsigned_integral<value_type>
721 {
722 return named_type{m_value >> rhs.m_value};
723 }
724
726 constexpr auto operator&=(const named_type& rhs) & noexcept(noexcept(m_value &= rhs.m_value)) -> named_type&
727 requires std::unsigned_integral<value_type>
728 {
729 m_value &= rhs.m_value;
730 return *this;
731 }
732
734 constexpr auto operator&=(named_type&& rhs) & noexcept(noexcept(m_value &= rhs.m_value)) -> named_type&
735 requires std::unsigned_integral<value_type>
736 {
737 m_value &= rhs.m_value;
738 return *this;
739 }
740
742 constexpr auto operator|=(const named_type& rhs) & noexcept(noexcept(m_value |= rhs.m_value)) -> named_type&
743 requires std::unsigned_integral<value_type>
744 {
745 m_value |= rhs.m_value;
746 return *this;
747 }
748
750 constexpr auto operator|=(named_type&& rhs) & noexcept(noexcept(m_value |= rhs.m_value)) -> named_type&
751 requires std::unsigned_integral<value_type>
752 {
753 m_value |= rhs.m_value;
754 return *this;
755 }
756
758 constexpr auto operator^=(const named_type& rhs) & noexcept(noexcept(m_value ^= rhs.m_value)) -> named_type&
759 requires std::unsigned_integral<value_type>
760 {
761 m_value ^= rhs.m_value;
762 return *this;
763 }
764
766 constexpr auto operator^=(named_type&& rhs) & noexcept(noexcept(m_value ^= rhs.m_value)) -> named_type&
767 requires std::unsigned_integral<value_type>
768 {
769 m_value ^= rhs.m_value;
770 return *this;
771 }
772
774 constexpr auto operator<<=(const named_type& rhs) & noexcept(noexcept(m_value <<= rhs.m_value)) -> named_type&
775 requires std::unsigned_integral<value_type>
776 {
777 m_value <<= rhs.m_value;
778 return *this;
779 }
780
782 constexpr auto operator<<=(named_type&& rhs) & noexcept(noexcept(m_value <<= rhs.m_value)) -> named_type&
783 requires std::unsigned_integral<value_type>
784 {
785 m_value <<= rhs.m_value;
786 return *this;
787 }
788
790 constexpr auto operator>>=(const named_type& rhs) & noexcept(noexcept(m_value >>= rhs.m_value)) -> named_type&
791 requires std::unsigned_integral<value_type>
792 {
793 m_value >>= rhs.m_value;
794 return *this;
795 }
796
798 constexpr auto operator>>=(named_type&& rhs) & noexcept(noexcept(m_value >>= rhs.m_value)) -> named_type&
799 requires std::unsigned_integral<value_type>
800 {
801 m_value >>= rhs.m_value;
802 return *this;
803 }
804
805 //
806 // Ranges interface
807 //
808
810 constexpr auto begin() const noexcept(noexcept(std::ranges::begin(m_value)))
811 requires std::ranges::range<value_type>
812 {
813 return std::ranges::begin(m_value);
814 }
815
817 constexpr auto begin() noexcept(noexcept(std::ranges::begin(m_value)))
818 requires std::ranges::range<value_type>
819 {
820 return std::ranges::begin(m_value);
821 }
822
824 constexpr auto end() const noexcept(noexcept(std::ranges::end(m_value)))
825 requires std::ranges::range<value_type>
826 {
827 return std::ranges::end(m_value);
828 }
829
831 constexpr auto end() noexcept(noexcept(std::ranges::end(m_value)))
832 requires std::ranges::range<value_type>
833 {
834 return std::ranges::end(m_value);
835 }
836
837 //
838 // Stream operators
839 //
840
842 friend inline auto operator<<(std::ostream& ostream,
843 const named_type& rhs) noexcept(noexcept(ostream << rhs.m_value)) -> std::ostream&
845 {
846 return ostream << rhs.m_value;
847 }
848
850 friend inline auto operator>>(std::istream& istream,
851 named_type& rhs) noexcept(noexcept(istream >> rhs.m_value)) -> std::istream&
853 {
854 return istream >> rhs.m_value;
855 }
856
857 private:
858 value_type m_value{};
859};
860
862template <basic_inplace_string Name, typename T, typename... Args>
863constexpr auto make_named_type(Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args...>)
864 requires std::constructible_from<std::remove_cvref_t<T>, Args...>
865{
866 return named_type<std::remove_cvref_t<T>, Name>{std::forward<Args>(args)...};
867}
868
870template <basic_inplace_string Name, typename T, typename U, typename... Args>
871constexpr auto make_named_type(std::initializer_list<U> ilist, Args&&... args) noexcept(
872 std::is_nothrow_constructible_v<T, std::initializer_list<U>&, Args...>)
873 requires std::constructible_from<T, std::initializer_list<U>&, Args...>
874{
875 return named_type<std::remove_cvref_t<T>, Name>{ilist, std::forward<Args>(args)...};
876}
877
879template <basic_inplace_string Name, typename T>
880constexpr auto make_named_type(T&& value) noexcept(
881 std::is_nothrow_constructible_v<named_type<std::remove_cvref_t<T>, Name>, T>)
882 requires std::constructible_from<std::remove_cvref_t<T>, T>
883{
884 return named_type<std::remove_cvref_t<T>, Name>{std::forward<T>(value)};
885}
886
887} // namespace gw
888
889namespace std {
890
892template <::gw::hashable T, ::gw::basic_inplace_string Name>
893// NOLINTNEXTLINE(cert-dcl58-cpp)
894struct hash<::gw::named_type<T, Name>> {
896 [[nodiscard]] auto inline operator()(const ::gw::named_type<T, Name>& named_type) const noexcept -> size_t {
897 using value_type = std::remove_cvref_t<T>;
898 using name_type = std::remove_cvref_t<decltype(Name)>;
899 auto value_hash = hash<value_type>{}(named_type.value());
900 auto name_hash = hash<name_type>{}(named_type.name());
901 return value_hash ^ name_hash;
902 }
903};
904
906template <typename T, ::gw::basic_inplace_string Name, class CharT>
907// NOLINTNEXTLINE(cert-dcl58-cpp)
908struct formatter<::gw::named_type<T, Name>, CharT> {
909 bool with_name{};
910
912 template <class ParseContext>
913 constexpr auto parse(ParseContext& context) -> ParseContext::iterator {
914 auto it = context.begin();
915 if (it == context.end()) {
916 return it;
917 }
918
919 if (*it == '#') {
920 with_name = true;
921 ++it;
922 }
923
924 if (it != context.end() && *it != '}') {
925 throw std::format_error("Invalid format args for gw::named_type.");
926 }
927
928 return it;
929 }
930
932 template <class FormatContext>
933 auto format(const ::gw::named_type<T, Name>& named_type, FormatContext& context) const -> FormatContext::iterator
934#if __cplusplus > 202002L
935 requires std::formattable<T, CharT>
936#endif // __cplusplus > 202002L
937 {
938 if (with_name) {
939 return format_to(context.out(), "{}: {}", named_type.name(), named_type.value());
940 }
941
942 return format_to(context.out(), "{}", named_type.value());
943 }
944};
945
946} // namespace std
Named type wrapper.
Definition named_type.hpp:47
constexpr auto operator+() &&noexcept(noexcept(+m_value)) -> named_type
affirms the contained value
Definition named_type.hpp:334
constexpr auto operator&(const named_type &rhs) const &noexcept(noexcept(m_value &rhs.m_value)) -> named_type
performs binary AND on the contained values
Definition named_type.hpp:586
constexpr auto operator&(const named_type &rhs) &&noexcept(noexcept(m_value &rhs.m_value)) -> named_type
performs binary AND on the contained values
Definition named_type.hpp:600
constexpr auto operator^(named_type &&rhs) const &noexcept(noexcept(m_value ^ rhs.m_value)) -> named_type
performs binary XOR on the contained values
Definition named_type.hpp:649
constexpr named_type(Args &&... args) noexcept(std::is_nothrow_constructible_v< value_type, Args... >)
Construct the gw::named_type object.
Definition named_type.hpp:65
constexpr auto operator|(const named_type &rhs) &&noexcept(noexcept(m_value|rhs.m_value)) -> named_type
performs binary OR on the contained values
Definition named_type.hpp:628
constexpr auto value() const &noexcept -> const_reference
Return the contained value.
Definition named_type.hpp:113
constexpr auto operator>>(const named_type &rhs) const &noexcept(noexcept(m_value > > rhs.m_value)) -> named_type
performs binary right shift on the contained values
Definition named_type.hpp:698
T value_type
The type of the contained value.
Definition named_type.hpp:53
constexpr auto value() &noexcept -> reference
Return the contained value.
Definition named_type.hpp:116
constexpr auto operator+() const &noexcept(noexcept(+m_value)) -> named_type
affirms the contained value
Definition named_type.hpp:327
constexpr auto end() noexcept(noexcept(std::ranges::end(m_value)))
returns an iterator to the end of the contained value
Definition named_type.hpp:831
constexpr auto operator>>(const named_type &rhs) &&noexcept(noexcept(m_value > > rhs.m_value)) -> named_type
performs binary right shift on the contained values
Definition named_type.hpp:712
constexpr auto operator-() &&noexcept(noexcept(-m_value)) -> named_type
negates the contained value
Definition named_type.hpp:348
constexpr auto operator++(int) &&noexcept(noexcept(m_value++)) -> named_type
increments the contained value
Definition named_type.hpp:286
value_type & reference
The type of the reference to the contained value.
Definition named_type.hpp:54
const value_type * const_pointer
The type of the const pointer to the contained value.
Definition named_type.hpp:57
constexpr auto operator-(named_type &&rhs) &&noexcept(noexcept(m_value - rhs.m_value)) -> named_type
subtracts the contained values
Definition named_type.hpp:404
constexpr auto operator/(named_type &&rhs) const &noexcept(noexcept(m_value/rhs.m_value)) -> named_type
devides the contained values
Definition named_type.hpp:446
constexpr auto operator*() &&noexcept -> value_type &&
Access the contained value.
Definition named_type.hpp:110
constexpr auto operator>>(named_type &&rhs) &&noexcept(noexcept(m_value > > rhs.m_value)) -> named_type
performs binary right shift on the contained values
Definition named_type.hpp:719
constexpr auto operator--(int) &&noexcept(noexcept(m_value--)) -> named_type
decrements the contained value
Definition named_type.hpp:316
constexpr auto operator^(named_type &&rhs) &&noexcept(noexcept(m_value ^ rhs.m_value)) -> named_type
performs binary XOR on the contained values
Definition named_type.hpp:663
constexpr auto operator+(const named_type &rhs) &&noexcept(noexcept(m_value+rhs.m_value)) -> named_type
adds the contained values
Definition named_type.hpp:369
constexpr auto operator|(const named_type &rhs) const &noexcept(noexcept(m_value|rhs.m_value)) -> named_type
performs binary OR on the contained values
Definition named_type.hpp:614
constexpr auto operator<<(named_type &&rhs) &&noexcept(noexcept(m_value<< rhs.m_value)) -> named_type
performs binary left shift on the contained values
Definition named_type.hpp:691
constexpr auto operator|(named_type &&rhs) &&noexcept(noexcept(m_value|rhs.m_value)) -> named_type
performs binary OR on the contained values
Definition named_type.hpp:635
constexpr auto operator--(int) &noexcept(noexcept(m_value--)) -> named_type
decrements the contained value
Definition named_type.hpp:309
constexpr auto operator++() &&noexcept(noexcept(++m_value)) -> named_type &&
increments the contained value
Definition named_type.hpp:271
constexpr auto operator*() const &&noexcept -> const value_type &&
Access the contained value.
Definition named_type.hpp:107
constexpr auto operator++() &noexcept(noexcept(++m_value)) -> named_type &
increments the contained value
Definition named_type.hpp:263
constexpr auto operator/(const named_type &rhs) const &noexcept(noexcept(m_value/rhs.m_value)) -> named_type
devides the contained values
Definition named_type.hpp:439
constexpr auto operator+(named_type &&rhs) const &noexcept(noexcept(m_value+rhs.m_value)) -> named_type
adds the contained values
Definition named_type.hpp:362
constexpr auto operator*(const named_type &rhs) const &noexcept(noexcept(m_value *rhs.m_value)) -> named_type
multiplies the contained values
Definition named_type.hpp:411
constexpr auto operator&(named_type &&rhs) &&noexcept(noexcept(m_value &rhs.m_value)) -> named_type
performs binary AND on the contained values
Definition named_type.hpp:607
static constexpr auto name() noexcept
Return the name of the gw::named_type.
Definition named_type.hpp:88
constexpr auto operator<<(const named_type &rhs) &&noexcept(noexcept(m_value<< rhs.m_value)) -> named_type
performs binary left shift on the contained values
Definition named_type.hpp:684
constexpr auto operator--() &&noexcept(noexcept(--m_value)) -> named_type &&
decrements the contained value
Definition named_type.hpp:301
constexpr auto operator<(const named_type &rhs) const &noexcept(noexcept(m_value< rhs.m_value)) -> bool
Compare gw::named_type objects.
Definition named_type.hpp:207
constexpr auto operator*() &noexcept -> reference
Access the contained value.
Definition named_type.hpp:104
constexpr auto operator-(const named_type &rhs) &&noexcept(noexcept(m_value - rhs.m_value)) -> named_type
subtracts the contained values
Definition named_type.hpp:397
constexpr auto transform(F &&func) const &noexcept(noexcept(func(m_value))) -> named_type
Return a gw::named_type containing the transformed contained value.
Definition named_type.hpp:130
constexpr auto operator<<(named_type &&rhs) const &noexcept(noexcept(m_value<< rhs.m_value)) -> named_type
performs binary left shift on the contained values
Definition named_type.hpp:677
constexpr auto operator|(named_type &&rhs) const &noexcept(noexcept(m_value|rhs.m_value)) -> named_type
performs binary OR on the contained values
Definition named_type.hpp:621
value_type * pointer
The type of the pointer to the contained value.
Definition named_type.hpp:56
friend auto operator>>(std::istream &istream, named_type &rhs) noexcept(noexcept(istream > > rhs.m_value)) -> std::istream &
extracts formatted data
Definition named_type.hpp:850
constexpr auto operator-(const named_type &rhs) const &noexcept(noexcept(m_value - rhs.m_value)) -> named_type
subtracts the contained values
Definition named_type.hpp:383
constexpr void swap(named_type &rhs) noexcept(std::is_nothrow_swappable_v< value_type >)
Specialize the std::swap algorithm.
Definition named_type.hpp:165
constexpr auto operator/(const named_type &rhs) &&noexcept(noexcept(m_value/rhs.m_value)) -> named_type
devides the contained values
Definition named_type.hpp:453
constexpr auto operator/(named_type &&rhs) &&noexcept(noexcept(m_value/rhs.m_value)) -> named_type
devides the contained values
Definition named_type.hpp:460
constexpr auto operator*() const &noexcept -> const_reference
Access the contained value.
Definition named_type.hpp:101
constexpr auto operator%(const named_type &rhs) &&noexcept(noexcept(m_value % rhs.m_value)) -> named_type
calculates the remainder of the contained values
Definition named_type.hpp:481
constexpr auto operator*(named_type &&rhs) &&noexcept(noexcept(m_value *rhs.m_value)) -> named_type
multiplies the contained values
Definition named_type.hpp:432
constexpr auto end() const noexcept(noexcept(std::ranges::end(m_value)))
returns an iterator to the end of the contained value
Definition named_type.hpp:824
constexpr named_type(std::initializer_list< U > ilist, Args &&... args) noexcept(std::is_nothrow_constructible_v< value_type, std::initializer_list< U > &, Args... >)
Construct the gw::named_type object.
Definition named_type.hpp:71
constexpr auto operator%(const named_type &rhs) const &noexcept(noexcept(m_value % rhs.m_value)) -> named_type
calculates the remainder of the contained values
Definition named_type.hpp:467
constexpr auto operator--() &noexcept(noexcept(--m_value)) -> named_type &
decrements the contained value
Definition named_type.hpp:293
constexpr auto operator%(named_type &&rhs) &&noexcept(noexcept(m_value % rhs.m_value)) -> named_type
calculates the remainder of the contained values
Definition named_type.hpp:488
constexpr auto operator^(const named_type &rhs) &&noexcept(noexcept(m_value ^ rhs.m_value)) -> named_type
performs binary XOR on the contained values
Definition named_type.hpp:656
constexpr auto begin() noexcept(noexcept(std::ranges::begin(m_value)))
returns an iterator to the beginning of the contained value
Definition named_type.hpp:817
constexpr auto operator<<(const named_type &rhs) const &noexcept(noexcept(m_value<< rhs.m_value)) -> named_type
performs binary left shift on the contained values
Definition named_type.hpp:670
~named_type() noexcept(std::is_nothrow_destructible_v< value_type >)=default
Destroy the contained value.
const value_type & const_reference
The type of the const reference to the contained value.
Definition named_type.hpp:55
friend auto operator<<(std::ostream &ostream, const named_type &rhs) noexcept(noexcept(ostream<< rhs.m_value)) -> std::ostream &
inserts formatted data
Definition named_type.hpp:842
constexpr auto value() &&noexcept -> value_type &&
Return the contained value.
Definition named_type.hpp:122
constexpr auto operator->() noexcept -> pointer
Access the contained value.
Definition named_type.hpp:98
constexpr auto operator+(named_type &&rhs) &&noexcept(noexcept(m_value+rhs.m_value)) -> named_type
adds the contained values
Definition named_type.hpp:376
constexpr auto operator>(const named_type &rhs) const &noexcept(noexcept(m_value > rhs.m_value)) -> bool
Compare gw::named_type objects.
Definition named_type.hpp:214
constexpr auto operator%(named_type &&rhs) const &noexcept(noexcept(m_value % rhs.m_value)) -> named_type
calculates the remainder of the contained values
Definition named_type.hpp:474
constexpr void reset() noexcept(std::is_nothrow_default_constructible_v< value_type >)
Destroy any contained value.
Definition named_type.hpp:173
constexpr auto operator+(const named_type &rhs) const &noexcept(noexcept(m_value+rhs.m_value)) -> named_type
adds the contained values
Definition named_type.hpp:355
constexpr auto operator==(const named_type &rhs) const &noexcept(noexcept(m_value==rhs.m_value)) -> bool
Compare gw::named_type objects.
Definition named_type.hpp:193
constexpr auto operator>>(named_type &&rhs) const &noexcept(noexcept(m_value > > rhs.m_value)) -> named_type
performs binary right shift on the contained values
Definition named_type.hpp:705
constexpr auto begin() const noexcept(noexcept(std::ranges::begin(m_value)))
returns an iterator to the beginning of the contained value
Definition named_type.hpp:810
constexpr auto transform(F &&func) const &&noexcept(noexcept(func(m_value))) -> named_type
Return a gw::named_type containing the transformed contained value.
Definition named_type.hpp:146
constexpr auto transform(F &&func) &&noexcept(noexcept(func(m_value))) -> named_type
Return a gw::named_type containing the transformed contained value.
Definition named_type.hpp:154
constexpr auto operator~() const &noexcept(noexcept(~m_value)) -> named_type
inverts the contained value
Definition named_type.hpp:579
constexpr auto operator++(int) &noexcept(noexcept(m_value++)) -> named_type
increments the contained value
Definition named_type.hpp:279
constexpr auto operator->() const noexcept -> const_pointer
Access the contained value.
Definition named_type.hpp:95
constexpr auto operator&(named_type &&rhs) const &noexcept(noexcept(m_value &rhs.m_value)) -> named_type
performs binary AND on the contained values
Definition named_type.hpp:593
constexpr auto operator*(const named_type &rhs) &&noexcept(noexcept(m_value *rhs.m_value)) -> named_type
multiplies the contained values
Definition named_type.hpp:425
constexpr auto operator*(named_type &&rhs) const &noexcept(noexcept(m_value *rhs.m_value)) -> named_type
multiplies the contained values
Definition named_type.hpp:418
constexpr auto value() const &&noexcept -> const value_type &&
Return the contained value.
Definition named_type.hpp:119
constexpr auto operator^(const named_type &rhs) const &noexcept(noexcept(m_value ^ rhs.m_value)) -> named_type
performs binary XOR on the contained values
Definition named_type.hpp:642
constexpr auto emplace(Args &&... args) noexcept(std::is_nothrow_constructible_v< value_type, Args... >) -> reference
Construct the contained value in-place.
Definition named_type.hpp:181
constexpr auto operator-() const &noexcept(noexcept(-m_value)) -> named_type
negates the contained value
Definition named_type.hpp:341
constexpr auto operator-(named_type &&rhs) const &noexcept(noexcept(m_value - rhs.m_value)) -> named_type
subtracts the contained values
Definition named_type.hpp:390
constexpr auto transform(F &&func) &noexcept(noexcept(func(m_value))) -> named_type
Return a gw::named_type containing the transformed contained value.
Definition named_type.hpp:138
Concept for arithmetic types.
Definition concepts.hpp:18
Concept for decrementable types.
Definition concepts.hpp:29
Concept for incrementable types.
Definition concepts.hpp:22
Concept for istreamable types.
Definition concepts.hpp:52
Concept for ostreamable types.
Definition concepts.hpp:46
GW namespace.
Definition concepts.hpp:14
basic_inplace_string(const CharT(&)[N]) -> basic_inplace_string< N - 1U, CharT >
Deduction guide for basic_inplace_string.
constexpr auto make_named_type(Args &&... args) noexcept(std::is_nothrow_constructible_v< T, Args... >)
Create a gw::named_type object.
Definition named_type.hpp:863
STL namespace.