OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 // Slightly adapted for inclusion in V8. | |
6 // Copyright 2014 the V8 project authors. All rights reserved. | |
7 | |
8 #ifndef BASE_SAFE_CONVERSIONS_IMPL_H_ | |
jochen (gone - plz use gerrit)
2014/06/16 14:25:46
please use V8_BASE_SAFE_CONVERSIONS_IMPL_H_
Jakob Kummerow
2014/06/17 13:53:20
Done.
| |
9 #define BASE_SAFE_CONVERSIONS_IMPL_H_ | |
10 | |
11 #include <limits> | |
12 | |
13 #include "src/base/macros.h" | |
14 | |
15 namespace v8 { | |
16 namespace internal { | |
jochen (gone - plz use gerrit)
2014/06/16 14:25:46
please use namespace v8::base in the base library
Jakob Kummerow
2014/06/17 13:53:20
Done.
| |
17 | |
18 // The std library doesn't provide a binary max_exponent for integers, however | |
19 // we can compute one by adding one to the number of non-sign bits. This allows | |
20 // for accurate range comparisons between floating point and integer types. | |
21 template <typename NumericType> | |
22 struct MaxExponent { | |
23 static const int value = std::numeric_limits<NumericType>::is_iec559 | |
24 ? std::numeric_limits<NumericType>::max_exponent | |
25 : (sizeof(NumericType) * 8 + 1 - | |
26 std::numeric_limits<NumericType>::is_signed); | |
27 }; | |
28 | |
29 enum IntegerRepresentation { | |
30 INTEGER_REPRESENTATION_UNSIGNED, | |
31 INTEGER_REPRESENTATION_SIGNED | |
32 }; | |
33 | |
34 // A range for a given nunmeric Src type is contained for a given numeric Dst | |
35 // type if both numeric_limits<Src>::max() <= numeric_limits<Dst>::max() and | |
36 // numeric_limits<Src>::min() >= numeric_limits<Dst>::min() are true. | |
37 // We implement this as template specializations rather than simple static | |
38 // comparisons to ensure type correctness in our comparisons. | |
39 enum NumericRangeRepresentation { | |
40 NUMERIC_RANGE_NOT_CONTAINED, | |
41 NUMERIC_RANGE_CONTAINED | |
42 }; | |
43 | |
44 // Helper templates to statically determine if our destination type can contain | |
45 // maximum and minimum values represented by the source type. | |
46 | |
47 template < | |
48 typename Dst, | |
49 typename Src, | |
50 IntegerRepresentation DstSign = std::numeric_limits<Dst>::is_signed | |
51 ? INTEGER_REPRESENTATION_SIGNED | |
52 : INTEGER_REPRESENTATION_UNSIGNED, | |
53 IntegerRepresentation SrcSign = | |
54 std::numeric_limits<Src>::is_signed | |
55 ? INTEGER_REPRESENTATION_SIGNED | |
56 : INTEGER_REPRESENTATION_UNSIGNED > | |
57 struct StaticDstRangeRelationToSrcRange; | |
58 | |
59 // Same sign: Dst is guaranteed to contain Src only if its range is equal or | |
60 // larger. | |
61 template <typename Dst, typename Src, IntegerRepresentation Sign> | |
62 struct StaticDstRangeRelationToSrcRange<Dst, Src, Sign, Sign> { | |
63 static const NumericRangeRepresentation value = | |
64 MaxExponent<Dst>::value >= MaxExponent<Src>::value | |
65 ? NUMERIC_RANGE_CONTAINED | |
66 : NUMERIC_RANGE_NOT_CONTAINED; | |
67 }; | |
68 | |
69 // Unsigned to signed: Dst is guaranteed to contain source only if its range is | |
70 // larger. | |
71 template <typename Dst, typename Src> | |
72 struct StaticDstRangeRelationToSrcRange<Dst, | |
73 Src, | |
74 INTEGER_REPRESENTATION_SIGNED, | |
75 INTEGER_REPRESENTATION_UNSIGNED> { | |
76 static const NumericRangeRepresentation value = | |
77 MaxExponent<Dst>::value > MaxExponent<Src>::value | |
78 ? NUMERIC_RANGE_CONTAINED | |
79 : NUMERIC_RANGE_NOT_CONTAINED; | |
80 }; | |
81 | |
82 // Signed to unsigned: Dst cannot be statically determined to contain Src. | |
83 template <typename Dst, typename Src> | |
84 struct StaticDstRangeRelationToSrcRange<Dst, | |
85 Src, | |
86 INTEGER_REPRESENTATION_UNSIGNED, | |
87 INTEGER_REPRESENTATION_SIGNED> { | |
88 static const NumericRangeRepresentation value = NUMERIC_RANGE_NOT_CONTAINED; | |
89 }; | |
90 | |
91 enum RangeConstraint { | |
92 RANGE_VALID = 0x0, // Value can be represented by the destination type. | |
93 RANGE_UNDERFLOW = 0x1, // Value would overflow. | |
94 RANGE_OVERFLOW = 0x2, // Value would underflow. | |
95 RANGE_INVALID = RANGE_UNDERFLOW | RANGE_OVERFLOW // Invalid (i.e. NaN). | |
96 }; | |
97 | |
98 // Helper function for coercing an int back to a RangeContraint. | |
99 inline RangeConstraint GetRangeConstraint(int integer_range_constraint) { | |
100 // TODO(jochen/jkummerow): Re-enable this when checks.h is available in base. | |
101 // ASSERT(integer_range_constraint >= RANGE_VALID && | |
102 // integer_range_constraint <= RANGE_INVALID); | |
103 return static_cast<RangeConstraint>(integer_range_constraint); | |
104 } | |
105 | |
106 // This function creates a RangeConstraint from an upper and lower bound | |
107 // check by taking advantage of the fact that only NaN can be out of range in | |
108 // both directions at once. | |
109 inline RangeConstraint GetRangeConstraint(bool is_in_upper_bound, | |
110 bool is_in_lower_bound) { | |
111 return GetRangeConstraint((is_in_upper_bound ? 0 : RANGE_OVERFLOW) | | |
112 (is_in_lower_bound ? 0 : RANGE_UNDERFLOW)); | |
113 } | |
114 | |
115 template < | |
116 typename Dst, | |
117 typename Src, | |
118 IntegerRepresentation DstSign = std::numeric_limits<Dst>::is_signed | |
119 ? INTEGER_REPRESENTATION_SIGNED | |
120 : INTEGER_REPRESENTATION_UNSIGNED, | |
121 IntegerRepresentation SrcSign = std::numeric_limits<Src>::is_signed | |
122 ? INTEGER_REPRESENTATION_SIGNED | |
123 : INTEGER_REPRESENTATION_UNSIGNED, | |
124 NumericRangeRepresentation DstRange = | |
125 StaticDstRangeRelationToSrcRange<Dst, Src>::value > | |
126 struct DstRangeRelationToSrcRangeImpl; | |
127 | |
128 // The following templates are for ranges that must be verified at runtime. We | |
129 // split it into checks based on signedness to avoid confusing casts and | |
130 // compiler warnings on signed an unsigned comparisons. | |
131 | |
132 // Dst range is statically determined to contain Src: Nothing to check. | |
133 template <typename Dst, | |
134 typename Src, | |
135 IntegerRepresentation DstSign, | |
136 IntegerRepresentation SrcSign> | |
137 struct DstRangeRelationToSrcRangeImpl<Dst, | |
138 Src, | |
139 DstSign, | |
140 SrcSign, | |
141 NUMERIC_RANGE_CONTAINED> { | |
142 static RangeConstraint Check(Src value) { return RANGE_VALID; } | |
143 }; | |
144 | |
145 // Signed to signed narrowing: Both the upper and lower boundaries may be | |
146 // exceeded. | |
147 template <typename Dst, typename Src> | |
148 struct DstRangeRelationToSrcRangeImpl<Dst, | |
149 Src, | |
150 INTEGER_REPRESENTATION_SIGNED, | |
151 INTEGER_REPRESENTATION_SIGNED, | |
152 NUMERIC_RANGE_NOT_CONTAINED> { | |
153 static RangeConstraint Check(Src value) { | |
154 return std::numeric_limits<Dst>::is_iec559 | |
155 ? GetRangeConstraint(value <= std::numeric_limits<Dst>::max(), | |
156 value >= -std::numeric_limits<Dst>::max()) | |
157 : GetRangeConstraint(value <= std::numeric_limits<Dst>::max(), | |
158 value >= std::numeric_limits<Dst>::min()); | |
159 } | |
160 }; | |
161 | |
162 // Unsigned to unsigned narrowing: Only the upper boundary can be exceeded. | |
163 template <typename Dst, typename Src> | |
164 struct DstRangeRelationToSrcRangeImpl<Dst, | |
165 Src, | |
166 INTEGER_REPRESENTATION_UNSIGNED, | |
167 INTEGER_REPRESENTATION_UNSIGNED, | |
168 NUMERIC_RANGE_NOT_CONTAINED> { | |
169 static RangeConstraint Check(Src value) { | |
170 return GetRangeConstraint(value <= std::numeric_limits<Dst>::max(), true); | |
171 } | |
172 }; | |
173 | |
174 // Unsigned to signed: The upper boundary may be exceeded. | |
175 template <typename Dst, typename Src> | |
176 struct DstRangeRelationToSrcRangeImpl<Dst, | |
177 Src, | |
178 INTEGER_REPRESENTATION_SIGNED, | |
179 INTEGER_REPRESENTATION_UNSIGNED, | |
180 NUMERIC_RANGE_NOT_CONTAINED> { | |
181 static RangeConstraint Check(Src value) { | |
182 return sizeof(Dst) > sizeof(Src) | |
183 ? RANGE_VALID | |
184 : GetRangeConstraint( | |
185 value <= static_cast<Src>(std::numeric_limits<Dst>::max()), | |
186 true); | |
187 } | |
188 }; | |
189 | |
190 // Signed to unsigned: The upper boundary may be exceeded for a narrower Dst, | |
191 // and any negative value exceeds the lower boundary. | |
192 template <typename Dst, typename Src> | |
193 struct DstRangeRelationToSrcRangeImpl<Dst, | |
194 Src, | |
195 INTEGER_REPRESENTATION_UNSIGNED, | |
196 INTEGER_REPRESENTATION_SIGNED, | |
197 NUMERIC_RANGE_NOT_CONTAINED> { | |
198 static RangeConstraint Check(Src value) { | |
199 return (MaxExponent<Dst>::value >= MaxExponent<Src>::value) | |
200 ? GetRangeConstraint(true, value >= static_cast<Src>(0)) | |
201 : GetRangeConstraint( | |
202 value <= static_cast<Src>(std::numeric_limits<Dst>::max()), | |
203 value >= static_cast<Src>(0)); | |
204 } | |
205 }; | |
206 | |
207 template <typename Dst, typename Src> | |
208 inline RangeConstraint DstRangeRelationToSrcRange(Src value) { | |
209 // Both source and destination must be numeric. | |
210 STATIC_ASSERT(std::numeric_limits<Src>::is_specialized); | |
211 STATIC_ASSERT(std::numeric_limits<Dst>::is_specialized); | |
212 return DstRangeRelationToSrcRangeImpl<Dst, Src>::Check(value); | |
213 } | |
214 | |
215 } // namespace internal | |
216 } // namespace v8 | |
217 | |
218 #endif // BASE_SAFE_CONVERSIONS_IMPL_H_ | |
OLD | NEW |