| Flutter Impeller |

saturated_math.h
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef FLUTTER_IMPELLER_GEOMETRY_SATURATED_MATH_H_
6 #define FLUTTER_IMPELLER_GEOMETRY_SATURATED_MATH_H_
7
8 #include <algorithm>
9 #include <limits>
10 #include <type_traits>
11
12 #include "flutter/fml/logging.h"
13 #include "impeller/geometry/scalar.h"
14
15 namespace impeller {
16
17 namespace saturated {
18
19 // NOLINTBEGIN(readability-identifier-naming)
20 template <typename T>
21 inline constexpr bool is_signed_integral_v =
22 std::is_integral_v<T> && std::is_signed_v<T>;
23 // NOLINTEND(readability-identifier-naming)
24
25 #define ONLY_ON_SIGNED_INT_RET(Type, Ret) \
26 template <typename Type> \
27 constexpr inline std::enable_if_t<is_signed_integral_v<Type>, Ret>
28 #define ONLY_ON_SIGNED_INT(Type) ONLY_ON_SIGNED_INT_RET(Type, Type)
29
30 #define ONLY_ON_FLOAT_RET(Type, Ret) \
31 template <typename Type> \
32 constexpr inline std::enable_if_t<std::is_floating_point_v<Type>, Ret>
33 #define ONLY_ON_FLOAT(Type) ONLY_ON_FLOAT_RET(Type, Type)
34
35 #define ONLY_ON_FLOAT_TO_SIGNED_INT_RET(FPType, SIType, Ret) \
36 template <typename FPType, typename SIType> \
37 constexpr inline std::enable_if_t< \
38 std::is_floating_point_v<FPType> && is_signed_integral_v<SIType>, Ret>
39 #define ONLY_ON_FLOAT_TO_SIGNED_INT(FPType, SIType) \
40 ONLY_ON_FLOAT_TO_SIGNED_INT_RET(FPType, SIType, SIType)
41
42 #define ONLY_ON_DIFFERING_FLOAT_RET(FPType1, FPType2, Ret) \
43 template <typename FPType1, typename FPType2> \
44 constexpr inline std::enable_if_t<std::is_floating_point_v<FPType1> && \
45 std::is_floating_point_v<FPType2> && \
46 !std::is_same_v<FPType1, FPType2>, \
47 Ret>
48 #define ONLY_ON_DIFFERING_FLOAT(FPType1, FPType2) \
49 ONLY_ON_DIFFERING_FLOAT_RET(FPType1, FPType2, FPType2)
50
51 #define ONLY_ON_SAME_TYPES_RET(Type1, Type2, Ret) \
52 template <typename Type1, typename Type2> \
53 constexpr inline std::enable_if_t<std::is_same_v<Type1, Type2>, Ret>
54 #define ONLY_ON_SAME_TYPES(Type1, Type2) \
55 ONLY_ON_SAME_TYPES_RET(Type1, Type2, Type2)
56
57 ONLY_ON_SIGNED_INT(SI) Add(SI location, SI distance) {
58 if (location >= 0) {
59 if (distance > std::numeric_limits<SI>::max() - location) {
60 return std::numeric_limits<SI>::max();
61 }
62 } else if (distance < std::numeric_limits<SI>::min() - location) {
63 return std::numeric_limits<SI>::min();
64 }
65 return location + distance;
66 }
67
68 ONLY_ON_FLOAT(FP) Add(FP location, FP distance) {
69 return location + distance;
70 }
71
72 ONLY_ON_SIGNED_INT(SI) Sub(SI upper, SI lower) {
73 if (upper >= 0) {
74 if (lower < 0 && upper > std::numeric_limits<SI>::max() + lower) {
75 return std::numeric_limits<SI>::max();
76 }
77 } else if (lower > 0 && upper < std::numeric_limits<SI>::min() + lower) {
78 return std::numeric_limits<SI>::min();
79 }
80 return upper - lower;
81 }
82
83 ONLY_ON_FLOAT(FP) Sub(FP upper, FP lower) {
84 return upper - lower;
85 }
86
87 ONLY_ON_SIGNED_INT_RET(SI, Scalar) AverageScalar(SI a, SI b) {
88 // scalbn has an implementation for ints that converts to double
89 // while adjusting the exponent.
90 return static_cast<Scalar>(std::scalbn(a, -1) + std::scalbn(b, -1));
91 }
92
93 ONLY_ON_FLOAT(FP) AverageScalar(FP a, FP b) {
94 // GetCenter might want this to return 0 for a Maximum Rect, but it
95 // will currently produce NaN instead. For the Maximum Rect itself
96 // a 0 would make sense as the center, but for a computed rect that
97 // incidentally ended up with infinities, NaN may be a better choice.
98 // return static_cast<Scalar>(std::scalbn(a, -1) + std::scalbn(b, -1));
99
100 // This equation would save an extra scalbn operation but at the cost
101 // of having very large (or very neagive) a's and b's overflow to
102 // +/- infinity. Scaling first allows finite numbers to be more likely
103 // to have a finite average.
104 // return std::scalbn(a + b, -1);
105
106 return static_cast<Scalar>(std::scalbn(a, -1) + std::scalbn(b, -1));
107 }
108
109 ONLY_ON_SAME_TYPES(T, U) Cast(T v) {
110 return v;
111 }
112
113 ONLY_ON_FLOAT_TO_SIGNED_INT(FP, SI) Cast(FP v) {
114 if (v <= static_cast<FP>(std::numeric_limits<SI>::min())) {
115 return std::numeric_limits<SI>::min();
116 } else if (v >= static_cast<FP>(std::numeric_limits<SI>::max())) {
117 return std::numeric_limits<SI>::max();
118 }
119 return static_cast<SI>(v);
120 }
121
122 ONLY_ON_DIFFERING_FLOAT(FP1, FP2) Cast(FP1 v) {
123 if (std::isfinite(v)) {
124 // Avoid truncation to inf/-inf.
125 return std::clamp(static_cast<FP2>(v), //
126 std::numeric_limits<FP2>::lowest(),
127 std::numeric_limits<FP2>::max());
128 } else {
129 return static_cast<FP2>(v);
130 }
131 }
132
133 #undef ONLY_ON_SAME_TYPES
134 #undef ONLY_ON_SAME_TYPES_RET
135 #undef ONLY_ON_DIFFERING_FLOAT
136 #undef ONLY_ON_DIFFERING_FLOAT_RET
137 #undef ONLY_ON_FLOAT_TO_SIGNED_INT
138 #undef ONLY_ON_FLOAT_TO_SIGNED_INT_RET
139 #undef ONLY_ON_FLOAT
140 #undef ONLY_ON_FLOAT_RET
141 #undef ONLY_ON_SIGNED_INT
142 #undef ONLY_ON_SIGNED_INT_RET
143
144 } // namespace saturated
145
146 } // namespace impeller
147
148 #endif // FLUTTER_IMPELLER_GEOMETRY_SATURATED_MATH_H_
impeller::saturated::ONLY_ON_SAME_TYPES
ONLY_ON_SAME_TYPES(T, U) Cast(T v)
Definition: saturated_math.h:109
impeller::saturated::ONLY_ON_SIGNED_INT
ONLY_ON_SIGNED_INT(SI) Add(SI location
impeller::saturated::lower
SI lower
Definition: saturated_math.h:72
impeller::saturated::ONLY_ON_DIFFERING_FLOAT
ONLY_ON_DIFFERING_FLOAT(FP1, FP2) Cast(FP1 v)
Definition: saturated_math.h:122
impeller::saturated::b
SI b
Definition: saturated_math.h:87
impeller::saturated::ONLY_ON_FLOAT_TO_SIGNED_INT
ONLY_ON_FLOAT_TO_SIGNED_INT(FP, SI) Cast(FP v)
Definition: saturated_math.h:113
impeller::saturated::ONLY_ON_FLOAT
ONLY_ON_FLOAT(FP) Add(FP location
impeller::saturated::distance
SI distance
Definition: saturated_math.h:57
impeller::saturated::is_signed_integral_v
constexpr bool is_signed_integral_v
Definition: saturated_math.h:21
impeller::saturated::ONLY_ON_SIGNED_INT_RET
ONLY_ON_SIGNED_INT_RET(SI, Scalar) AverageScalar(SI a
impeller
Definition: allocation.cc:12
impeller::Scalar
float Scalar
Definition: scalar.h:19
scalar.h