11 #include <initializer_list>
15 #include <string_view>
16 #include <type_traits>
19 #include "gw/concepts.hpp"
26 template <std::
size_t N>
29 constexpr fixed_string(
const char (&str)[N]) { std::copy_n(str, N, value); }
35 struct named_type_empty_base {
36 constexpr
auto operator<=>(
const named_type_empty_base&)
const noexcept =
default;
52 template <
typename T, detail::fixed_
string Name>
54 :
public std::conditional_t<std::ranges::range<T>, std::ranges::view_interface<named_type<T, Name>>,
55 detail::named_type_empty_base> {
69 template <
typename... Args>
70 constexpr
explicit named_type(Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args...>)
71 requires std::constructible_from<T, Args...>
72 : m_value(T{std::forward<Args>(args)...}) {}
75 template <
typename U,
typename... Args>
77 Args&&... args) noexcept(std::is_nothrow_constructible_v<T, std::initializer_list<U>&, Args...>)
78 requires std::constructible_from<T, std::initializer_list<U>&, Args...>
79 : m_value(T{ilist, std::forward<Args>(args)...}) {}
86 ~named_type() noexcept(std::is_nothrow_destructible_v<T>) = default;
93 static constexpr auto
name() noexcept -> std::string_view {
return k_name; }
100 constexpr
auto operator->() const noexcept -> const T* {
return &m_value; }
103 constexpr
auto operator->() noexcept -> T* {
return &m_value; }
106 constexpr
auto operator*() const& noexcept -> const T& {
return m_value; }
109 constexpr
auto operator*() & noexcept -> T& {
return m_value; }
112 constexpr
auto operator*() const&& noexcept -> const T&& {
return std::move(m_value); }
115 constexpr
auto operator*() && noexcept -> T&& {
return std::move(m_value); }
118 constexpr
auto value() const& noexcept -> const T& {
return m_value; }
121 constexpr
auto value() & noexcept -> T& {
return m_value; }
124 constexpr
auto value() const&& noexcept -> const T&& {
return std::move(m_value); }
127 constexpr
auto value() && noexcept -> T&& {
return std::move(m_value); }
134 template <
typename F>
135 constexpr
auto transform(F&& func)
const& noexcept(noexcept(func(m_value)))
136 requires std::invocable<F, const T&>
142 template <
typename F>
143 constexpr
auto transform(F&& func) & noexcept(noexcept(func(m_value)))
144 requires std::invocable<F, T&>
146 return named_type<std::remove_cv_t<std::invoke_result_t<F, T&>>, Name>{func(m_value)};
150 template <
typename F>
151 constexpr
auto transform(F&& func)
const&& noexcept(noexcept(func(m_value)))
152 requires std::invocable<F, const T&&>
154 return named_type<std::remove_cv_t<std::invoke_result_t<F, const T&&>>, Name>{func(std::move(m_value))};
158 template <
typename F>
159 constexpr
auto transform(F&& func) && noexcept(noexcept(func(m_value)))
160 requires std::invocable<F, T&&>
162 return named_type<std::remove_cv_t<std::invoke_result_t<F, T&&>>, Name>{func(std::move(m_value))};
170 constexpr
void swap(
named_type& rhs) noexcept(std::is_nothrow_swappable_v<T>)
171 requires std::swappable<T>
174 swap(m_value, rhs.m_value);
178 constexpr
void reset() noexcept(std::is_nothrow_default_constructible_v<T>)
179 requires std::default_initializable<T>
185 template <
typename... Args>
186 constexpr
auto emplace(Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args...>) -> T&
187 requires std::constructible_from<T, Args...>
189 m_value = T{std::forward<Args>(args)...};
198 constexpr
auto operator==(
const named_type& rhs)
const& noexcept(noexcept(m_value == rhs.m_value)) ->
bool
199 requires std::equality_comparable<T>
201 return m_value == rhs.m_value;
205 constexpr
auto operator!=(
const named_type& rhs)
const& noexcept(noexcept(m_value != rhs.m_value)) ->
bool
206 requires std::equality_comparable<T>
208 return m_value != rhs.m_value;
212 constexpr
auto operator<(
const named_type& rhs)
const& noexcept(noexcept(m_value < rhs.m_value)) ->
bool
213 requires std::totally_ordered<T>
215 return m_value < rhs.m_value;
219 constexpr
auto operator>(
const named_type& rhs)
const& noexcept(noexcept(m_value > rhs.m_value)) ->
bool
220 requires std::totally_ordered<T>
222 return m_value > rhs.m_value;
226 constexpr
auto operator<=(
const named_type& rhs)
const& noexcept(noexcept(m_value <= rhs.m_value)) ->
bool
227 requires std::totally_ordered<T>
229 return m_value <= rhs.m_value;
233 constexpr
auto operator>=(
const named_type& rhs)
const& noexcept(noexcept(m_value >= rhs.m_value)) ->
bool
234 requires std::totally_ordered<T>
236 return m_value >= rhs.m_value;
240 constexpr
auto operator<=>(
const named_type& rhs)
const& noexcept(noexcept(m_value <=>
241 rhs.m_value)) -> std::strong_ordering
242 requires std::three_way_comparable<T>
244 return m_value <=> rhs.m_value;
252 constexpr
explicit operator const T&()
const& noexcept {
return m_value; }
255 constexpr
explicit operator T&() & noexcept {
return m_value; }
258 constexpr
explicit operator const T&&()
const&& noexcept {
return std::move(m_value); }
261 constexpr
explicit operator T&&() && noexcept {
return std::move(m_value); }
268 constexpr
auto operator++() & noexcept(noexcept(++m_value)) ->
named_type&
269 requires incrementable<T>
276 constexpr
auto operator++() && noexcept(noexcept(++m_value)) ->
named_type&&
277 requires incrementable<T>
280 return std::move(*
this);
284 constexpr
auto operator++(
int) & noexcept(noexcept(m_value++)) ->
named_type
285 requires incrementable<T>
291 constexpr
auto operator++(
int) && noexcept(noexcept(m_value++)) ->
named_type
292 requires incrementable<T>
298 constexpr
auto operator--() & noexcept(noexcept(--m_value)) ->
named_type&
299 requires decrementable<T>
306 constexpr
auto operator--() && noexcept(noexcept(--m_value)) ->
named_type&&
307 requires decrementable<T>
310 return std::move(*
this);
314 constexpr
auto operator--(
int) & noexcept(noexcept(m_value--)) ->
named_type
315 requires decrementable<T>
321 constexpr
auto operator--(
int) && noexcept(noexcept(m_value--)) ->
named_type
322 requires decrementable<T>
332 constexpr
auto operator+() const& noexcept(noexcept(+m_value)) ->
named_type
333 requires std::signed_integral<T>
339 constexpr
auto operator+() && noexcept(noexcept(+m_value)) ->
named_type
340 requires std::signed_integral<T>
346 constexpr
auto operator-() const& noexcept(noexcept(-m_value)) ->
named_type
347 requires std::signed_integral<T>
353 constexpr
auto operator-() && noexcept(noexcept(-m_value)) ->
named_type
354 requires std::signed_integral<T>
360 constexpr
auto operator+(
const named_type& rhs)
const& noexcept(noexcept(m_value + rhs.m_value)) ->
named_type
361 requires arithmetic<T>
367 constexpr
auto operator+(
named_type&& rhs)
const& noexcept(noexcept(m_value + rhs.m_value)) ->
named_type
368 requires arithmetic<T>
374 constexpr
auto operator+(
const named_type& rhs) && noexcept(noexcept(m_value + rhs.m_value)) ->
named_type
375 requires arithmetic<T>
381 constexpr
auto operator+(
named_type&& rhs) && noexcept(noexcept(m_value + rhs.m_value)) ->
named_type
382 requires arithmetic<T>
388 constexpr
auto operator-(
const named_type& rhs)
const& noexcept(noexcept(m_value - rhs.m_value)) ->
named_type
389 requires arithmetic<T>
395 constexpr
auto operator-(
named_type&& rhs)
const& noexcept(noexcept(m_value - rhs.m_value)) ->
named_type
396 requires arithmetic<T>
402 constexpr
auto operator-(
const named_type& rhs) && noexcept(noexcept(m_value - rhs.m_value)) ->
named_type
403 requires arithmetic<T>
409 constexpr
auto operator-(
named_type&& rhs) && noexcept(noexcept(m_value - rhs.m_value)) ->
named_type
410 requires arithmetic<T>
417 requires arithmetic<T>
424 requires arithmetic<T>
431 requires arithmetic<T>
438 requires arithmetic<T>
444 constexpr
auto operator/(
const named_type& rhs)
const& noexcept(noexcept(m_value / rhs.m_value)) ->
named_type
445 requires arithmetic<T>
451 constexpr
auto operator/(
named_type&& rhs)
const& noexcept(noexcept(m_value / rhs.m_value)) ->
named_type
452 requires arithmetic<T>
458 constexpr
auto operator/(
const named_type& rhs) && noexcept(noexcept(m_value / rhs.m_value)) ->
named_type
459 requires arithmetic<T>
465 constexpr
auto operator/(
named_type&& rhs) && noexcept(noexcept(m_value / rhs.m_value)) ->
named_type
466 requires arithmetic<T>
472 constexpr
auto operator%(
const named_type& rhs)
const& noexcept(noexcept(m_value % rhs.m_value)) ->
named_type
473 requires arithmetic<T>
479 constexpr
auto operator%(
named_type&& rhs)
const& noexcept(noexcept(m_value % rhs.m_value)) ->
named_type
480 requires arithmetic<T>
486 constexpr
auto operator%(
const named_type& rhs) && noexcept(noexcept(m_value % rhs.m_value)) ->
named_type
487 requires arithmetic<T>
493 constexpr
auto operator%(
named_type&& rhs) && noexcept(noexcept(m_value % rhs.m_value)) ->
named_type
494 requires arithmetic<T>
500 constexpr
auto operator+=(
const named_type& rhs) & noexcept(noexcept(m_value += rhs.m_value)) ->
named_type&
501 requires arithmetic<T>
503 m_value += rhs.m_value;
508 constexpr
auto operator+=(
named_type&& rhs) & noexcept(noexcept(m_value += rhs.m_value)) ->
named_type&
509 requires arithmetic<T>
511 m_value += rhs.m_value;
516 constexpr
auto operator-=(
const named_type& rhs) & noexcept(noexcept(m_value -= rhs.m_value)) ->
named_type&
517 requires arithmetic<T>
519 m_value -= rhs.m_value;
524 constexpr
auto operator-=(
named_type&& rhs) & noexcept(noexcept(m_value -= rhs.m_value)) ->
named_type&
525 requires arithmetic<T>
527 m_value -= rhs.m_value;
532 constexpr
auto operator*=(
const named_type& rhs) & noexcept(noexcept(m_value *= rhs.m_value)) ->
named_type&
533 requires arithmetic<T>
535 m_value *= rhs.m_value;
540 constexpr
auto operator*=(
named_type&& rhs) & noexcept(noexcept(m_value *= rhs.m_value)) ->
named_type&
541 requires arithmetic<T>
543 m_value *= rhs.m_value;
548 constexpr
auto operator/=(
const named_type& rhs) & noexcept(noexcept(m_value /= rhs.m_value)) ->
named_type&
549 requires arithmetic<T>
551 m_value /= rhs.m_value;
556 constexpr
auto operator/=(
named_type&& rhs) & noexcept(noexcept(m_value /= rhs.m_value)) ->
named_type&
557 requires arithmetic<T>
559 m_value /= rhs.m_value;
564 constexpr
auto operator%=(
const named_type& rhs) & noexcept(noexcept(m_value %= rhs.m_value)) ->
named_type&
565 requires arithmetic<T>
567 m_value %= rhs.m_value;
572 constexpr
auto operator%=(
named_type&& rhs) & noexcept(noexcept(m_value %= rhs.m_value)) ->
named_type&
573 requires arithmetic<T>
575 m_value %= rhs.m_value;
584 constexpr
auto operator~() const& noexcept(noexcept(~m_value)) ->
named_type
585 requires std::unsigned_integral<T>
591 constexpr
auto operator&(
const named_type& rhs)
const& noexcept(noexcept(m_value & rhs.m_value)) ->
named_type
592 requires std::unsigned_integral<T>
598 constexpr
auto operator&(
named_type&& rhs)
const& noexcept(noexcept(m_value & rhs.m_value)) ->
named_type
599 requires std::unsigned_integral<T>
605 constexpr
auto operator&(
const named_type& rhs) && noexcept(noexcept(m_value & rhs.m_value)) ->
named_type
606 requires std::unsigned_integral<T>
612 constexpr
auto operator&(
named_type&& rhs) && noexcept(noexcept(m_value & rhs.m_value)) ->
named_type
613 requires std::unsigned_integral<T>
619 constexpr
auto operator|(
const named_type& rhs)
const& noexcept(noexcept(m_value | rhs.m_value)) ->
named_type
620 requires std::unsigned_integral<T>
626 constexpr
auto operator|(
named_type&& rhs)
const& noexcept(noexcept(m_value | rhs.m_value)) ->
named_type
627 requires std::unsigned_integral<T>
633 constexpr
auto operator|(
const named_type& rhs) && noexcept(noexcept(m_value | rhs.m_value)) ->
named_type
634 requires std::unsigned_integral<T>
640 constexpr
auto operator|(
named_type&& rhs) && noexcept(noexcept(m_value | rhs.m_value)) ->
named_type
641 requires std::unsigned_integral<T>
647 constexpr
auto operator^(
const named_type& rhs)
const& noexcept(noexcept(m_value ^ rhs.m_value)) ->
named_type
648 requires std::unsigned_integral<T>
654 constexpr
auto operator^(
named_type&& rhs)
const& noexcept(noexcept(m_value ^ rhs.m_value)) ->
named_type
655 requires std::unsigned_integral<T>
661 constexpr
auto operator^(
const named_type& rhs) && noexcept(noexcept(m_value ^ rhs.m_value)) ->
named_type
662 requires std::unsigned_integral<T>
668 constexpr
auto operator^(
named_type&& rhs) && noexcept(noexcept(m_value ^ rhs.m_value)) ->
named_type
669 requires std::unsigned_integral<T>
675 constexpr
auto operator<<(
const named_type& rhs)
const& noexcept(noexcept(m_value << rhs.m_value)) ->
named_type
676 requires std::unsigned_integral<T>
682 constexpr
auto operator<<(
named_type&& rhs)
const& noexcept(noexcept(m_value << rhs.m_value)) ->
named_type
683 requires std::unsigned_integral<T>
689 constexpr
auto operator<<(
const named_type& rhs) && noexcept(noexcept(m_value << rhs.m_value)) ->
named_type
690 requires std::unsigned_integral<T>
696 constexpr
auto operator<<(
named_type&& rhs) && noexcept(noexcept(m_value << rhs.m_value)) ->
named_type
697 requires std::unsigned_integral<T>
703 constexpr
auto operator>>(
const named_type& rhs)
const& noexcept(noexcept(m_value >> rhs.m_value)) ->
named_type
704 requires std::unsigned_integral<T>
710 constexpr
auto operator>>(
named_type&& rhs)
const& noexcept(noexcept(m_value >> rhs.m_value)) ->
named_type
711 requires std::unsigned_integral<T>
717 constexpr
auto operator>>(
const named_type& rhs) && noexcept(noexcept(m_value >> rhs.m_value)) ->
named_type
718 requires std::unsigned_integral<T>
724 constexpr
auto operator>>(
named_type&& rhs) && noexcept(noexcept(m_value >> rhs.m_value)) ->
named_type
725 requires std::unsigned_integral<T>
731 constexpr
auto operator&=(
const named_type& rhs) & noexcept(noexcept(m_value &= rhs.m_value)) ->
named_type&
732 requires std::unsigned_integral<T>
734 m_value &= rhs.m_value;
739 constexpr
auto operator&=(
named_type&& rhs) & noexcept(noexcept(m_value &= rhs.m_value)) ->
named_type&
740 requires std::unsigned_integral<T>
742 m_value &= rhs.m_value;
747 constexpr
auto operator|=(
const named_type& rhs) & noexcept(noexcept(m_value |= rhs.m_value)) ->
named_type&
748 requires std::unsigned_integral<T>
750 m_value |= rhs.m_value;
755 constexpr
auto operator|=(
named_type&& rhs) & noexcept(noexcept(m_value |= rhs.m_value)) ->
named_type&
756 requires std::unsigned_integral<T>
758 m_value |= rhs.m_value;
763 constexpr
auto operator^=(
const named_type& rhs) & noexcept(noexcept(m_value ^= rhs.m_value)) ->
named_type&
764 requires std::unsigned_integral<T>
766 m_value ^= rhs.m_value;
771 constexpr
auto operator^=(
named_type&& rhs) & noexcept(noexcept(m_value ^= rhs.m_value)) ->
named_type&
772 requires std::unsigned_integral<T>
774 m_value ^= rhs.m_value;
779 constexpr
auto operator<<=(
const named_type& rhs) & noexcept(noexcept(m_value <<= rhs.m_value)) ->
named_type&
780 requires std::unsigned_integral<T>
782 m_value <<= rhs.m_value;
787 constexpr
auto operator<<=(
named_type&& rhs) & noexcept(noexcept(m_value <<= rhs.m_value)) ->
named_type&
788 requires std::unsigned_integral<T>
790 m_value <<= rhs.m_value;
795 constexpr
auto operator>>=(
const named_type& rhs) & noexcept(noexcept(m_value >>= rhs.m_value)) ->
named_type&
796 requires std::unsigned_integral<T>
798 m_value >>= rhs.m_value;
803 constexpr
auto operator>>=(
named_type&& rhs) & noexcept(noexcept(m_value >>= rhs.m_value)) ->
named_type&
804 requires std::unsigned_integral<T>
806 m_value >>= rhs.m_value;
815 constexpr
auto begin() const noexcept(noexcept(std::ranges::begin(m_value)))
816 requires std::ranges::range<T>
818 return std::ranges::begin(m_value);
822 constexpr
auto begin() noexcept(noexcept(std::ranges::begin(m_value)))
823 requires std::ranges::range<T>
825 return std::ranges::begin(m_value);
829 constexpr
auto end() const noexcept(noexcept(std::ranges::end(m_value)))
830 requires std::ranges::range<T>
832 return std::ranges::end(m_value);
836 constexpr
auto end() noexcept(noexcept(std::ranges::end(m_value)))
837 requires std::ranges::range<T>
839 return std::ranges::end(m_value);
847 friend inline auto operator<<(std::ostream& ostream,
848 const named_type& rhs) noexcept(noexcept(ostream << rhs.m_value)) -> std::ostream&
849 requires ostreamable<T>
851 return ostream << rhs.m_value;
855 friend inline auto operator>>(std::istream& istream,
856 named_type& rhs) noexcept(noexcept(istream >> rhs.m_value)) -> std::istream&
857 requires istreamable<T>
859 return istream >> rhs.m_value;
864 static constexpr
auto k_name = Name.value;
872 template <detail::fixed_string Name,
typename T,
typename... Args>
873 constexpr
auto make_named_type(Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args...>)
874 requires std::constructible_from<std::remove_cvref_t<T>, Args...>
880 template <detail::fixed_string Name,
typename T,
typename U,
typename... Args>
881 constexpr
auto make_named_type(std::initializer_list<U> ilist, Args&&... args) noexcept(
882 std::is_nothrow_constructible_v<T, std::initializer_list<U>&, Args...>)
883 requires std::constructible_from<T, std::initializer_list<U>&, Args...>
885 return named_type<std::remove_cvref_t<T>, Name>{ilist, std::forward<Args>(args)...};
889 template <detail::fixed_
string Name,
typename T>
890 constexpr
auto make_named_type(T&& value) noexcept(
891 std::is_nothrow_constructible_v<named_type<std::remove_cvref_t<T>, Name>, T>)
892 requires std::constructible_from<std::remove_cvref_t<T>, T>
894 return named_type<std::remove_cvref_t<T>, Name>{std::forward<T>(value)};
906 template <::gw::hashable T, ::gw::detail::fixed_
string Name>
909 [[nodiscard]]
auto inline operator()(const ::gw::named_type<T, Name>& named_type)
const noexcept ->
size_t {
910 auto value_hash = hash<T>{}(named_type.value());
911 auto name_hash = hash<string_view>{}(named_type.name());
912 return value_hash ^ name_hash;
921 template <::gw::
string_convertable T, ::gw::detail::fixed_
string Name>
923 [[nodiscard]]
auto inline to_string(const ::gw::named_type<T, Name>& named_type) ->
string {
924 return string{named_type.name()} +
": " + to_string(named_type.value());
Named type wrapper.
Definition: named_type.hpp:55
constexpr auto operator*() const &noexcept -> const T &
accesses the contained value
Definition: named_type.hpp:106
T value_type
the type of the contained value
Definition: named_type.hpp:62
constexpr auto operator->() noexcept -> T *
accesses the contained value
Definition: named_type.hpp:103
constexpr auto static constexpr transform(F &&func) const &noexcept(noexcept(func(m_value))) requires std auto k_name
returns a gw::named_type containing the transformed contained value
Definition: named_type.hpp:864
constexpr auto operator*() const &&noexcept -> const T &&
accesses the contained value
Definition: named_type.hpp:112
constexpr auto operator*() &noexcept -> T &
accesses the contained value
Definition: named_type.hpp:109
~named_type() noexcept(std::is_nothrow_destructible_v< T >)=default
destroys the contained value
constexpr auto operator*() &&noexcept -> T &&
accesses the contained value
Definition: named_type.hpp:115
constexpr named_type(std::initializer_list< U > ilist, Args &&... args) noexcept(std::is_nothrow_constructible_v< T, std::initializer_list< U > &, Args... >) requires std
constructs the gw::named_type object
Definition: named_type.hpp:76
constexpr auto value() &noexcept -> T &
returns the contained value
Definition: named_type.hpp:121
constexpr auto value() const &noexcept -> const T &
returns the contained value
Definition: named_type.hpp:118
constexpr auto value() const &&noexcept -> const T &&
returns the contained value
Definition: named_type.hpp:124
static constexpr auto name() noexcept -> std::string_view
returns the name of the gw::named_type
Definition: named_type.hpp:93
constexpr auto value() &&noexcept -> T &&
returns the contained value
Definition: named_type.hpp:127
constexpr named_type(Args &&... args) noexcept(std::is_nothrow_constructible_v< T, Args... >) requires std
constructs the gw::named_type object
Definition: named_type.hpp:70
constexpr auto operator->() const noexcept -> const T *
accesses the contained value
Definition: named_type.hpp:100
GW namespace.
Definition: concepts.hpp:14