Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(86)

Side by Side Diff: third_party/WebKit/Source/wtf/CheckedArithmetic.h

Issue 1611343002: wtf reformat test Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: pydent Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2011 Apple Inc. All rights reserved. 2 * Copyright (C) 2011 Apple Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 5 * modification, are permitted provided that the following conditions
6 * are met: 6 * are met:
7 * 1. Redistributions of source code must retain the above copyright 7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright 9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
59 * Checked<T> works for all integer types, with the following caveats: 59 * Checked<T> works for all integer types, with the following caveats:
60 * - Mixing signedness of operands is only supported for types narrower than 60 * - Mixing signedness of operands is only supported for types narrower than
61 * 64bits. 61 * 64bits.
62 * - It does have a performance impact, so tight loops may want to be careful 62 * - It does have a performance impact, so tight loops may want to be careful
63 * when using it. 63 * when using it.
64 * 64 *
65 */ 65 */
66 66
67 namespace WTF { 67 namespace WTF {
68 68
69 enum class CheckedState { 69 enum class CheckedState { DidOverflow, DidNotOverflow };
70 DidOverflow,
71 DidNotOverflow
72 };
73 70
74 class CrashOnOverflow { 71 class CrashOnOverflow {
75 protected: 72 protected:
76 NO_RETURN_DUE_TO_CRASH void overflowed() 73 NO_RETURN_DUE_TO_CRASH void overflowed() { CRASH(); }
77 { 74
78 CRASH(); 75 void clearOverflow() {}
79 } 76
80 77 public:
81 void clearOverflow() { } 78 bool hasOverflowed() const { return false; }
82
83 public:
84 bool hasOverflowed() const { return false; }
85 }; 79 };
86 80
87 class RecordOverflow { 81 class RecordOverflow {
88 protected: 82 protected:
89 RecordOverflow() 83 RecordOverflow() : m_overflowed(false) {}
90 : m_overflowed(false) 84
91 { 85 void overflowed() { m_overflowed = true; }
92 } 86
93 87 void clearOverflow() { m_overflowed = false; }
94 void overflowed() 88
95 { 89 public:
96 m_overflowed = true; 90 bool hasOverflowed() const { return m_overflowed; }
97 } 91
98 92 private:
99 void clearOverflow() 93 unsigned char m_overflowed;
100 { 94 };
101 m_overflowed = false; 95
102 } 96 template <typename T, class OverflowHandler = CrashOnOverflow>
103 97 class Checked;
104 public: 98 template <typename T>
105 bool hasOverflowed() const { return m_overflowed; } 99 struct RemoveChecked;
106 100 template <typename T>
107 private: 101 struct RemoveChecked<Checked<T>>;
108 unsigned char m_overflowed; 102
109 }; 103 template <typename Target,
110 104 typename Source,
111 template <typename T, class OverflowHandler = CrashOnOverflow> class Checked; 105 bool targetSigned = std::numeric_limits<Target>::is_signed,
112 template <typename T> struct RemoveChecked; 106 bool sourceSigned = std::numeric_limits<Source>::is_signed>
113 template <typename T> struct RemoveChecked<Checked<T>>; 107 struct BoundsChecker;
114 108 template <typename Target, typename Source>
115 template <typename Target, typename Source, bool targetSigned = std::numeric_lim its<Target>::is_signed, bool sourceSigned = std::numeric_limits<Source>::is_sign ed> struct BoundsChecker; 109 struct BoundsChecker<Target, Source, false, false> {
116 template <typename Target, typename Source> struct BoundsChecker<Target, Source, false, false> { 110 static bool inBounds(Source value) {
117 static bool inBounds(Source value) 111 // Same signedness so implicit type conversion will always increase precisio n
118 { 112 // to widest type
119 // Same signedness so implicit type conversion will always increase prec ision 113 return value <= std::numeric_limits<Target>::max();
120 // to widest type 114 }
121 return value <= std::numeric_limits<Target>::max(); 115 };
122 } 116
123 }; 117 template <typename Target, typename Source>
124 118 struct BoundsChecker<Target, Source, true, true> {
125 template <typename Target, typename Source> struct BoundsChecker<Target, Source, true, true> { 119 static bool inBounds(Source value) {
126 static bool inBounds(Source value) 120 // Same signedness so implicit type conversion will always increase precisio n
127 { 121 // to widest type
128 // Same signedness so implicit type conversion will always increase prec ision 122 return std::numeric_limits<Target>::min() <= value &&
129 // to widest type 123 value <= std::numeric_limits<Target>::max();
130 return std::numeric_limits<Target>::min() <= value && value <= std::nume ric_limits<Target>::max(); 124 }
131 } 125 };
132 }; 126
133 127 template <typename Target, typename Source>
134 template <typename Target, typename Source> struct BoundsChecker<Target, Source, false, true> { 128 struct BoundsChecker<Target, Source, false, true> {
135 static bool inBounds(Source value) 129 static bool inBounds(Source value) {
136 { 130 // Target is unsigned so any value less than zero is clearly unsafe
137 // Target is unsigned so any value less than zero is clearly unsafe 131 if (value < 0)
138 if (value < 0) 132 return false;
139 return false; 133 // If our (unsigned) Target is the same or greater width we can
140 // If our (unsigned) Target is the same or greater width we can 134 // convert value to type Target without losing precision
141 // convert value to type Target without losing precision 135 if (sizeof(Target) >= sizeof(Source))
142 if (sizeof(Target) >= sizeof(Source)) 136 return static_cast<Target>(value) <= std::numeric_limits<Target>::max();
143 return static_cast<Target>(value) <= std::numeric_limits<Target>::ma x(); 137 // The signed Source type has greater precision than the target so
144 // The signed Source type has greater precision than the target so 138 // max(Target) -> Source will widen.
145 // max(Target) -> Source will widen. 139 return value <= static_cast<Source>(std::numeric_limits<Target>::max());
146 return value <= static_cast<Source>(std::numeric_limits<Target>::max()); 140 }
147 } 141 };
148 }; 142
149 143 template <typename Target, typename Source>
150 template <typename Target, typename Source> struct BoundsChecker<Target, Source, true, false> { 144 struct BoundsChecker<Target, Source, true, false> {
151 static bool inBounds(Source value) 145 static bool inBounds(Source value) {
152 { 146 // Signed target with an unsigned source
153 // Signed target with an unsigned source 147 if (sizeof(Target) <= sizeof(Source))
154 if (sizeof(Target) <= sizeof(Source)) 148 return value <= static_cast<Source>(std::numeric_limits<Target>::max());
155 return value <= static_cast<Source>(std::numeric_limits<Target>::max ()); 149 // Target is Wider than Source so we're guaranteed to fit any value in
156 // Target is Wider than Source so we're guaranteed to fit any value in 150 // unsigned Source
157 // unsigned Source 151 return true;
158 return true; 152 }
159 } 153 };
160 }; 154
161 155 template <typename Target,
162 template <typename Target, typename Source, bool CanElide = std::is_same<Target, Source>::value || (sizeof(Target) > sizeof(Source)) > struct BoundsCheckElider; 156 typename Source,
163 template <typename Target, typename Source> struct BoundsCheckElider<Target, Sou rce, true> { 157 bool CanElide = std::is_same<Target, Source>::value ||
164 static bool inBounds(Source) { return true; } 158 (sizeof(Target) > sizeof(Source))>
165 }; 159 struct BoundsCheckElider;
166 template <typename Target, typename Source> struct BoundsCheckElider<Target, Sou rce, false> : public BoundsChecker<Target, Source> { 160 template <typename Target, typename Source>
167 }; 161 struct BoundsCheckElider<Target, Source, true> {
168 162 static bool inBounds(Source) { return true; }
169 template <typename Target, typename Source> static inline bool isInBounds(Source value) 163 };
170 { 164 template <typename Target, typename Source>
171 return BoundsCheckElider<Target, Source>::inBounds(value); 165 struct BoundsCheckElider<Target, Source, false>
172 } 166 : public BoundsChecker<Target, Source> {};
173 167
174 template <typename T> struct RemoveChecked { 168 template <typename Target, typename Source>
175 typedef T CleanType; 169 static inline bool isInBounds(Source value) {
176 static const CleanType DefaultValue = 0; 170 return BoundsCheckElider<Target, Source>::inBounds(value);
177 }; 171 }
178 172
179 template <typename T> struct RemoveChecked<Checked<T, CrashOnOverflow>> { 173 template <typename T>
180 typedef typename RemoveChecked<T>::CleanType CleanType; 174 struct RemoveChecked {
181 static const CleanType DefaultValue = 0; 175 typedef T CleanType;
182 }; 176 static const CleanType DefaultValue = 0;
183 177 };
184 template <typename T> struct RemoveChecked<Checked<T, RecordOverflow>> { 178
185 typedef typename RemoveChecked<T>::CleanType CleanType; 179 template <typename T>
186 static const CleanType DefaultValue = 0; 180 struct RemoveChecked<Checked<T, CrashOnOverflow>> {
181 typedef typename RemoveChecked<T>::CleanType CleanType;
182 static const CleanType DefaultValue = 0;
183 };
184
185 template <typename T>
186 struct RemoveChecked<Checked<T, RecordOverflow>> {
187 typedef typename RemoveChecked<T>::CleanType CleanType;
188 static const CleanType DefaultValue = 0;
187 }; 189 };
188 190
189 // The ResultBase and SignednessSelector are used to workaround typeof not being 191 // The ResultBase and SignednessSelector are used to workaround typeof not being
190 // available in MSVC 192 // available in MSVC
191 template <typename U, typename V, bool uIsBigger = (sizeof(U) > sizeof(V)), bool sameSize = (sizeof(U) == sizeof(V))> struct ResultBase; 193 template <typename U,
192 template <typename U, typename V> struct ResultBase<U, V, true, false> { 194 typename V,
193 typedef U ResultType; 195 bool uIsBigger = (sizeof(U) > sizeof(V)),
194 }; 196 bool sameSize = (sizeof(U) == sizeof(V))>
195 197 struct ResultBase;
196 template <typename U, typename V> struct ResultBase<U, V, false, false> { 198 template <typename U, typename V>
197 typedef V ResultType; 199 struct ResultBase<U, V, true, false> {
198 }; 200 typedef U ResultType;
199 201 };
200 template <typename U> struct ResultBase<U, U, false, true> { 202
201 typedef U ResultType; 203 template <typename U, typename V>
202 }; 204 struct ResultBase<U, V, false, false> {
203 205 typedef V ResultType;
204 template <typename U, typename V, bool uIsSigned = std::numeric_limits<U>::is_si gned, bool vIsSigned = std::numeric_limits<V>::is_signed> struct SignednessSelec tor; 206 };
205 template <typename U, typename V> struct SignednessSelector<U, V, true, true> { 207
206 typedef U ResultType; 208 template <typename U>
207 }; 209 struct ResultBase<U, U, false, true> {
208 210 typedef U ResultType;
209 template <typename U, typename V> struct SignednessSelector<U, V, false, false> { 211 };
210 typedef U ResultType; 212
211 }; 213 template <typename U,
212 214 typename V,
213 template <typename U, typename V> struct SignednessSelector<U, V, true, false> { 215 bool uIsSigned = std::numeric_limits<U>::is_signed,
214 typedef V ResultType; 216 bool vIsSigned = std::numeric_limits<V>::is_signed>
215 }; 217 struct SignednessSelector;
216 218 template <typename U, typename V>
217 template <typename U, typename V> struct SignednessSelector<U, V, false, true> { 219 struct SignednessSelector<U, V, true, true> {
218 typedef U ResultType; 220 typedef U ResultType;
219 }; 221 };
220 222
221 template <typename U, typename V> struct ResultBase<U, V, false, true> { 223 template <typename U, typename V>
222 typedef typename SignednessSelector<U, V>::ResultType ResultType; 224 struct SignednessSelector<U, V, false, false> {
223 }; 225 typedef U ResultType;
224 226 };
225 template <typename U, typename V> struct Result : ResultBase<typename RemoveChec ked<U>::CleanType, typename RemoveChecked<V>::CleanType> { 227
226 }; 228 template <typename U, typename V>
227 229 struct SignednessSelector<U, V, true, false> {
228 template <typename LHS, typename RHS, typename ResultType = typename Result<LHS, RHS>::ResultType, 230 typedef V ResultType;
229 bool lhsSigned = std::numeric_limits<LHS>::is_signed, bool rhsSigned = std:: numeric_limits<RHS>::is_signed> struct ArithmeticOperations; 231 };
230 232
231 template <typename LHS, typename RHS, typename ResultType> struct ArithmeticOper ations<LHS, RHS, ResultType, true, true> { 233 template <typename U, typename V>
232 // LHS and RHS are signed types 234 struct SignednessSelector<U, V, false, true> {
233 235 typedef U ResultType;
234 // Helper function 236 };
235 static inline bool signsMatch(LHS lhs, RHS rhs) 237
236 { 238 template <typename U, typename V>
237 return (lhs ^ rhs) >= 0; 239 struct ResultBase<U, V, false, true> {
240 typedef typename SignednessSelector<U, V>::ResultType ResultType;
241 };
242
243 template <typename U, typename V>
244 struct Result : ResultBase<typename RemoveChecked<U>::CleanType,
245 typename RemoveChecked<V>::CleanType> {};
246
247 template <typename LHS,
248 typename RHS,
249 typename ResultType = typename Result<LHS, RHS>::ResultType,
250 bool lhsSigned = std::numeric_limits<LHS>::is_signed,
251 bool rhsSigned = std::numeric_limits<RHS>::is_signed>
252 struct ArithmeticOperations;
253
254 template <typename LHS, typename RHS, typename ResultType>
255 struct ArithmeticOperations<LHS, RHS, ResultType, true, true> {
256 // LHS and RHS are signed types
257
258 // Helper function
259 static inline bool signsMatch(LHS lhs, RHS rhs) { return (lhs ^ rhs) >= 0; }
260
261 static inline bool add(LHS lhs,
262 RHS rhs,
263 ResultType& result) WARN_UNUSED_RETURN {
264 if (signsMatch(lhs, rhs)) {
265 if (lhs >= 0) {
266 if ((std::numeric_limits<ResultType>::max() - rhs) < lhs)
267 return false;
268 } else {
269 ResultType temp = lhs - std::numeric_limits<ResultType>::min();
270 if (rhs < -temp)
271 return false;
272 }
273 } // if the signs do not match this operation can't overflow
274 result = static_cast<ResultType>(lhs + rhs);
275 return true;
276 }
277
278 static inline bool sub(LHS lhs,
279 RHS rhs,
280 ResultType& result) WARN_UNUSED_RETURN {
281 if (!signsMatch(lhs, rhs)) {
282 if (lhs >= 0) {
283 if (lhs > std::numeric_limits<ResultType>::max() + rhs)
284 return false;
285 } else {
286 if (rhs > std::numeric_limits<ResultType>::max() + lhs)
287 return false;
288 }
289 } // if the signs match this operation can't overflow
290 result = static_cast<ResultType>(lhs - rhs);
291 return true;
292 }
293
294 static inline bool multiply(LHS lhs,
295 RHS rhs,
296 ResultType& result) WARN_UNUSED_RETURN {
297 if (signsMatch(lhs, rhs)) {
298 if (lhs >= 0) {
299 if (lhs && (std::numeric_limits<ResultType>::max() / lhs) < rhs)
300 return false;
301 } else {
302 if (static_cast<ResultType>(lhs) ==
303 std::numeric_limits<ResultType>::min() ||
304 static_cast<ResultType>(rhs) ==
305 std::numeric_limits<ResultType>::min())
306 return false;
307 if ((std::numeric_limits<ResultType>::max() / -lhs) < -rhs)
308 return false;
309 }
310 } else {
311 if (lhs < 0) {
312 if (rhs && lhs < (std::numeric_limits<ResultType>::min() / rhs))
313 return false;
314 } else {
315 if (lhs && rhs < (std::numeric_limits<ResultType>::min() / lhs))
316 return false;
317 }
238 } 318 }
239 319 result = static_cast<ResultType>(lhs * rhs);
240 static inline bool add(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RET URN 320 return true;
241 { 321 }
242 if (signsMatch(lhs, rhs)) { 322
243 if (lhs >= 0) { 323 static inline bool equals(LHS lhs, RHS rhs) { return lhs == rhs; }
244 if ((std::numeric_limits<ResultType>::max() - rhs) < lhs) 324 };
245 return false; 325
246 } else { 326 template <typename LHS, typename RHS, typename ResultType>
247 ResultType temp = lhs - std::numeric_limits<ResultType>::min(); 327 struct ArithmeticOperations<LHS, RHS, ResultType, false, false> {
248 if (rhs < -temp) 328 // LHS and RHS are unsigned types so bounds checks are nice and easy
249 return false; 329 static inline bool add(LHS lhs,
250 } 330 RHS rhs,
251 } // if the signs do not match this operation can't overflow 331 ResultType& result) WARN_UNUSED_RETURN {
252 result = static_cast<ResultType>(lhs + rhs); 332 ResultType temp = lhs + rhs;
253 return true; 333 if (temp < lhs)
334 return false;
335 result = temp;
336 return true;
337 }
338
339 static inline bool sub(LHS lhs,
340 RHS rhs,
341 ResultType& result) WARN_UNUSED_RETURN {
342 ResultType temp = lhs - rhs;
343 if (temp > lhs)
344 return false;
345 result = temp;
346 return true;
347 }
348
349 static inline bool multiply(LHS lhs,
350 RHS rhs,
351 ResultType& result) WARN_UNUSED_RETURN {
352 if (!lhs || !rhs) {
353 result = 0;
354 return true;
254 } 355 }
255 356 if (std::numeric_limits<ResultType>::max() / lhs < rhs)
256 static inline bool sub(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RET URN 357 return false;
257 { 358 result = lhs * rhs;
258 if (!signsMatch(lhs, rhs)) { 359 return true;
259 if (lhs >= 0) { 360 }
260 if (lhs > std::numeric_limits<ResultType>::max() + rhs) 361
261 return false; 362 static inline bool equals(LHS lhs, RHS rhs) { return lhs == rhs; }
262 } else { 363 };
263 if (rhs > std::numeric_limits<ResultType>::max() + lhs) 364
264 return false; 365 template <typename ResultType>
265 } 366 struct ArithmeticOperations<int, unsigned, ResultType, true, false> {
266 } // if the signs match this operation can't overflow 367 static inline bool add(int64_t lhs, int64_t rhs, ResultType& result) {
267 result = static_cast<ResultType>(lhs - rhs); 368 int64_t temp = lhs + rhs;
268 return true; 369 if (temp < std::numeric_limits<ResultType>::min())
269 } 370 return false;
270 371 if (temp > std::numeric_limits<ResultType>::max())
271 static inline bool multiply(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSE D_RETURN 372 return false;
272 { 373 result = static_cast<ResultType>(temp);
273 if (signsMatch(lhs, rhs)) { 374 return true;
274 if (lhs >= 0) { 375 }
275 if (lhs && (std::numeric_limits<ResultType>::max() / lhs) < rhs) 376
276 return false; 377 static inline bool sub(int64_t lhs, int64_t rhs, ResultType& result) {
277 } else { 378 int64_t temp = lhs - rhs;
278 if (static_cast<ResultType>(lhs) == std::numeric_limits<ResultTy pe>::min() || static_cast<ResultType>(rhs) == std::numeric_limits<ResultType>::m in()) 379 if (temp < std::numeric_limits<ResultType>::min())
279 return false; 380 return false;
280 if ((std::numeric_limits<ResultType>::max() / -lhs) < -rhs) 381 if (temp > std::numeric_limits<ResultType>::max())
281 return false; 382 return false;
282 } 383 result = static_cast<ResultType>(temp);
283 } else { 384 return true;
284 if (lhs < 0) { 385 }
285 if (rhs && lhs < (std::numeric_limits<ResultType>::min() / rhs)) 386
286 return false; 387 static inline bool multiply(int64_t lhs, int64_t rhs, ResultType& result) {
287 } else { 388 int64_t temp = lhs * rhs;
288 if (lhs && rhs < (std::numeric_limits<ResultType>::min() / lhs)) 389 if (temp < std::numeric_limits<ResultType>::min())
289 return false; 390 return false;
290 } 391 if (temp > std::numeric_limits<ResultType>::max())
291 } 392 return false;
292 result = static_cast<ResultType>(lhs * rhs); 393 result = static_cast<ResultType>(temp);
293 return true; 394 return true;
294 } 395 }
295 396
296 static inline bool equals(LHS lhs, RHS rhs) { return lhs == rhs; } 397 static inline bool equals(int lhs, unsigned rhs) {
297 398 return static_cast<int64_t>(lhs) == static_cast<int64_t>(rhs);
298 }; 399 }
299 400 };
300 template <typename LHS, typename RHS, typename ResultType> struct ArithmeticOper ations<LHS, RHS, ResultType, false, false> { 401
301 // LHS and RHS are unsigned types so bounds checks are nice and easy 402 template <typename ResultType>
302 static inline bool add(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RET URN 403 struct ArithmeticOperations<unsigned, int, ResultType, false, true> {
303 { 404 static inline bool add(int64_t lhs, int64_t rhs, ResultType& result) {
304 ResultType temp = lhs + rhs; 405 return ArithmeticOperations<int, unsigned, ResultType>::add(rhs, lhs,
305 if (temp < lhs) 406 result);
306 return false; 407 }
307 result = temp; 408
308 return true; 409 static inline bool sub(int64_t lhs, int64_t rhs, ResultType& result) {
309 } 410 return ArithmeticOperations<int, unsigned, ResultType>::sub(lhs, rhs,
310 411 result);
311 static inline bool sub(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RET URN 412 }
312 { 413
313 ResultType temp = lhs - rhs; 414 static inline bool multiply(int64_t lhs, int64_t rhs, ResultType& result) {
314 if (temp > lhs) 415 return ArithmeticOperations<int, unsigned, ResultType>::multiply(rhs, lhs,
315 return false; 416 result);
316 result = temp; 417 }
317 return true; 418
318 } 419 static inline bool equals(unsigned lhs, int rhs) {
319 420 return ArithmeticOperations<int, unsigned, ResultType>::equals(rhs, lhs);
320 static inline bool multiply(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSE D_RETURN 421 }
321 { 422 };
322 if (!lhs || !rhs) { 423
323 result = 0; 424 template <typename U, typename V, typename R>
324 return true; 425 static inline bool safeAdd(U lhs, V rhs, R& result) {
325 } 426 return ArithmeticOperations<U, V, R>::add(lhs, rhs, result);
326 if (std::numeric_limits<ResultType>::max() / lhs < rhs) 427 }
327 return false; 428
328 result = lhs * rhs; 429 template <typename U, typename V, typename R>
329 return true; 430 static inline bool safeSub(U lhs, V rhs, R& result) {
330 } 431 return ArithmeticOperations<U, V, R>::sub(lhs, rhs, result);
331 432 }
332 static inline bool equals(LHS lhs, RHS rhs) { return lhs == rhs; } 433
333 434 template <typename U, typename V, typename R>
334 }; 435 static inline bool safeMultiply(U lhs, V rhs, R& result) {
335 436 return ArithmeticOperations<U, V, R>::multiply(lhs, rhs, result);
336 template <typename ResultType> struct ArithmeticOperations<int, unsigned, Result Type, true, false> { 437 }
337 static inline bool add(int64_t lhs, int64_t rhs, ResultType& result) 438
338 { 439 template <typename U, typename V>
339 int64_t temp = lhs + rhs; 440 static inline bool safeEquals(U lhs, V rhs) {
340 if (temp < std::numeric_limits<ResultType>::min()) 441 return ArithmeticOperations<U, V>::equals(lhs, rhs);
341 return false;
342 if (temp > std::numeric_limits<ResultType>::max())
343 return false;
344 result = static_cast<ResultType>(temp);
345 return true;
346 }
347
348 static inline bool sub(int64_t lhs, int64_t rhs, ResultType& result)
349 {
350 int64_t temp = lhs - rhs;
351 if (temp < std::numeric_limits<ResultType>::min())
352 return false;
353 if (temp > std::numeric_limits<ResultType>::max())
354 return false;
355 result = static_cast<ResultType>(temp);
356 return true;
357 }
358
359 static inline bool multiply(int64_t lhs, int64_t rhs, ResultType& result)
360 {
361 int64_t temp = lhs * rhs;
362 if (temp < std::numeric_limits<ResultType>::min())
363 return false;
364 if (temp > std::numeric_limits<ResultType>::max())
365 return false;
366 result = static_cast<ResultType>(temp);
367 return true;
368 }
369
370 static inline bool equals(int lhs, unsigned rhs)
371 {
372 return static_cast<int64_t>(lhs) == static_cast<int64_t>(rhs);
373 }
374 };
375
376 template <typename ResultType> struct ArithmeticOperations<unsigned, int, Result Type, false, true> {
377 static inline bool add(int64_t lhs, int64_t rhs, ResultType& result)
378 {
379 return ArithmeticOperations<int, unsigned, ResultType>::add(rhs, lhs, re sult);
380 }
381
382 static inline bool sub(int64_t lhs, int64_t rhs, ResultType& result)
383 {
384 return ArithmeticOperations<int, unsigned, ResultType>::sub(lhs, rhs, re sult);
385 }
386
387 static inline bool multiply(int64_t lhs, int64_t rhs, ResultType& result)
388 {
389 return ArithmeticOperations<int, unsigned, ResultType>::multiply(rhs, lh s, result);
390 }
391
392 static inline bool equals(unsigned lhs, int rhs)
393 {
394 return ArithmeticOperations<int, unsigned, ResultType>::equals(rhs, lhs) ;
395 }
396 };
397
398 template <typename U, typename V, typename R> static inline bool safeAdd(U lhs, V rhs, R& result)
399 {
400 return ArithmeticOperations<U, V, R>::add(lhs, rhs, result);
401 }
402
403 template <typename U, typename V, typename R> static inline bool safeSub(U lhs, V rhs, R& result)
404 {
405 return ArithmeticOperations<U, V, R>::sub(lhs, rhs, result);
406 }
407
408 template <typename U, typename V, typename R> static inline bool safeMultiply(U lhs, V rhs, R& result)
409 {
410 return ArithmeticOperations<U, V, R>::multiply(lhs, rhs, result);
411 }
412
413 template <typename U, typename V> static inline bool safeEquals(U lhs, V rhs)
414 {
415 return ArithmeticOperations<U, V>::equals(lhs, rhs);
416 } 442 }
417 443
418 enum ResultOverflowedTag { ResultOverflowed }; 444 enum ResultOverflowedTag { ResultOverflowed };
419 445
420 template <typename T, class OverflowHandler> class Checked : public OverflowHand ler { 446 template <typename T, class OverflowHandler>
421 public: 447 class Checked : public OverflowHandler {
422 template <typename _T, class _OverflowHandler> friend class Checked; 448 public:
423 Checked() 449 template <typename _T, class _OverflowHandler>
424 : m_value(0) 450 friend class Checked;
425 { 451 Checked() : m_value(0) {}
426 } 452
427 453 Checked(ResultOverflowedTag) : m_value(0) { this->overflowed(); }
428 Checked(ResultOverflowedTag) 454
429 : m_value(0) 455 template <typename U>
430 { 456 Checked(U value) {
431 this->overflowed(); 457 if (!isInBounds<T>(value))
432 } 458 this->overflowed();
433 459 m_value = static_cast<T>(value);
434 template <typename U> Checked(U value) 460 }
435 { 461
436 if (!isInBounds<T>(value)) 462 template <typename V>
437 this->overflowed(); 463 Checked(const Checked<T, V>& rhs) : m_value(rhs.m_value) {
438 m_value = static_cast<T>(value); 464 if (rhs.hasOverflowed())
439 } 465 this->overflowed();
440 466 }
441 template <typename V> Checked(const Checked<T, V>& rhs) 467
442 : m_value(rhs.m_value) 468 template <typename U>
443 { 469 Checked(const Checked<U, OverflowHandler>& rhs) : OverflowHandler(rhs) {
444 if (rhs.hasOverflowed()) 470 if (!isInBounds<T>(rhs.m_value))
445 this->overflowed(); 471 this->overflowed();
446 } 472 m_value = static_cast<T>(rhs.m_value);
447 473 }
448 template <typename U> Checked(const Checked<U, OverflowHandler>& rhs) 474
449 : OverflowHandler(rhs) 475 template <typename U, typename V>
450 { 476 Checked(const Checked<U, V>& rhs) {
451 if (!isInBounds<T>(rhs.m_value)) 477 if (rhs.hasOverflowed())
452 this->overflowed(); 478 this->overflowed();
453 m_value = static_cast<T>(rhs.m_value); 479 if (!isInBounds<T>(rhs.m_value))
454 } 480 this->overflowed();
455 481 m_value = static_cast<T>(rhs.m_value);
456 template <typename U, typename V> Checked(const Checked<U, V>& rhs) 482 }
457 { 483
458 if (rhs.hasOverflowed()) 484 const Checked& operator=(Checked rhs) {
459 this->overflowed(); 485 this->clearOverflow();
460 if (!isInBounds<T>(rhs.m_value)) 486 if (rhs.hasOverflowed())
461 this->overflowed(); 487 this->overflowed();
462 m_value = static_cast<T>(rhs.m_value); 488 m_value = static_cast<T>(rhs.m_value);
463 } 489 return *this;
464 490 }
465 const Checked& operator=(Checked rhs) 491
466 { 492 template <typename U>
467 this->clearOverflow(); 493 const Checked& operator=(U value) {
468 if (rhs.hasOverflowed()) 494 return *this = Checked(value);
469 this->overflowed(); 495 }
470 m_value = static_cast<T>(rhs.m_value); 496
471 return *this; 497 template <typename U, typename V>
472 } 498 const Checked& operator=(const Checked<U, V>& rhs) {
473 499 return *this = Checked(rhs);
474 template <typename U> const Checked& operator=(U value) 500 }
475 { 501
476 return *this = Checked(value); 502 // prefix
477 } 503 const Checked& operator++() {
478 504 if (m_value == std::numeric_limits<T>::max())
479 template <typename U, typename V> const Checked& operator=(const Checked<U, V>& rhs) 505 this->overflowed();
480 { 506 m_value++;
481 return *this = Checked(rhs); 507 return *this;
482 } 508 }
483 509
484 // prefix 510 const Checked& operator--() {
485 const Checked& operator++() 511 if (m_value == std::numeric_limits<T>::min())
486 { 512 this->overflowed();
487 if (m_value == std::numeric_limits<T>::max()) 513 m_value--;
488 this->overflowed(); 514 return *this;
489 m_value++; 515 }
490 return *this; 516
491 } 517 // postfix operators
492 518 const Checked operator++(int) {
493 const Checked& operator--() 519 if (m_value == std::numeric_limits<T>::max())
494 { 520 this->overflowed();
495 if (m_value == std::numeric_limits<T>::min()) 521 return Checked(m_value++);
496 this->overflowed(); 522 }
497 m_value--; 523
498 return *this; 524 const Checked operator--(int) {
499 } 525 if (m_value == std::numeric_limits<T>::min())
500 526 this->overflowed();
501 // postfix operators 527 return Checked(m_value--);
502 const Checked operator++(int) 528 }
503 { 529
504 if (m_value == std::numeric_limits<T>::max()) 530 // Boolean operators
505 this->overflowed(); 531 bool operator!() const {
506 return Checked(m_value++); 532 if (this->hasOverflowed())
507 } 533 CRASH();
508 534 return !m_value;
509 const Checked operator--(int) 535 }
510 { 536
511 if (m_value == std::numeric_limits<T>::min()) 537 typedef void*(Checked::*UnspecifiedBoolType);
512 this->overflowed(); 538 operator UnspecifiedBoolType*() const {
513 return Checked(m_value--); 539 if (this->hasOverflowed())
514 } 540 CRASH();
515 541 return (m_value) ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0;
516 // Boolean operators 542 }
517 bool operator!() const 543
518 { 544 // Value accessors. unsafeGet() will crash if there's been an overflow.
519 if (this->hasOverflowed()) 545 T unsafeGet() const {
520 CRASH(); 546 if (this->hasOverflowed())
521 return !m_value; 547 CRASH();
522 } 548 return m_value;
523 549 }
524 typedef void* (Checked::*UnspecifiedBoolType); 550
525 operator UnspecifiedBoolType*() const 551 inline CheckedState safeGet(T& value) const WARN_UNUSED_RETURN {
526 { 552 value = m_value;
527 if (this->hasOverflowed()) 553 if (this->hasOverflowed())
528 CRASH(); 554 return CheckedState::DidOverflow;
529 return (m_value) ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; 555 return CheckedState::DidNotOverflow;
530 } 556 }
531 557
532 // Value accessors. unsafeGet() will crash if there's been an overflow. 558 // Mutating assignment
533 T unsafeGet() const 559 template <typename U>
534 { 560 const Checked operator+=(U rhs) {
535 if (this->hasOverflowed()) 561 if (!safeAdd(m_value, rhs, m_value))
536 CRASH(); 562 this->overflowed();
537 return m_value; 563 return *this;
538 } 564 }
539 565
540 inline CheckedState safeGet(T& value) const WARN_UNUSED_RETURN 566 template <typename U>
541 { 567 const Checked operator-=(U rhs) {
542 value = m_value; 568 if (!safeSub(m_value, rhs, m_value))
543 if (this->hasOverflowed()) 569 this->overflowed();
544 return CheckedState::DidOverflow; 570 return *this;
545 return CheckedState::DidNotOverflow; 571 }
546 } 572
547 573 template <typename U>
548 // Mutating assignment 574 const Checked operator*=(U rhs) {
549 template <typename U> const Checked operator+=(U rhs) 575 if (!safeMultiply(m_value, rhs, m_value))
550 { 576 this->overflowed();
551 if (!safeAdd(m_value, rhs, m_value)) 577 return *this;
552 this->overflowed(); 578 }
553 return *this; 579
554 } 580 const Checked operator*=(double rhs) {
555 581 double result = rhs * m_value;
556 template <typename U> const Checked operator-=(U rhs) 582 // Handle +/- infinity and NaN
557 { 583 if (!(std::numeric_limits<T>::min() <= result &&
558 if (!safeSub(m_value, rhs, m_value)) 584 std::numeric_limits<T>::max() >= result))
559 this->overflowed(); 585 this->overflowed();
560 return *this; 586 m_value = (T)result;
561 } 587 return *this;
562 588 }
563 template <typename U> const Checked operator*=(U rhs) 589
564 { 590 const Checked operator*=(float rhs) { return *this *= (double)rhs; }
565 if (!safeMultiply(m_value, rhs, m_value)) 591
566 this->overflowed(); 592 template <typename U, typename V>
567 return *this; 593 const Checked operator+=(Checked<U, V> rhs) {
568 } 594 if (rhs.hasOverflowed())
569 595 this->overflowed();
570 const Checked operator*=(double rhs) 596 return *this += rhs.m_value;
571 { 597 }
572 double result = rhs * m_value; 598
573 // Handle +/- infinity and NaN 599 template <typename U, typename V>
574 if (!(std::numeric_limits<T>::min() <= result && std::numeric_limits<T>: :max() >= result)) 600 const Checked operator-=(Checked<U, V> rhs) {
575 this->overflowed(); 601 if (rhs.hasOverflowed())
576 m_value = (T)result; 602 this->overflowed();
577 return *this; 603 return *this -= rhs.m_value;
578 } 604 }
579 605
580 const Checked operator*=(float rhs) 606 template <typename U, typename V>
581 { 607 const Checked operator*=(Checked<U, V> rhs) {
582 return *this *= (double)rhs; 608 if (rhs.hasOverflowed())
583 } 609 this->overflowed();
584 610 return *this *= rhs.m_value;
585 template <typename U, typename V> const Checked operator+=(Checked<U, V> rhs ) 611 }
586 { 612
587 if (rhs.hasOverflowed()) 613 // Equality comparisons
588 this->overflowed(); 614 template <typename V>
589 return *this += rhs.m_value; 615 bool operator==(Checked<T, V> rhs) {
590 } 616 return unsafeGet() == rhs.unsafeGet();
591 617 }
592 template <typename U, typename V> const Checked operator-=(Checked<U, V> rhs ) 618
593 { 619 template <typename U>
594 if (rhs.hasOverflowed()) 620 bool operator==(U rhs) {
595 this->overflowed(); 621 if (this->hasOverflowed())
596 return *this -= rhs.m_value; 622 this->overflowed();
597 } 623 return safeEquals(m_value, rhs);
598 624 }
599 template <typename U, typename V> const Checked operator*=(Checked<U, V> rhs ) 625
600 { 626 template <typename U, typename V>
601 if (rhs.hasOverflowed()) 627 const Checked operator==(Checked<U, V> rhs) {
602 this->overflowed(); 628 return unsafeGet() == Checked(rhs.unsafeGet());
603 return *this *= rhs.m_value; 629 }
604 } 630
605 631 template <typename U>
606 // Equality comparisons 632 bool operator!=(U rhs) {
607 template <typename V> bool operator==(Checked<T, V> rhs) 633 return !(*this == rhs);
608 { 634 }
609 return unsafeGet() == rhs.unsafeGet(); 635
610 } 636 private:
611 637 // Disallow implicit conversion of floating point to integer types
612 template <typename U> bool operator==(U rhs) 638 Checked(float);
613 { 639 Checked(double);
614 if (this->hasOverflowed()) 640 void operator=(float);
615 this->overflowed(); 641 void operator=(double);
616 return safeEquals(m_value, rhs); 642 void operator+=(float);
617 } 643 void operator+=(double);
618 644 void operator-=(float);
619 template <typename U, typename V> const Checked operator==(Checked<U, V> rhs ) 645 void operator-=(double);
620 { 646 T m_value;
621 return unsafeGet() == Checked(rhs.unsafeGet()); 647 };
622 } 648
623 649 template <typename U, typename V, typename OverflowHandler>
624 template <typename U> bool operator!=(U rhs) 650 static inline Checked<typename Result<U, V>::ResultType, OverflowHandler>
625 { 651 operator+(Checked<U, OverflowHandler> lhs, Checked<V, OverflowHandler> rhs) {
626 return !(*this == rhs); 652 U x = 0;
627 } 653 V y = 0;
628 654 bool overflowed = lhs.safeGet(x) == CheckedState::DidOverflow ||
629 private: 655 rhs.safeGet(y) == CheckedState::DidOverflow;
630 // Disallow implicit conversion of floating point to integer types 656 typename Result<U, V>::ResultType result = 0;
631 Checked(float); 657 overflowed |= !safeAdd(x, y, result);
632 Checked(double); 658 if (overflowed)
633 void operator=(float); 659 return ResultOverflowed;
634 void operator=(double); 660 return result;
635 void operator+=(float); 661 }
636 void operator+=(double); 662
637 void operator-=(float); 663 template <typename U, typename V, typename OverflowHandler>
638 void operator-=(double); 664 static inline Checked<typename Result<U, V>::ResultType, OverflowHandler>
639 T m_value; 665 operator-(Checked<U, OverflowHandler> lhs, Checked<V, OverflowHandler> rhs) {
640 }; 666 U x = 0;
641 667 V y = 0;
642 template <typename U, typename V, typename OverflowHandler> static inline Checke d<typename Result<U, V>::ResultType, OverflowHandler> operator+(Checked<U, Overf lowHandler> lhs, Checked<V, OverflowHandler> rhs) 668 bool overflowed = lhs.safeGet(x) == CheckedState::DidOverflow ||
643 { 669 rhs.safeGet(y) == CheckedState::DidOverflow;
644 U x = 0; 670 typename Result<U, V>::ResultType result = 0;
645 V y = 0; 671 overflowed |= !safeSub(x, y, result);
646 bool overflowed = lhs.safeGet(x) == CheckedState::DidOverflow || rhs.safeGet (y) == CheckedState::DidOverflow; 672 if (overflowed)
647 typename Result<U, V>::ResultType result = 0; 673 return ResultOverflowed;
648 overflowed |= !safeAdd(x, y, result); 674 return result;
649 if (overflowed) 675 }
650 return ResultOverflowed; 676
651 return result; 677 template <typename U, typename V, typename OverflowHandler>
652 } 678 static inline Checked<typename Result<U, V>::ResultType, OverflowHandler>
653 679 operator*(Checked<U, OverflowHandler> lhs, Checked<V, OverflowHandler> rhs) {
654 template <typename U, typename V, typename OverflowHandler> static inline Checke d<typename Result<U, V>::ResultType, OverflowHandler> operator-(Checked<U, Overf lowHandler> lhs, Checked<V, OverflowHandler> rhs) 680 U x = 0;
655 { 681 V y = 0;
656 U x = 0; 682 bool overflowed = lhs.safeGet(x) == CheckedState::DidOverflow ||
657 V y = 0; 683 rhs.safeGet(y) == CheckedState::DidOverflow;
658 bool overflowed = lhs.safeGet(x) == CheckedState::DidOverflow || rhs.safeGet (y) == CheckedState::DidOverflow; 684 typename Result<U, V>::ResultType result = 0;
659 typename Result<U, V>::ResultType result = 0; 685 overflowed |= !safeMultiply(x, y, result);
660 overflowed |= !safeSub(x, y, result); 686 if (overflowed)
661 if (overflowed) 687 return ResultOverflowed;
662 return ResultOverflowed; 688 return result;
663 return result; 689 }
664 } 690
665 691 template <typename U, typename V, typename OverflowHandler>
666 template <typename U, typename V, typename OverflowHandler> static inline Checke d<typename Result<U, V>::ResultType, OverflowHandler> operator*(Checked<U, Overf lowHandler> lhs, Checked<V, OverflowHandler> rhs) 692 static inline Checked<typename Result<U, V>::ResultType, OverflowHandler>
667 { 693 operator+(Checked<U, OverflowHandler> lhs, V rhs) {
668 U x = 0; 694 return lhs + Checked<V, OverflowHandler>(rhs);
669 V y = 0; 695 }
670 bool overflowed = lhs.safeGet(x) == CheckedState::DidOverflow || rhs.safeGet (y) == CheckedState::DidOverflow; 696
671 typename Result<U, V>::ResultType result = 0; 697 template <typename U, typename V, typename OverflowHandler>
672 overflowed |= !safeMultiply(x, y, result); 698 static inline Checked<typename Result<U, V>::ResultType, OverflowHandler>
673 if (overflowed) 699 operator-(Checked<U, OverflowHandler> lhs, V rhs) {
674 return ResultOverflowed; 700 return lhs - Checked<V, OverflowHandler>(rhs);
675 return result; 701 }
676 } 702
677 703 template <typename U, typename V, typename OverflowHandler>
678 template <typename U, typename V, typename OverflowHandler> static inline Checke d<typename Result<U, V>::ResultType, OverflowHandler> operator+(Checked<U, Overf lowHandler> lhs, V rhs) 704 static inline Checked<typename Result<U, V>::ResultType, OverflowHandler>
679 { 705 operator*(Checked<U, OverflowHandler> lhs, V rhs) {
680 return lhs + Checked<V, OverflowHandler>(rhs); 706 return lhs * Checked<V, OverflowHandler>(rhs);
681 } 707 }
682 708
683 template <typename U, typename V, typename OverflowHandler> static inline Checke d<typename Result<U, V>::ResultType, OverflowHandler> operator-(Checked<U, Overf lowHandler> lhs, V rhs) 709 template <typename U, typename V, typename OverflowHandler>
684 { 710 static inline Checked<typename Result<U, V>::ResultType, OverflowHandler>
685 return lhs - Checked<V, OverflowHandler>(rhs); 711 operator+(U lhs, Checked<V, OverflowHandler> rhs) {
686 } 712 return Checked<U, OverflowHandler>(lhs) + rhs;
687 713 }
688 template <typename U, typename V, typename OverflowHandler> static inline Checke d<typename Result<U, V>::ResultType, OverflowHandler> operator*(Checked<U, Overf lowHandler> lhs, V rhs) 714
689 { 715 template <typename U, typename V, typename OverflowHandler>
690 return lhs * Checked<V, OverflowHandler>(rhs); 716 static inline Checked<typename Result<U, V>::ResultType, OverflowHandler>
691 } 717 operator-(U lhs, Checked<V, OverflowHandler> rhs) {
692 718 return Checked<U, OverflowHandler>(lhs) - rhs;
693 template <typename U, typename V, typename OverflowHandler> static inline Checke d<typename Result<U, V>::ResultType, OverflowHandler> operator+(U lhs, Checked<V , OverflowHandler> rhs) 719 }
694 { 720
695 return Checked<U, OverflowHandler>(lhs) + rhs; 721 template <typename U, typename V, typename OverflowHandler>
696 } 722 static inline Checked<typename Result<U, V>::ResultType, OverflowHandler>
697 723 operator*(U lhs, Checked<V, OverflowHandler> rhs) {
698 template <typename U, typename V, typename OverflowHandler> static inline Checke d<typename Result<U, V>::ResultType, OverflowHandler> operator-(U lhs, Checked<V , OverflowHandler> rhs) 724 return Checked<U, OverflowHandler>(lhs) * rhs;
699 { 725 }
700 return Checked<U, OverflowHandler>(lhs) - rhs;
701 }
702
703 template <typename U, typename V, typename OverflowHandler> static inline Checke d<typename Result<U, V>::ResultType, OverflowHandler> operator*(U lhs, Checked<V , OverflowHandler> rhs)
704 {
705 return Checked<U, OverflowHandler>(lhs) * rhs;
706 }
707
708 } 726 }
709 727
710 using WTF::Checked; 728 using WTF::Checked;
711 using WTF::CheckedState; 729 using WTF::CheckedState;
712 using WTF::RecordOverflow; 730 using WTF::RecordOverflow;
713 731
714 #endif 732 #endif
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/wtf/CPU.h ('k') | third_party/WebKit/Source/wtf/CheckedArithmeticTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698