| OLD | NEW |
| 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 Loading... |
| 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 |
| OLD | NEW |