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