#pragma once #include <compare> #include <concepts> #include <type_traits> namespace util { template <typename T> concept Number = std::integral<T> || std::floating_point<T>; template <auto T, auto U> requires std::equality_comparable_with<decltype(T), decltype(T)> struct is_equal : public std::integral_constant<bool, T == U> { }; template <auto T, auto U> inline constexpr auto is_equal_v = is_equal<T, U>::value; template <auto T, auto U> requires std::three_way_comparable_with<decltype(T), decltype(T)> struct cmp { constexpr static std::partial_ordering ordering = T <=> U; }; template <auto T, auto U> inline constexpr auto cmp_v = cmp<T, U>::ordering; template <std::partial_ordering ordering, auto T, auto U> concept Compare = is_equal_v<cmp_v<T, U>, ordering>; template <auto T, auto U> concept Equal = is_equal_v<T, U>; template <typename T, typename... Pack> concept all_same_as = (std::same_as<T, Pack> && ...); template <typename T, typename U> concept explicit_convertible_to = requires(const T ct, T t, const U &cu) { {t = cu}; { ct.operator U() } -> std::same_as<U>; } || std::same_as<T, U>; template <typename From, typename... To> concept explicit_convertible_to_any_of = (explicit_convertible_to<std::remove_cv_t<From>, To> || ...); template <typename From, typename... To> struct is_explicit_convertible_to_any_of : std::bool_constant<explicit_convertible_to_any_of<From, To...>> {}; template <typename T> concept explicit_convertible_to_integral = std::integral<T> || explicit_convertible_to_any_of < std::remove_cv_t<T>, bool, char, signed char, unsigned char, wchar_t, #ifdef __cpp_char8_t char8_t, #endif // __cpp_char8_t char16_t, char32_t, short, unsigned short, int, unsigned int, long, unsigned long, long long, unsigned long long > ; template <typename T> concept explicit_convertible_to_floating_point = std::floating_point<T> || explicit_convertible_to_any_of<T, float, double, long double>; template <typename From, typename To> struct is_explicit_convertible : std::bool_constant<explicit_convertible_to<From, To>> {}; template <typename From, typename To> inline constexpr bool is_explicit_convertible_v = is_explicit_convertible<From, To>::value; template <typename Fn, typename R, typename... Args> concept with_return_type = requires(Fn fn, Args... args) { { fn(args...) } -> std::same_as<R>; }; } // namespace util