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