|
10 | 10 | #include <limits> |
11 | 11 | #include <type_traits> |
12 | 12 |
|
| 13 | +namespace detail { |
| 14 | + |
| 15 | +template<class T> |
| 16 | +struct type_identity |
| 17 | +{ |
| 18 | + using type = T; |
| 19 | +}; |
| 20 | + |
| 21 | +/// Convert the type T to a signed type if the condition is true (safe for float types) |
| 22 | +template<bool cond, typename T> |
| 23 | +using make_signed_if_t = |
| 24 | + typename std::conditional_t<cond && !std::is_signed<T>::value, std::make_signed<T>, type_identity<T>>::type; |
| 25 | + |
| 26 | +// clang-format off |
| 27 | + |
| 28 | +/// Creates a mixed type out of types T and U which is |
| 29 | +/// the larger type of T & U AND signed iff either is signed |
| 30 | +/// Will be a floating point type if either T or U is floating point |
| 31 | +template<typename T, typename U> |
| 32 | +using mixed_type_t = |
| 33 | + make_signed_if_t< |
| 34 | + std::is_signed<T>::value || std::is_signed<U>::value, |
| 35 | + typename std::conditional_t< |
| 36 | + std::is_floating_point<T>::value == std::is_floating_point<U>::value, // both are FP or not FP? |
| 37 | + std::conditional<(sizeof(T) > sizeof(U)), T, U>, // Take the larger type |
| 38 | + std::conditional<std::is_floating_point<T>::value, T, U> // Take the floating point type |
| 39 | + >::type |
| 40 | + >; |
| 41 | + |
| 42 | +template<typename T, typename U> |
| 43 | +using IsNonLossyOp = std::integral_constant<bool, |
| 44 | + // We can do T = T <op> U (except overflow) if: |
| 45 | + std::is_floating_point<T>::value || std::is_signed<T>::value || std::is_unsigned<U>::value |
| 46 | +>; |
| 47 | + |
| 48 | +// clang-format on |
| 49 | + |
| 50 | +template<typename T, typename U> |
| 51 | +using require_nonLossyOp = std::enable_if_t<IsNonLossyOp<T, U>::value>; |
| 52 | +template<typename T> |
| 53 | +using require_arithmetic = std::enable_if_t<std::is_arithmetic<T>::value>; |
| 54 | + |
| 55 | +} // namespace detail |
| 56 | + |
13 | 57 | /// Type for describing a 2D value (position, size, offset...) |
14 | 58 | /// Note: Combining a signed with an unsigned point will result in a signed type! |
15 | 59 | /// Allowed operations: |
@@ -88,50 +132,6 @@ constexpr bool Point<T>::operator!=(const Point<T>& second) const noexcept |
88 | 132 | return !(*this == second); |
89 | 133 | } |
90 | 134 |
|
91 | | -namespace detail { |
92 | | - |
93 | | -template<class T> |
94 | | -struct type_identity |
95 | | -{ |
96 | | - using type = T; |
97 | | -}; |
98 | | - |
99 | | -/// Convert the type T to a signed type if the condition is true (safe for float types) |
100 | | -template<bool cond, typename T> |
101 | | -using make_signed_if_t = |
102 | | - typename std::conditional_t<cond && !std::is_signed<T>::value, std::make_signed<T>, type_identity<T>>::type; |
103 | | - |
104 | | -// clang-format off |
105 | | - |
106 | | -/// Creates a mixed type out of types T and U which is |
107 | | -/// the larger type of T & U AND signed iff either is signed |
108 | | -/// Will be a floating point type if either T or U is floating point |
109 | | -template<typename T, typename U> |
110 | | -using mixed_type_t = |
111 | | - make_signed_if_t< |
112 | | - std::is_signed<T>::value || std::is_signed<U>::value, |
113 | | - typename std::conditional_t< |
114 | | - std::is_floating_point<T>::value == std::is_floating_point<U>::value, // both are FP or not FP? |
115 | | - std::conditional<(sizeof(T) > sizeof(U)), T, U>, // Take the larger type |
116 | | - std::conditional<std::is_floating_point<T>::value, T, U> // Take the floating point type |
117 | | - >::type |
118 | | - >; |
119 | | - |
120 | | -template<typename T, typename U> |
121 | | -using IsNonLossyOp = std::integral_constant<bool, |
122 | | - // We can do T = T <op> U (except overflow) if: |
123 | | - std::is_floating_point<T>::value || std::is_signed<T>::value || std::is_unsigned<U>::value |
124 | | ->; |
125 | | - |
126 | | -// clang-format on |
127 | | - |
128 | | -template<typename T, typename U> |
129 | | -using require_nonLossyOp = std::enable_if_t<IsNonLossyOp<T, U>::value>; |
130 | | -template<typename T> |
131 | | -using require_arithmetic = std::enable_if_t<std::is_arithmetic<T>::value>; |
132 | | - |
133 | | -} // namespace detail |
134 | | - |
135 | 135 | /// Compute the element wise minimum |
136 | 136 | template<typename T> |
137 | 137 | constexpr Point<T> elMin(const Point<T>& lhs, const Point<T>& rhs) noexcept |
|
0 commit comments