#pragma once #include "compat/limits.hpp" #include "erased-constraints.hpp" #include #include #include namespace floormat::entities::limit_detail { template struct limit_traits; template requires Math::IsVector::value struct limit_traits { static constexpr auto min() { return T(limits::min); } static constexpr auto max() { return T(limits::max); } }; template requires std::is_arithmetic_v struct limit_traits { static constexpr auto min() { return limits::min; } static constexpr auto max() { return limits::max; } }; template requires std::is_enum_v struct limit_traits { static constexpr T min() { return T(limits>::min); } static constexpr T max() { return T(limits>::max); } }; template struct limit_traits { static_assert(std::is_nothrow_default_constructible_v); static constexpr T min() { return T{}; } static constexpr T max() { return T{}; } }; } // namespace floormat::entities::limit_detail namespace floormat::entities::constraints { template struct range { T min = limit_detail::limit_traits::min(); T max = limit_detail::limit_traits::max(); constexpr operator erased_constraints::range() const noexcept; constexpr operator std::pair() const noexcept; constexpr bool operator==(const range&) const noexcept = default; }; template range(T min, T max) -> range; template requires (std::is_floating_point_v) constexpr erased_constraints::range erased_range_from_range(T min, T max) { return { { .f = min }, { .f = max }, erased_constraints::range::type_::type_float }; } template requires (std::is_integral_v && std::is_unsigned_v) constexpr erased_constraints::range erased_range_from_range(T min, T max) { return { { .u = min }, { .u = max }, erased_constraints::range::type_::type_uint }; } template requires (std::is_integral_v && std::is_signed_v) constexpr erased_constraints::range erased_range_from_range(T min, T max) { return { { .i = min }, { .i = max }, erased_constraints::range::type_::type_int }; } template requires (std::is_integral_v || std::is_floating_point_v) constexpr erased_constraints::range erased_range_from_range(const Math::Vector& min0, const Math::Vector& max0) { static_assert(N <= 4); static_assert(sizeof T{} <= sizeof 0uz); using type = erased_constraints::range::type_; using Element = std::conditional_t, float, std::conditional_t, size_t, std::make_signed_t>>; Math::Vector4 min{limits::min}, max{limits::max}; for (auto i = 0u; i < N; i++) { min[i] = Element(min0[i]); max[i] = Element(max0[i]); } if constexpr(std::is_floating_point_v) { static_assert(std::is_same_v); return { .min = {.f4 = min}, .max = {.f4 = max}, .type = type::type_float4 }; } else if constexpr(std::is_unsigned_v) { static_assert(sizeof T{} <= sizeof 0uz); return { .min = {.u4 = min}, .max = {.u4 = max}, .type = type::type_uint4 }; } else if constexpr(std::is_signed_v) { static_assert(sizeof T{} <= sizeof 0uz); return { .min = {.i4 = min}, .max = {.i4 = max}, .type = type::type_int4 }; } else { static_assert(sizeof T{} == (size_t)-1); static_assert(sizeof T{} != (size_t)-1); return {}; } } template requires (std::is_enum_v) constexpr erased_constraints::range erased_range_from_range(T min, T max) { return erased_range_from_range(std::underlying_type_t(min), std::underlying_type_t(max)); } template constexpr range::operator erased_constraints::range() const noexcept { return erased_range_from_range(min, max); } template constexpr range::operator std::pair() const noexcept { return { min, max }; } template<> struct range { constexpr operator erased_constraints::range() const noexcept { return {}; } }; template<> struct range { constexpr operator erased_constraints::range() const noexcept { return {}; } }; using max_length = erased_constraints::max_length; } // namespace floormat::entities::constraints