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

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

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