summaryrefslogtreecommitdiffhomepage
path: root/entity/constraints.hpp
blob: 6a5587d57a4f9f59b881d3e49e27557dc4e09607 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#pragma once
#include "compat/limits.hpp"
#include "erased-constraints.hpp"
#include <type_traits>
#include <utility>
#include <mg/Vector.h>

namespace floormat::entities::limit_detail {

template<typename T> struct limit_traits;

template<typename T>
requires Math::IsVector<T>::value
struct limit_traits<T>
{
    static constexpr auto min() { return T(limits<typename T::Type>::min); }
    static constexpr auto max() { return T(limits<typename T::Type>::max); }
};

template<typename T>
requires std::is_arithmetic_v<T>
struct limit_traits<T>
{
    static constexpr auto min() { return limits<T>::min; }
    static constexpr auto max() { return limits<T>::max; }
};

template<typename T>
requires std::is_enum_v<T>
struct limit_traits<T>
{
    static constexpr T min() { return T(limits<std::underlying_type_t<T>>::min); }
    static constexpr T max() { return T(limits<std::underlying_type_t<T>>::max); }
};

template<typename T>
struct limit_traits
{
    static_assert(std::is_nothrow_default_constructible_v<T>);
    static constexpr T min() { return T{}; }
    static constexpr T max() { return T{}; }
};

} // namespace floormat::entities::limit_detail


namespace floormat::entities::constraints {

template<typename T> struct range
{
    T min = limit_detail::limit_traits<T>::min();
    T max = limit_detail::limit_traits<T>::max();

    constexpr operator erased_constraints::range() const noexcept;
    constexpr operator std::pair<T, T>() const noexcept;
    constexpr bool operator==(const range&) const noexcept = default;
};

template<typename T> range(T min, T max) -> range<T>;

template<typename T>
requires (std::is_floating_point_v<T>)
constexpr erased_constraints::range erased_range_from_range(T min, T max)
{ return { { .f = min }, { .f = max }, erased_constraints::range::type_::type_float }; }

template<typename T>
requires (std::is_integral_v<T> && std::is_unsigned_v<T>)
constexpr erased_constraints::range erased_range_from_range(T min, T max)
{ return { { .u = min }, { .u = max }, erased_constraints::range::type_::type_uint }; }

template<typename T>
requires (std::is_integral_v<T> && std::is_signed_v<T>)
constexpr erased_constraints::range erased_range_from_range(T min, T max)
{ return { { .i = min }, { .i = max }, erased_constraints::range::type_::type_int }; }

template<size_t N, typename T>
requires (std::is_integral_v<T> || std::is_floating_point_v<T>)
constexpr erased_constraints::range erased_range_from_range(const Math::Vector<N, T>& min0,
                                                            const Math::Vector<N, T>& max0)
{
    static_assert(N <= 4);
    static_assert(sizeof T{} <= sizeof 0uz);
    using type = erased_constraints::range::type_;

    using Element = std::conditional_t<std::is_floating_point_v<T>, float,
                                       std::conditional_t<std::is_unsigned_v<T>, size_t,
                                                          std::make_signed_t<size_t>>>;

    Math::Vector4<Element> min{limits<Element>::min}, max{limits<Element>::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<T>)
    {
        static_assert(std::is_same_v<T, float>);
        return { .min = {.f4 = min}, .max = {.f4 = max}, .type = type::type_float4 };
    }
    else if constexpr(std::is_unsigned_v<T>)
    {
        static_assert(sizeof T{} <= sizeof 0uz);
        return { .min = {.u4 = min}, .max = {.u4 = max}, .type = type::type_uint4 };
    }
    else if constexpr(std::is_signed_v<T>)
    {
        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<typename T>
requires (std::is_enum_v<T>)
constexpr erased_constraints::range erased_range_from_range(T min, T max)
{ return erased_range_from_range(std::underlying_type_t<T>(min), std::underlying_type_t<T>(max)); }

template<typename T>
constexpr range<T>::operator erased_constraints::range() const noexcept
{ return erased_range_from_range(min, max); }

template<typename T> constexpr range<T>::operator std::pair<T, T>() const noexcept { return { min, max }; }

template<> struct range<String> { constexpr operator erased_constraints::range() const noexcept { return {}; } };
template<> struct range<StringView> { constexpr operator erased_constraints::range() const noexcept { return {}; } };

using max_length = erased_constraints::max_length;

} // namespace floormat::entities::constraints