OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #ifndef SkTFitsIn_DEFINED | 8 #ifndef SkTFitsIn_DEFINED |
9 #define SkTFitsIn_DEFINED | 9 #define SkTFitsIn_DEFINED |
10 | 10 |
11 #include "SkTypes.h" | 11 #include "../private/SkTLogic.h" |
12 #include "SkTLogic.h" | |
13 #include <limits> | 12 #include <limits> |
14 #include <type_traits> | 13 #include <type_traits> |
15 | 14 |
16 namespace sktfitsin { | 15 namespace sktfitsin { |
17 namespace Private { | 16 namespace Private { |
18 | 17 |
19 /** SkTMux::type = (a && b) ? Both : (a) ? A : (b) ? B : Neither; */ | 18 /** SkTMux::type = (a && b) ? Both : (a) ? A : (b) ? B : Neither; */ |
20 template <bool a, bool b, typename Both, typename A, typename B, typename Neithe
r> | 19 template <bool a, bool b, typename Both, typename A, typename B, typename Neithe
r> |
21 struct SkTMux { | 20 struct SkTMux { |
22 using type = skstd::conditional_t<a, skstd::conditional_t<b, Both, A>, | 21 using type = skstd::conditional_t<a, skstd::conditional_t<b, Both, A>, |
23 skstd::conditional_t<b, B, Neither>>; | 22 skstd::conditional_t<b, B, Neither>>; |
24 }; | 23 }; |
25 | 24 |
26 /** SkTHasMoreDigits = (digits(A) >= digits(B)) ? true_type : false_type. */ | 25 /** SkTHasMoreDigits = (digits(A) >= digits(B)) ? true_type : false_type. */ |
27 template<typename A, typename B> struct SkTHasMoreDigits | 26 template <typename A, typename B> struct SkTHasMoreDigits |
28 : skstd::bool_constant<std::numeric_limits<A>::digits >= std::numeric_limits
<B>::digits> | 27 : skstd::bool_constant<std::numeric_limits<A>::digits >= std::numeric_limits
<B>::digits> |
29 { }; | 28 { }; |
30 | 29 |
31 /** A high or low side predicate which is used when it is statically known | 30 /** A high or low side predicate which is used when it is statically known |
32 * that source values are in the range of the Destination. | 31 * that source values are in the range of the Destination. |
33 */ | 32 */ |
34 template <typename S> struct SkTOutOfRange_False { | 33 template <typename S> struct SkTOutOfRange_False { |
35 typedef std::false_type can_be_true; | 34 using can_be_true = std::false_type; |
36 typedef S source_type; | 35 using source_type = S; |
37 static bool apply(S s) { | 36 static bool apply(S) { |
38 return false; | 37 return false; |
39 } | 38 } |
40 }; | 39 }; |
41 | 40 |
42 /** A low side predicate which tests if the source value < Min(D). | 41 /** A low side predicate which tests if the source value < Min(D). |
43 * Assumes that Min(S) <= Min(D). | 42 * Assumes that Min(S) <= Min(D). |
44 */ | 43 */ |
45 template <typename D, typename S> struct SkTOutOfRange_LT_MinD { | 44 template <typename D, typename S> struct SkTOutOfRange_LT_MinD { |
46 typedef std::true_type can_be_true; | 45 using can_be_true = std::true_type; |
47 typedef S source_type; | 46 using source_type = S; |
48 static bool apply(S s) { | 47 static bool apply(S s) { |
49 typedef SkTHasMoreDigits<S, D> precondition; | 48 using precondition = SkTHasMoreDigits<S, D>; |
50 static_assert(precondition::value, "SkTOutOfRange_LT_MinD__minS_gt_minD"
); | 49 static_assert(precondition::value, "minS > minD"); |
51 | 50 |
52 return s < static_cast<S>((std::numeric_limits<D>::min)()); | 51 return s < static_cast<S>((std::numeric_limits<D>::min)()); |
53 } | 52 } |
54 }; | 53 }; |
55 | 54 |
56 /** A low side predicate which tests if the source value is less than 0. */ | 55 /** A low side predicate which tests if the source value is less than 0. */ |
57 template <typename D, typename S> struct SkTOutOfRange_LT_Zero { | 56 template <typename D, typename S> struct SkTOutOfRange_LT_Zero { |
58 typedef std::true_type can_be_true; | 57 using can_be_true = std::true_type; |
59 typedef S source_type; | 58 using source_type = S; |
60 static bool apply(S s) { | 59 static bool apply(S s) { |
61 return s < static_cast<S>(0); | 60 return s < static_cast<S>(0); |
62 } | 61 } |
63 }; | 62 }; |
64 | 63 |
65 /** A high side predicate which tests if the source value > Max(D). | 64 /** A high side predicate which tests if the source value > Max(D). |
66 * Assumes that Max(S) >= Max(D). | 65 * Assumes that Max(S) >= Max(D). |
67 */ | 66 */ |
68 template <typename D, typename S> struct SkTOutOfRange_GT_MaxD { | 67 template <typename D, typename S> struct SkTOutOfRange_GT_MaxD { |
69 typedef std::true_type can_be_true; | 68 using can_be_true = std::true_type; |
70 typedef S source_type; | 69 using source_type = S; |
71 static bool apply(S s) { | 70 static bool apply(S s) { |
72 typedef SkTHasMoreDigits<S, D> precondition; | 71 using precondition = SkTHasMoreDigits<S, D>; |
73 static_assert(precondition::value, "SkTOutOfRange_GT_MaxD__maxS_lt_maxD"
); | 72 static_assert(precondition::value, "maxS < maxD"); |
74 | 73 |
75 return s > static_cast<S>((std::numeric_limits<D>::max)()); | 74 return s > static_cast<S>((std::numeric_limits<D>::max)()); |
76 } | 75 } |
77 }; | 76 }; |
78 | 77 |
79 /** Composes two SkTOutOfRange predicates. | 78 /** Composes two SkTOutOfRange predicates. |
80 * First checks OutOfRange_Low then, if in range, OutOfRange_High. | 79 * First checks OutOfRange_Low then, if in range, OutOfRange_High. |
81 */ | 80 */ |
82 template<class OutOfRange_Low, class OutOfRange_High> struct SkTOutOfRange_Eithe
r { | 81 template <typename OutOfRange_Low, typename OutOfRange_High> struct SkTOutOfRang
e_Either { |
83 typedef std::true_type can_be_true; | 82 using can_be_true = std::true_type; |
84 typedef typename OutOfRange_Low::source_type source_type; | 83 using source_type = typename OutOfRange_Low::source_type; |
85 static bool apply(source_type s) { | 84 static bool apply(source_type s) { |
86 bool outOfRange = OutOfRange_Low::apply(s); | 85 bool outOfRange = OutOfRange_Low::apply(s); |
87 if (!outOfRange) { | 86 if (!outOfRange) { |
88 outOfRange = OutOfRange_High::apply(s); | 87 outOfRange = OutOfRange_High::apply(s); |
89 } | 88 } |
90 return outOfRange; | 89 return outOfRange; |
91 } | 90 } |
92 }; | 91 }; |
93 | 92 |
94 /** SkTCombineOutOfRange::type is an SkTOutOfRange_XXX type which is the | 93 /** SkTCombineOutOfRange::type is an SkTOutOfRange_XXX type which is the |
95 * optimal combination of OutOfRange_Low and OutOfRange_High. | 94 * optimal combination of OutOfRange_Low and OutOfRange_High. |
96 */ | 95 */ |
97 template<class OutOfRange_Low, class OutOfRange_High> struct SkTCombineOutOfRang
e { | 96 template <typename OutOfRange_Low, typename OutOfRange_High> struct SkTCombineOu
tOfRange { |
98 typedef SkTOutOfRange_Either<OutOfRange_Low, OutOfRange_High> Both; | 97 using Both = SkTOutOfRange_Either<OutOfRange_Low, OutOfRange_High>; |
99 typedef SkTOutOfRange_False<typename OutOfRange_Low::source_type> Neither; | 98 using Neither = SkTOutOfRange_False<typename OutOfRange_Low::source_type>; |
100 | 99 |
101 typedef typename OutOfRange_Low::can_be_true apply_low; | 100 using apply_low = typename OutOfRange_Low::can_be_true; |
102 typedef typename OutOfRange_High::can_be_true apply_high; | 101 using apply_high = typename OutOfRange_High::can_be_true; |
103 | 102 |
104 typedef typename SkTMux<apply_low::value, apply_high::value, | 103 using type = typename SkTMux<apply_low::value, apply_high::value, |
105 Both, OutOfRange_Low, OutOfRange_High, Neither>::typ
e type; | 104 Both, OutOfRange_Low, OutOfRange_High, Neither>
::type; |
106 }; | 105 }; |
107 | 106 |
108 template<typename D, typename S, class OutOfRange_Low, class OutOfRange_High> | 107 template <typename D, typename S, typename OutOfRange_Low, typename OutOfRange_H
igh> |
109 struct SkTRangeChecker { | 108 struct SkTRangeChecker { |
110 /** This is the method which is called at runtime to do the range check. */ | 109 /** This is the method which is called at runtime to do the range check. */ |
111 static bool OutOfRange(S s) { | 110 static bool OutOfRange(S s) { |
112 typedef typename SkTCombineOutOfRange<OutOfRange_Low, OutOfRange_High>::
type Combined; | 111 using Combined = typename SkTCombineOutOfRange<OutOfRange_Low, OutOfRang
e_High>::type; |
113 return Combined::apply(s); | 112 return Combined::apply(s); |
114 } | 113 } |
115 }; | 114 }; |
116 | 115 |
117 /** SkTFitsIn_Unsigned2Unsiged::type is an SkTRangeChecker with an OutOfRange(S
s) method | 116 /** SkTFitsIn_Unsigned2Unsiged::type is an SkTRangeChecker with an OutOfRange(S
s) method |
118 * the implementation of which is tailored for the source and destination types
. | 117 * the implementation of which is tailored for the source and destination types
. |
119 * Assumes that S and D are unsigned integer types. | 118 * Assumes that S and D are unsigned integer types. |
120 */ | 119 */ |
121 template<typename D, typename S> struct SkTFitsIn_Unsigned2Unsiged { | 120 template <typename D, typename S> struct SkTFitsIn_Unsigned2Unsiged { |
122 typedef SkTOutOfRange_False<S> OutOfRange_Low; | 121 using OutOfRange_Low = SkTOutOfRange_False<S>; |
123 typedef SkTOutOfRange_GT_MaxD<D, S> OutOfRange_High; | 122 using OutOfRange_High = SkTOutOfRange_GT_MaxD<D, S>; |
124 | 123 |
125 typedef SkTRangeChecker<D, S, OutOfRange_Low, OutOfRange_High> HighSideOnlyC
heck; | 124 using HighSideOnlyCheck = SkTRangeChecker<D, S, OutOfRange_Low, OutOfRange_H
igh>; |
126 typedef SkTRangeChecker<D, S, SkTOutOfRange_False<S>, SkTOutOfRange_False<S>
> NoCheck; | 125 using NoCheck = SkTRangeChecker<D, S, SkTOutOfRange_False<S>, SkTOutOfRange_
False<S>>; |
127 | 126 |
128 // If std::numeric_limits<D>::digits >= std::numeric_limits<S>::digits, noth
ing to check. | 127 // If std::numeric_limits<D>::digits >= std::numeric_limits<S>::digits, noth
ing to check. |
129 // This also protects the precondition of SkTOutOfRange_GT_MaxD. | 128 // This also protects the precondition of SkTOutOfRange_GT_MaxD. |
130 typedef SkTHasMoreDigits<D, S> sourceFitsInDesitination; | 129 using sourceFitsInDesitination = SkTHasMoreDigits<D, S>; |
131 typedef skstd::conditional_t<sourceFitsInDesitination::value, NoCheck, HighS
ideOnlyCheck> type; | 130 using type = skstd::conditional_t<sourceFitsInDesitination::value, NoCheck,
HighSideOnlyCheck>; |
132 }; | 131 }; |
133 | 132 |
134 /** SkTFitsIn_Signed2Signed::type is an SkTRangeChecker with an OutOfRange(S s)
method | 133 /** SkTFitsIn_Signed2Signed::type is an SkTRangeChecker with an OutOfRange(S s)
method |
135 * the implementation of which is tailored for the source and destination types
. | 134 * the implementation of which is tailored for the source and destination types
. |
136 * Assumes that S and D are signed integer types. | 135 * Assumes that S and D are signed integer types. |
137 */ | 136 */ |
138 template<typename D, typename S> struct SkTFitsIn_Signed2Signed { | 137 template <typename D, typename S> struct SkTFitsIn_Signed2Signed { |
139 typedef SkTOutOfRange_LT_MinD<D, S> OutOfRange_Low; | 138 using OutOfRange_Low = SkTOutOfRange_LT_MinD<D, S>; |
140 typedef SkTOutOfRange_GT_MaxD<D, S> OutOfRange_High; | 139 using OutOfRange_High = SkTOutOfRange_GT_MaxD<D, S>; |
141 | 140 |
142 typedef SkTRangeChecker<D, S, OutOfRange_Low, OutOfRange_High> FullCheck; | 141 using FullCheck = SkTRangeChecker<D, S, OutOfRange_Low, OutOfRange_High>; |
143 typedef SkTRangeChecker<D, S, SkTOutOfRange_False<S>, SkTOutOfRange_False<S>
> NoCheck; | 142 using NoCheck = SkTRangeChecker<D, S, SkTOutOfRange_False<S>, SkTOutOfRange_
False<S>>; |
144 | 143 |
145 // If std::numeric_limits<D>::digits >= std::numeric_limits<S>::digits, noth
ing to check. | 144 // If std::numeric_limits<D>::digits >= std::numeric_limits<S>::digits, noth
ing to check. |
146 // This also protects the precondition of SkTOutOfRange_LT_MinD and SkTOutOf
Range_GT_MaxD. | 145 // This also protects the precondition of SkTOutOfRange_LT_MinD and SkTOutOf
Range_GT_MaxD. |
147 typedef SkTHasMoreDigits<D, S> sourceFitsInDesitination; | 146 using sourceFitsInDesitination = SkTHasMoreDigits<D, S>; |
148 typedef skstd::conditional_t<sourceFitsInDesitination::value, NoCheck, FullC
heck> type; | 147 using type = skstd::conditional_t<sourceFitsInDesitination::value, NoCheck,
FullCheck>; |
149 }; | 148 }; |
150 | 149 |
151 /** SkTFitsIn_Signed2Unsigned::type is an SkTRangeChecker with an OutOfRange(S s
) method | 150 /** SkTFitsIn_Signed2Unsigned::type is an SkTRangeChecker with an OutOfRange(S s
) method |
152 * the implementation of which is tailored for the source and destination types
. | 151 * the implementation of which is tailored for the source and destination types
. |
153 * Assumes that S is a signed integer type and D is an unsigned integer type. | 152 * Assumes that S is a signed integer type and D is an unsigned integer type. |
154 */ | 153 */ |
155 template<typename D, typename S> struct SkTFitsIn_Signed2Unsigned { | 154 template <typename D, typename S> struct SkTFitsIn_Signed2Unsigned { |
156 typedef SkTOutOfRange_LT_Zero<D, S> OutOfRange_Low; | 155 using OutOfRange_Low = SkTOutOfRange_LT_Zero<D, S>; |
157 typedef SkTOutOfRange_GT_MaxD<D, S> OutOfRange_High; | 156 using OutOfRange_High = SkTOutOfRange_GT_MaxD<D, S>; |
158 | 157 |
159 typedef SkTRangeChecker<D, S, OutOfRange_Low, OutOfRange_High> FullCheck; | 158 using FullCheck = SkTRangeChecker<D, S, OutOfRange_Low, OutOfRange_High>; |
160 typedef SkTRangeChecker<D, S, OutOfRange_Low, SkTOutOfRange_False<S> > LowSi
deOnlyCheck; | 159 using LowSideOnlyCheck = SkTRangeChecker<D, S, OutOfRange_Low, SkTOutOfRange
_False<S>>; |
161 | 160 |
162 // If std::numeric_limits<D>::max() >= std::numeric_limits<S>::max(), | 161 // If std::numeric_limits<D>::max() >= std::numeric_limits<S>::max(), |
163 // no need to check the high side. (Until C++11, assume more digits means gr
eater max.) | 162 // no need to check the high side. (Until C++11, assume more digits means gr
eater max.) |
164 // This also protects the precondition of SkTOutOfRange_GT_MaxD. | 163 // This also protects the precondition of SkTOutOfRange_GT_MaxD. |
165 typedef SkTHasMoreDigits<D, S> sourceCannotExceedDest; | 164 using sourceCannotExceedDest = SkTHasMoreDigits<D, S>; |
166 typedef skstd::conditional_t<sourceCannotExceedDest::value, LowSideOnlyCheck
, FullCheck> type; | 165 using type = skstd::conditional_t<sourceCannotExceedDest::value, LowSideOnly
Check, FullCheck>; |
167 }; | 166 }; |
168 | 167 |
169 /** SkTFitsIn_Unsigned2Signed::type is an SkTRangeChecker with an OutOfRange(S s
) method | 168 /** SkTFitsIn_Unsigned2Signed::type is an SkTRangeChecker with an OutOfRange(S s
) method |
170 * the implementation of which is tailored for the source and destination types
. | 169 * the implementation of which is tailored for the source and destination types
. |
171 * Assumes that S is an usigned integer type and D is a signed integer type. | 170 * Assumes that S is an usigned integer type and D is a signed integer type. |
172 */ | 171 */ |
173 template<typename D, typename S> struct SkTFitsIn_Unsigned2Signed { | 172 template <typename D, typename S> struct SkTFitsIn_Unsigned2Signed { |
174 typedef SkTOutOfRange_False<S> OutOfRange_Low; | 173 using OutOfRange_Low = SkTOutOfRange_False<S>; |
175 typedef SkTOutOfRange_GT_MaxD<D, S> OutOfRange_High; | 174 using OutOfRange_High = SkTOutOfRange_GT_MaxD<D, S>; |
176 | 175 |
177 typedef SkTRangeChecker<D, S, OutOfRange_Low, OutOfRange_High> HighSideOnlyC
heck; | 176 using HighSideOnlyCheck = SkTRangeChecker<D, S, OutOfRange_Low, OutOfRange_H
igh>; |
178 typedef SkTRangeChecker<D, S, SkTOutOfRange_False<S>, SkTOutOfRange_False<S>
> NoCheck; | 177 using NoCheck = SkTRangeChecker<D, S, SkTOutOfRange_False<S>, SkTOutOfRange_
False<S>>; |
179 | 178 |
180 // If std::numeric_limits<D>::max() >= std::numeric_limits<S>::max(), nothin
g to check. | 179 // If std::numeric_limits<D>::max() >= std::numeric_limits<S>::max(), nothin
g to check. |
181 // (Until C++11, assume more digits means greater max.) | 180 // (Until C++11, assume more digits means greater max.) |
182 // This also protects the precondition of SkTOutOfRange_GT_MaxD. | 181 // This also protects the precondition of SkTOutOfRange_GT_MaxD. |
183 typedef SkTHasMoreDigits<D, S> sourceCannotExceedDest; | 182 using sourceCannotExceedDest = SkTHasMoreDigits<D, S>; |
184 typedef skstd::conditional_t<sourceCannotExceedDest::value, NoCheck, HighSid
eOnlyCheck> type; | 183 using type = skstd::conditional_t<sourceCannotExceedDest::value, NoCheck, Hi
ghSideOnlyCheck>; |
185 }; | 184 }; |
186 | 185 |
187 /** SkTFitsIn::type is an SkTRangeChecker with an OutOfRange(S s) method | 186 /** SkTFitsIn::type is an SkTRangeChecker with an OutOfRange(S s) method |
188 * the implementation of which is tailored for the source and destination types
. | 187 * the implementation of which is tailored for the source and destination types
. |
189 * Assumes that S and D are integer types. | 188 * Assumes that S and D are integer types. |
190 */ | 189 */ |
191 template<typename D, typename S> struct SkTFitsIn { | 190 template <typename D, typename S> struct SkTFitsIn { |
192 // One of the following will be the 'selector' type. | 191 // One of the following will be the 'selector' type. |
193 typedef SkTFitsIn_Signed2Signed<D, S> S2S; | 192 using S2S = SkTFitsIn_Signed2Signed<D, S>; |
194 typedef SkTFitsIn_Signed2Unsigned<D, S> S2U; | 193 using S2U = SkTFitsIn_Signed2Unsigned<D, S>; |
195 typedef SkTFitsIn_Unsigned2Signed<D, S> U2S; | 194 using U2S = SkTFitsIn_Unsigned2Signed<D, S>; |
196 typedef SkTFitsIn_Unsigned2Unsiged<D, S> U2U; | 195 using U2U = SkTFitsIn_Unsigned2Unsiged<D, S>; |
197 | 196 |
198 typedef skstd::bool_constant<std::numeric_limits<S>::is_signed> S_is_signed; | 197 using S_is_signed = skstd::bool_constant<std::numeric_limits<S>::is_signed>; |
199 typedef skstd::bool_constant<std::numeric_limits<D>::is_signed> D_is_signed; | 198 using D_is_signed = skstd::bool_constant<std::numeric_limits<D>::is_signed>; |
200 | 199 |
201 typedef typename SkTMux<S_is_signed::value, D_is_signed::value, | 200 using selector = typename SkTMux<S_is_signed::value, D_is_signed::value, |
202 S2S, S2U, U2S, U2U>::type selector; | 201 S2S, S2U, U2S, U2U>::type; |
203 // This type is an SkTRangeChecker. | 202 // This type is an SkTRangeChecker. |
204 typedef typename selector::type type; | 203 using type = typename selector::type; |
| 204 }; |
| 205 |
| 206 template <typename T, bool = std::is_enum<T>::value> struct underlying_type { |
| 207 using type = skstd::underlying_type_t<T>; |
| 208 }; |
| 209 template <typename T> struct underlying_type<T, false> { |
| 210 using type = T; |
205 }; | 211 }; |
206 | 212 |
207 } // namespace Private | 213 } // namespace Private |
208 } // namespace sktfitsin | 214 } // namespace sktfitsin |
209 | 215 |
210 /** Returns true if the integer source value 's' will fit in the integer destina
tion type 'D'. */ | 216 /** Returns true if the integer source value 's' will fit in the integer destina
tion type 'D'. */ |
211 template <typename D, typename S> inline bool SkTFitsIn(S s) { | 217 template <typename D, typename S> inline bool SkTFitsIn(S s) { |
212 static_assert(std::numeric_limits<S>::is_integer, "SkTFitsIn_source_must_be_
integer"); | 218 static_assert(std::is_integral<S>::value || std::is_enum<S>::value, "S must
be integral."); |
213 static_assert(std::numeric_limits<D>::is_integer, "SkTFitsIn_destination_mus
t_be_integer"); | 219 static_assert(std::is_integral<D>::value || std::is_enum<D>::value, "D must
be integral."); |
214 | 220 |
215 return !sktfitsin::Private::SkTFitsIn<D, S>::type::OutOfRange(s); | 221 using RealS = typename sktfitsin::Private::underlying_type<S>::type; |
| 222 using RealD = typename sktfitsin::Private::underlying_type<D>::type; |
| 223 |
| 224 return !sktfitsin::Private::SkTFitsIn<RealD, RealS>::type::OutOfRange(s); |
216 } | 225 } |
217 | 226 |
218 #endif | 227 #endif |
OLD | NEW |