| 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 "SkTypes.h" |
| 12 #include "SkTLogic.h" | 12 #include "SkTLogic.h" |
| 13 #include <limits> | 13 #include <limits> |
| 14 | 14 |
| 15 namespace sktfitsin { | 15 namespace sktfitsin { |
| 16 namespace Private { | 16 namespace Private { |
| 17 | 17 |
| 18 /** SkTHasMoreDigits::type = (digits(A) >= digits(B)) ? SkTrue : SkFalse. */ | 18 /** SkTMux::type = (a && b) ? Both : (a) ? A : (b) ? B : Neither; */ |
| 19 template<typename A, typename B> struct SkTHasMoreDigits { | 19 template <bool a, bool b, typename Both, typename A, typename B, typename Neithe
r> |
| 20 typedef SkTBool<std::numeric_limits<A>::digits >= std::numeric_limits<B>::di
gits> type; | 20 struct SkTMux { |
| 21 using type = skstd::conditional_t<a, skstd::conditional_t<b, Both, A>, |
| 22 skstd::conditional_t<b, B, Neither>>; |
| 21 }; | 23 }; |
| 22 | 24 |
| 25 /** SkTHasMoreDigits = (digits(A) >= digits(B)) ? true_type : false_type. */ |
| 26 template<typename A, typename B> struct SkTHasMoreDigits |
| 27 : skstd::bool_constant<std::numeric_limits<A>::digits >= std::numeric_limits
<B>::digits> |
| 28 { }; |
| 29 |
| 23 /** 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 |
| 24 * that source values are in the range of the Destination. | 31 * that source values are in the range of the Destination. |
| 25 */ | 32 */ |
| 26 template <typename S> struct SkTOutOfRange_False { | 33 template <typename S> struct SkTOutOfRange_False { |
| 27 typedef SkFalse can_be_true; | 34 typedef skstd::false_type can_be_true; |
| 28 typedef S source_type; | 35 typedef S source_type; |
| 29 static bool apply(S s) { | 36 static bool apply(S s) { |
| 30 return false; | 37 return false; |
| 31 } | 38 } |
| 32 }; | 39 }; |
| 33 | 40 |
| 34 /** 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). |
| 35 * Assumes that Min(S) <= Min(D). | 42 * Assumes that Min(S) <= Min(D). |
| 36 */ | 43 */ |
| 37 template <typename D, typename S> struct SkTOutOfRange_LT_MinD { | 44 template <typename D, typename S> struct SkTOutOfRange_LT_MinD { |
| 38 typedef SkTrue can_be_true; | 45 typedef skstd::true_type can_be_true; |
| 39 typedef S source_type; | 46 typedef S source_type; |
| 40 static bool apply(S s) { | 47 static bool apply(S s) { |
| 41 typedef typename SkTHasMoreDigits<S, D>::type precondition; | 48 typedef SkTHasMoreDigits<S, D> precondition; |
| 42 static_assert(precondition::value, "SkTOutOfRange_LT_MinD__minS_gt_minD"
); | 49 static_assert(precondition::value, "SkTOutOfRange_LT_MinD__minS_gt_minD"
); |
| 43 | 50 |
| 44 return s < static_cast<S>((std::numeric_limits<D>::min)()); | 51 return s < static_cast<S>((std::numeric_limits<D>::min)()); |
| 45 } | 52 } |
| 46 }; | 53 }; |
| 47 | 54 |
| 48 /** 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. */ |
| 49 template <typename D, typename S> struct SkTOutOfRange_LT_Zero { | 56 template <typename D, typename S> struct SkTOutOfRange_LT_Zero { |
| 50 typedef SkTrue can_be_true; | 57 typedef skstd::true_type can_be_true; |
| 51 typedef S source_type; | 58 typedef S source_type; |
| 52 static bool apply(S s) { | 59 static bool apply(S s) { |
| 53 return s < static_cast<S>(0); | 60 return s < static_cast<S>(0); |
| 54 } | 61 } |
| 55 }; | 62 }; |
| 56 | 63 |
| 57 /** 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). |
| 58 * Assumes that Max(S) >= Max(D). | 65 * Assumes that Max(S) >= Max(D). |
| 59 */ | 66 */ |
| 60 template <typename D, typename S> struct SkTOutOfRange_GT_MaxD { | 67 template <typename D, typename S> struct SkTOutOfRange_GT_MaxD { |
| 61 typedef SkTrue can_be_true; | 68 typedef skstd::true_type can_be_true; |
| 62 typedef S source_type; | 69 typedef S source_type; |
| 63 static bool apply(S s) { | 70 static bool apply(S s) { |
| 64 typedef typename SkTHasMoreDigits<S, D>::type precondition; | 71 typedef SkTHasMoreDigits<S, D> precondition; |
| 65 static_assert(precondition::value, "SkTOutOfRange_GT_MaxD__maxS_lt_maxD"
); | 72 static_assert(precondition::value, "SkTOutOfRange_GT_MaxD__maxS_lt_maxD"
); |
| 66 | 73 |
| 67 return s > static_cast<S>((std::numeric_limits<D>::max)()); | 74 return s > static_cast<S>((std::numeric_limits<D>::max)()); |
| 68 } | 75 } |
| 69 }; | 76 }; |
| 70 | 77 |
| 71 /** Composes two SkTOutOfRange predicates. | 78 /** Composes two SkTOutOfRange predicates. |
| 72 * First checks OutOfRange_Low then, if in range, OutOfRange_High. | 79 * First checks OutOfRange_Low then, if in range, OutOfRange_High. |
| 73 */ | 80 */ |
| 74 template<class OutOfRange_Low, class OutOfRange_High> struct SkTOutOfRange_Eithe
r { | 81 template<class OutOfRange_Low, class OutOfRange_High> struct SkTOutOfRange_Eithe
r { |
| 75 typedef SkTrue can_be_true; | 82 typedef skstd::true_type can_be_true; |
| 76 typedef typename OutOfRange_Low::source_type source_type; | 83 typedef typename OutOfRange_Low::source_type source_type; |
| 77 static bool apply(source_type s) { | 84 static bool apply(source_type s) { |
| 78 bool outOfRange = OutOfRange_Low::apply(s); | 85 bool outOfRange = OutOfRange_Low::apply(s); |
| 79 if (!outOfRange) { | 86 if (!outOfRange) { |
| 80 outOfRange = OutOfRange_High::apply(s); | 87 outOfRange = OutOfRange_High::apply(s); |
| 81 } | 88 } |
| 82 return outOfRange; | 89 return outOfRange; |
| 83 } | 90 } |
| 84 }; | 91 }; |
| 85 | 92 |
| 86 /** SkTCombineOutOfRange::type is an SkTOutOfRange_XXX type which is the | 93 /** SkTCombineOutOfRange::type is an SkTOutOfRange_XXX type which is the |
| 87 * optimal combination of OutOfRange_Low and OutOfRange_High. | 94 * optimal combination of OutOfRange_Low and OutOfRange_High. |
| 88 */ | 95 */ |
| 89 template<class OutOfRange_Low, class OutOfRange_High> struct SkTCombineOutOfRang
e { | 96 template<class OutOfRange_Low, class OutOfRange_High> struct SkTCombineOutOfRang
e { |
| 90 typedef SkTOutOfRange_Either<OutOfRange_Low, OutOfRange_High> Both; | 97 typedef SkTOutOfRange_Either<OutOfRange_Low, OutOfRange_High> Both; |
| 91 typedef SkTOutOfRange_False<typename OutOfRange_Low::source_type> Neither; | 98 typedef SkTOutOfRange_False<typename OutOfRange_Low::source_type> Neither; |
| 92 | 99 |
| 93 typedef typename OutOfRange_Low::can_be_true apply_low; | 100 typedef typename OutOfRange_Low::can_be_true apply_low; |
| 94 typedef typename OutOfRange_High::can_be_true apply_high; | 101 typedef typename OutOfRange_High::can_be_true apply_high; |
| 95 | 102 |
| 96 typedef typename SkTMux<apply_low, apply_high, | 103 typedef typename SkTMux<apply_low::value, apply_high::value, |
| 97 Both, OutOfRange_Low, OutOfRange_High, Neither>::typ
e type; | 104 Both, OutOfRange_Low, OutOfRange_High, Neither>::typ
e type; |
| 98 }; | 105 }; |
| 99 | 106 |
| 100 template<typename D, typename S, class OutOfRange_Low, class OutOfRange_High> | 107 template<typename D, typename S, class OutOfRange_Low, class OutOfRange_High> |
| 101 struct SkTRangeChecker { | 108 struct SkTRangeChecker { |
| 102 /** 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. */ |
| 103 static bool OutOfRange(S s) { | 110 static bool OutOfRange(S s) { |
| 104 typedef typename SkTCombineOutOfRange<OutOfRange_Low, OutOfRange_High>::
type Combined; | 111 typedef typename SkTCombineOutOfRange<OutOfRange_Low, OutOfRange_High>::
type Combined; |
| 105 return Combined::apply(s); | 112 return Combined::apply(s); |
| 106 } | 113 } |
| 107 }; | 114 }; |
| 108 | 115 |
| 109 /** 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 |
| 110 * 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
. |
| 111 * Assumes that S and D are unsigned integer types. | 118 * Assumes that S and D are unsigned integer types. |
| 112 */ | 119 */ |
| 113 template<typename D, typename S> struct SkTFitsIn_Unsigned2Unsiged { | 120 template<typename D, typename S> struct SkTFitsIn_Unsigned2Unsiged { |
| 114 typedef SkTOutOfRange_False<S> OutOfRange_Low; | 121 typedef SkTOutOfRange_False<S> OutOfRange_Low; |
| 115 typedef SkTOutOfRange_GT_MaxD<D, S> OutOfRange_High; | 122 typedef SkTOutOfRange_GT_MaxD<D, S> OutOfRange_High; |
| 116 | 123 |
| 117 typedef SkTRangeChecker<D, S, OutOfRange_Low, OutOfRange_High> HighSideOnlyC
heck; | 124 typedef SkTRangeChecker<D, S, OutOfRange_Low, OutOfRange_High> HighSideOnlyC
heck; |
| 118 typedef SkTRangeChecker<D, S, SkTOutOfRange_False<S>, SkTOutOfRange_False<S>
> NoCheck; | 125 typedef SkTRangeChecker<D, S, SkTOutOfRange_False<S>, SkTOutOfRange_False<S>
> NoCheck; |
| 119 | 126 |
| 120 // 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. |
| 121 // This also protects the precondition of SkTOutOfRange_GT_MaxD. | 128 // This also protects the precondition of SkTOutOfRange_GT_MaxD. |
| 122 typedef typename SkTHasMoreDigits<D, S>::type sourceFitsInDesitination; | 129 typedef SkTHasMoreDigits<D, S> sourceFitsInDesitination; |
| 123 typedef typename SkTIf<sourceFitsInDesitination, NoCheck, HighSideOnlyCheck>
::type type; | 130 typedef skstd::conditional_t<sourceFitsInDesitination::value, NoCheck, HighS
ideOnlyCheck> type; |
| 124 }; | 131 }; |
| 125 | 132 |
| 126 /** 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 |
| 127 * 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
. |
| 128 * Assumes that S and D are signed integer types. | 135 * Assumes that S and D are signed integer types. |
| 129 */ | 136 */ |
| 130 template<typename D, typename S> struct SkTFitsIn_Signed2Signed { | 137 template<typename D, typename S> struct SkTFitsIn_Signed2Signed { |
| 131 typedef SkTOutOfRange_LT_MinD<D, S> OutOfRange_Low; | 138 typedef SkTOutOfRange_LT_MinD<D, S> OutOfRange_Low; |
| 132 typedef SkTOutOfRange_GT_MaxD<D, S> OutOfRange_High; | 139 typedef SkTOutOfRange_GT_MaxD<D, S> OutOfRange_High; |
| 133 | 140 |
| 134 typedef SkTRangeChecker<D, S, OutOfRange_Low, OutOfRange_High> FullCheck; | 141 typedef SkTRangeChecker<D, S, OutOfRange_Low, OutOfRange_High> FullCheck; |
| 135 typedef SkTRangeChecker<D, S, SkTOutOfRange_False<S>, SkTOutOfRange_False<S>
> NoCheck; | 142 typedef SkTRangeChecker<D, S, SkTOutOfRange_False<S>, SkTOutOfRange_False<S>
> NoCheck; |
| 136 | 143 |
| 137 // 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. |
| 138 // 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. |
| 139 typedef typename SkTHasMoreDigits<D, S>::type sourceFitsInDesitination; | 146 typedef SkTHasMoreDigits<D, S> sourceFitsInDesitination; |
| 140 typedef typename SkTIf<sourceFitsInDesitination, NoCheck, FullCheck>::type t
ype; | 147 typedef skstd::conditional_t<sourceFitsInDesitination::value, NoCheck, FullC
heck> type; |
| 141 }; | 148 }; |
| 142 | 149 |
| 143 /** 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 |
| 144 * 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
. |
| 145 * 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. |
| 146 */ | 153 */ |
| 147 template<typename D, typename S> struct SkTFitsIn_Signed2Unsigned { | 154 template<typename D, typename S> struct SkTFitsIn_Signed2Unsigned { |
| 148 typedef SkTOutOfRange_LT_Zero<D, S> OutOfRange_Low; | 155 typedef SkTOutOfRange_LT_Zero<D, S> OutOfRange_Low; |
| 149 typedef SkTOutOfRange_GT_MaxD<D, S> OutOfRange_High; | 156 typedef SkTOutOfRange_GT_MaxD<D, S> OutOfRange_High; |
| 150 | 157 |
| 151 typedef SkTRangeChecker<D, S, OutOfRange_Low, OutOfRange_High> FullCheck; | 158 typedef SkTRangeChecker<D, S, OutOfRange_Low, OutOfRange_High> FullCheck; |
| 152 typedef SkTRangeChecker<D, S, OutOfRange_Low, SkTOutOfRange_False<S> > LowSi
deOnlyCheck; | 159 typedef SkTRangeChecker<D, S, OutOfRange_Low, SkTOutOfRange_False<S> > LowSi
deOnlyCheck; |
| 153 | 160 |
| 154 // If std::numeric_limits<D>::max() >= std::numeric_limits<S>::max(), | 161 // If std::numeric_limits<D>::max() >= std::numeric_limits<S>::max(), |
| 155 // 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.) |
| 156 // This also protects the precondition of SkTOutOfRange_GT_MaxD. | 163 // This also protects the precondition of SkTOutOfRange_GT_MaxD. |
| 157 typedef typename SkTHasMoreDigits<D, S>::type sourceCannotExceedDesitination
; | 164 typedef SkTHasMoreDigits<D, S> sourceCannotExceedDest; |
| 158 typedef typename SkTIf<sourceCannotExceedDesitination, LowSideOnlyCheck, Ful
lCheck>::type type; | 165 typedef skstd::conditional_t<sourceCannotExceedDest::value, LowSideOnlyCheck
, FullCheck> type; |
| 159 }; | 166 }; |
| 160 | 167 |
| 161 /** 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 |
| 162 * 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
. |
| 163 * 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. |
| 164 */ | 171 */ |
| 165 template<typename D, typename S> struct SkTFitsIn_Unsigned2Signed { | 172 template<typename D, typename S> struct SkTFitsIn_Unsigned2Signed { |
| 166 typedef SkTOutOfRange_False<S> OutOfRange_Low; | 173 typedef SkTOutOfRange_False<S> OutOfRange_Low; |
| 167 typedef SkTOutOfRange_GT_MaxD<D, S> OutOfRange_High; | 174 typedef SkTOutOfRange_GT_MaxD<D, S> OutOfRange_High; |
| 168 | 175 |
| 169 typedef SkTRangeChecker<D, S, OutOfRange_Low, OutOfRange_High> HighSideOnlyC
heck; | 176 typedef SkTRangeChecker<D, S, OutOfRange_Low, OutOfRange_High> HighSideOnlyC
heck; |
| 170 typedef SkTRangeChecker<D, S, SkTOutOfRange_False<S>, SkTOutOfRange_False<S>
> NoCheck; | 177 typedef SkTRangeChecker<D, S, SkTOutOfRange_False<S>, SkTOutOfRange_False<S>
> NoCheck; |
| 171 | 178 |
| 172 // 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. |
| 173 // (Until C++11, assume more digits means greater max.) | 180 // (Until C++11, assume more digits means greater max.) |
| 174 // This also protects the precondition of SkTOutOfRange_GT_MaxD. | 181 // This also protects the precondition of SkTOutOfRange_GT_MaxD. |
| 175 typedef typename SkTHasMoreDigits<D, S>::type sourceCannotExceedDesitination
; | 182 typedef SkTHasMoreDigits<D, S> sourceCannotExceedDest; |
| 176 typedef typename SkTIf<sourceCannotExceedDesitination, NoCheck, HighSideOnly
Check>::type type; | 183 typedef skstd::conditional_t<sourceCannotExceedDest::value, NoCheck, HighSid
eOnlyCheck> type; |
| 177 }; | 184 }; |
| 178 | 185 |
| 179 /** SkTFitsIn::type is an SkTRangeChecker with an OutOfRange(S s) method | 186 /** SkTFitsIn::type is an SkTRangeChecker with an OutOfRange(S s) method |
| 180 * 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
. |
| 181 * Assumes that S and D are integer types. | 188 * Assumes that S and D are integer types. |
| 182 */ | 189 */ |
| 183 template<typename D, typename S> struct SkTFitsIn { | 190 template<typename D, typename S> struct SkTFitsIn { |
| 184 // One of the following will be the 'selector' type. | 191 // One of the following will be the 'selector' type. |
| 185 typedef SkTFitsIn_Signed2Signed<D, S> S2S; | 192 typedef SkTFitsIn_Signed2Signed<D, S> S2S; |
| 186 typedef SkTFitsIn_Signed2Unsigned<D, S> S2U; | 193 typedef SkTFitsIn_Signed2Unsigned<D, S> S2U; |
| 187 typedef SkTFitsIn_Unsigned2Signed<D, S> U2S; | 194 typedef SkTFitsIn_Unsigned2Signed<D, S> U2S; |
| 188 typedef SkTFitsIn_Unsigned2Unsiged<D, S> U2U; | 195 typedef SkTFitsIn_Unsigned2Unsiged<D, S> U2U; |
| 189 | 196 |
| 190 typedef SkTBool<std::numeric_limits<S>::is_signed> S_is_signed; | 197 typedef skstd::bool_constant<std::numeric_limits<S>::is_signed> S_is_signed; |
| 191 typedef SkTBool<std::numeric_limits<D>::is_signed> D_is_signed; | 198 typedef skstd::bool_constant<std::numeric_limits<D>::is_signed> D_is_signed; |
| 192 | 199 |
| 193 typedef typename SkTMux<S_is_signed, D_is_signed, S2S, S2U, U2S, U2U>::type
selector; | 200 typedef typename SkTMux<S_is_signed::value, D_is_signed::value, |
| 201 S2S, S2U, U2S, U2U>::type selector; |
| 194 // This type is an SkTRangeChecker. | 202 // This type is an SkTRangeChecker. |
| 195 typedef typename selector::type type; | 203 typedef typename selector::type type; |
| 196 }; | 204 }; |
| 197 | 205 |
| 198 } // namespace Private | 206 } // namespace Private |
| 199 } // namespace sktfitsin | 207 } // namespace sktfitsin |
| 200 | 208 |
| 201 /** Returns true if the integer source value 's' will fit in the integer destina
tion type 'D'. */ | 209 /** Returns true if the integer source value 's' will fit in the integer destina
tion type 'D'. */ |
| 202 template <typename D, typename S> inline bool SkTFitsIn(S s) { | 210 template <typename D, typename S> inline bool SkTFitsIn(S s) { |
| 203 static_assert(std::numeric_limits<S>::is_integer, "SkTFitsIn_source_must_be_
integer"); | 211 static_assert(std::numeric_limits<S>::is_integer, "SkTFitsIn_source_must_be_
integer"); |
| 204 static_assert(std::numeric_limits<D>::is_integer, "SkTFitsIn_destination_mus
t_be_integer"); | 212 static_assert(std::numeric_limits<D>::is_integer, "SkTFitsIn_destination_mus
t_be_integer"); |
| 205 | 213 |
| 206 return !sktfitsin::Private::SkTFitsIn<D, S>::type::OutOfRange(s); | 214 return !sktfitsin::Private::SkTFitsIn<D, S>::type::OutOfRange(s); |
| 207 } | 215 } |
| 208 | 216 |
| 209 #endif | 217 #endif |
| OLD | NEW |