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 "SkTLogic.h" |
| 12 #include <limits> |
| 13 |
| 14 namespace sktfitsin { |
| 15 namespace Private { |
| 16 |
| 17 /** A high or low side predicate which is used when it is statically known |
| 18 * that source values are in the range of the Destination. |
| 19 */ |
| 20 template <typename S> struct SkTOutOfRange_False { |
| 21 typedef SkFalse can_be_true; |
| 22 typedef S source_type; |
| 23 static bool apply(S s) { |
| 24 return false; |
| 25 } |
| 26 }; |
| 27 |
| 28 /** A low side predicate which tests if the source value < Min(D). |
| 29 * Assumes that Min(S) <= Min(D). |
| 30 */ |
| 31 template <typename D, typename S> struct SkTOutOfRange_LT_MinD { |
| 32 typedef SkTrue can_be_true; |
| 33 typedef S source_type; |
| 34 static bool apply(S s) { |
| 35 return s < static_cast<S>(std::numeric_limits<D>::min()); |
| 36 } |
| 37 }; |
| 38 |
| 39 /** A low side predicate which tests if the source value is less than 0. */ |
| 40 template <typename D, typename S> struct SkTOutOfRange_LT_Zero { |
| 41 typedef SkTrue can_be_true; |
| 42 typedef S source_type; |
| 43 static bool apply(S s) { |
| 44 return s < static_cast<S>(0); |
| 45 } |
| 46 }; |
| 47 |
| 48 /** A high side predicate which tests if the source value > Max(D). |
| 49 * Assumes that Max(S) >= Max(D). |
| 50 */ |
| 51 template <typename D, typename S> struct SkTOutOfRange_GT_MaxD { |
| 52 typedef SkTrue can_be_true; |
| 53 typedef S source_type; |
| 54 static bool apply(S s) { |
| 55 return s > static_cast<S>(std::numeric_limits<D>::max()); |
| 56 } |
| 57 }; |
| 58 |
| 59 /** Composes two SkTOutOfRange predicates: first 'Low' then, if in range, 'High'
. */ |
| 60 template<class OutOfRange_Low, class OutOfRange_High> struct SkTOutOfRange_Eithe
r { |
| 61 typedef SkTrue can_be_true; |
| 62 typedef typename OutOfRange_Low::source_type source_type; |
| 63 static bool apply(source_type s) { |
| 64 bool outOfRange = OutOfRange_Low::apply(s); |
| 65 if (!outOfRange) { |
| 66 outOfRange = OutOfRange_High::apply(s); |
| 67 } |
| 68 return outOfRange; |
| 69 } |
| 70 }; |
| 71 |
| 72 /** Optimally combines low and high OutOfRange predicates. */ |
| 73 template<class OutOfRange_Low, class OutOfRange_High> struct SkTCombineOutOfRang
e { |
| 74 typedef SkTOutOfRange_Either<OutOfRange_Low, OutOfRange_High> Both; |
| 75 typedef SkTOutOfRange_False<typename OutOfRange_Low::source_type> Neither; |
| 76 |
| 77 typedef typename OutOfRange_Low::can_be_true apply_low; |
| 78 typedef typename OutOfRange_High::can_be_true apply_high; |
| 79 |
| 80 typedef typename SkTMux<apply_low, apply_high, |
| 81 Both, OutOfRange_Low, OutOfRange_High, Neither>::typ
e type; |
| 82 }; |
| 83 |
| 84 template<typename D, typename S, class OutOfRange_Low, class OutOfRange_High> |
| 85 struct SkTRangeChecker { |
| 86 /** This is the method which is called at runtime to do the range check. */ |
| 87 static bool OutOfRange(S s) { |
| 88 typedef typename SkTCombineOutOfRange<OutOfRange_Low, OutOfRange_High>::
type Combined; |
| 89 return Combined::apply(s); |
| 90 } |
| 91 }; |
| 92 |
| 93 /** SkTrue if D has the same or more magnitude digits than S. */ |
| 94 template<typename D, typename S> struct SkTHasMoreDigits { |
| 95 typedef SkTBool<std::numeric_limits<D>::digits >= std::numeric_limits<S>::di
gits> type; |
| 96 }; |
| 97 |
| 98 template<typename D, typename S> struct SkTFitsIn_Unsigned2Unsiged { |
| 99 typedef SkTOutOfRange_False<S> OutOfRange_Low; |
| 100 typedef SkTOutOfRange_GT_MaxD<D, S> OutOfRange_High; |
| 101 |
| 102 typedef SkTRangeChecker<D, S, OutOfRange_Low, OutOfRange_High> HighSideOnlyC
heck; |
| 103 typedef SkTRangeChecker<D, S, SkTOutOfRange_False<S>, SkTOutOfRange_False<S>
> NoCheck; |
| 104 |
| 105 // If std::numeric_limits<D>::digits >= std::numeric_limits<S>::digits, noth
ing to check. |
| 106 typedef typename SkTHasMoreDigits<D, S>::type sourceFitsInDesitination; |
| 107 typedef typename SkTIf<sourceFitsInDesitination, NoCheck, HighSideOnlyCheck>
::type type; |
| 108 }; |
| 109 |
| 110 template<typename D, typename S> struct SkTFitsIn_Signed2Signed { |
| 111 typedef SkTOutOfRange_LT_MinD<D, S> OutOfRange_Low; |
| 112 typedef SkTOutOfRange_GT_MaxD<D, S> OutOfRange_High; |
| 113 |
| 114 typedef SkTRangeChecker<D, S, OutOfRange_Low, OutOfRange_High> FullCheck; |
| 115 typedef SkTRangeChecker<D, S, SkTOutOfRange_False<S>, SkTOutOfRange_False<S>
> NoCheck; |
| 116 |
| 117 // If std::numeric_limits<D>::digits >= std::numeric_limits<S>::digits, noth
ing to check. |
| 118 typedef typename SkTHasMoreDigits<D, S>::type sourceFitsInDesitination; |
| 119 typedef typename SkTIf<sourceFitsInDesitination, NoCheck, FullCheck>::type t
ype; |
| 120 }; |
| 121 |
| 122 template<typename D, typename S> struct SkTFitsIn_Signed2Unsigned { |
| 123 typedef SkTOutOfRange_LT_Zero<D, S> OutOfRange_Low; |
| 124 typedef SkTOutOfRange_GT_MaxD<D, S> OutOfRange_High; |
| 125 |
| 126 typedef SkTRangeChecker<D, S, OutOfRange_Low, OutOfRange_High> FullCheck; |
| 127 typedef SkTRangeChecker<D, S, OutOfRange_Low, SkTOutOfRange_False<S> > LowSi
deOnlyCheck; |
| 128 |
| 129 // If std::numeric_limits<D>::max() >= std::numeric_limits<S>::max(), |
| 130 // no need to check the high side. (Until C++11, assume more digits means gr
eater max.) |
| 131 typedef typename SkTHasMoreDigits<D, S>::type sourceCannotExceedDesitination
; |
| 132 typedef typename SkTIf<sourceCannotExceedDesitination, LowSideOnlyCheck, Ful
lCheck>::type type; |
| 133 }; |
| 134 |
| 135 template<typename D, typename S> struct SkTFitsIn_Unsigned2Signed { |
| 136 typedef SkTOutOfRange_False<S> OutOfRange_Low; |
| 137 typedef SkTOutOfRange_GT_MaxD<D, S> OutOfRange_High; |
| 138 |
| 139 typedef SkTRangeChecker<D, S, OutOfRange_Low, OutOfRange_High> HighSideOnlyC
heck; |
| 140 typedef SkTRangeChecker<D, S, SkTOutOfRange_False<S>, SkTOutOfRange_False<S>
> NoCheck; |
| 141 |
| 142 // If std::numeric_limits<D>::max() >= std::numeric_limits<S>::max(), nothin
g to check. |
| 143 // (Until C++11, assume more digits means greater max.) |
| 144 typedef typename SkTHasMoreDigits<D, S>::type sourceCannotExceedDesitination
; |
| 145 typedef typename SkTIf<sourceCannotExceedDesitination, NoCheck, HighSideOnly
Check>::type type; |
| 146 }; |
| 147 |
| 148 template<typename D, typename S, typename Enable = void> struct SkTFitsIn { }; |
| 149 template<typename D, typename S> |
| 150 struct SkTFitsIn<D, S, typename SkTEnableIf_c<std::numeric_limits<S>::is_integer
&& |
| 151 std::numeric_limits<D>::is_integer
>::type> |
| 152 { |
| 153 // One of the following will be the 'selector' type. |
| 154 typedef SkTFitsIn_Signed2Signed<D, S> S2S; |
| 155 typedef SkTFitsIn_Signed2Unsigned<D, S> S2U; |
| 156 typedef SkTFitsIn_Unsigned2Signed<D, S> U2S; |
| 157 typedef SkTFitsIn_Unsigned2Unsiged<D, S> U2U; |
| 158 |
| 159 typedef SkTBool<std::numeric_limits<S>::is_signed> S_is_signed; |
| 160 typedef SkTBool<std::numeric_limits<D>::is_signed> D_is_signed; |
| 161 |
| 162 typedef typename SkTMux<S_is_signed, D_is_signed, S2S, S2U, U2S, U2U>::type
selector; |
| 163 // This type is an SkTRangeChecker. |
| 164 typedef typename selector::type type; |
| 165 }; |
| 166 |
| 167 } |
| 168 } |
| 169 |
| 170 /** Returns true if the integer source value 's' will fit in the integer destina
tion type 'D'. */ |
| 171 template <typename D, typename S> inline bool SkTFitsIn(S s) { |
| 172 return !sktfitsin::Private::SkTFitsIn<D, S>::type::OutOfRange(s); |
| 173 } |
| 174 |
| 175 #endif |
OLD | NEW |