OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef BASE_NUMERICS_SAFE_MATH_H_ | 5 #ifndef BASE_NUMERICS_SAFE_MATH_H_ |
6 #define BASE_NUMERICS_SAFE_MATH_H_ | 6 #define BASE_NUMERICS_SAFE_MATH_H_ |
7 | 7 |
8 #include <stddef.h> | 8 #include <stddef.h> |
9 | 9 |
10 #include <limits> | 10 #include <limits> |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
178 template <typename Src> | 178 template <typename Src> |
179 static CheckedNumeric<T> cast( | 179 static CheckedNumeric<T> cast( |
180 const CheckedNumeric<Src>& u, | 180 const CheckedNumeric<Src>& u, |
181 typename std::enable_if<!std::is_same<Src, T>::value, int>::type = 0) { | 181 typename std::enable_if<!std::is_same<Src, T>::value, int>::type = 0) { |
182 return u; | 182 return u; |
183 } | 183 } |
184 | 184 |
185 static const CheckedNumeric<T>& cast(const CheckedNumeric<T>& u) { return u; } | 185 static const CheckedNumeric<T>& cast(const CheckedNumeric<T>& u) { return u; } |
186 | 186 |
187 private: | 187 private: |
188 template <typename NumericType> | |
189 struct UnderlyingType { | |
190 using type = NumericType; | |
191 }; | |
192 | |
193 template <typename NumericType> | |
194 struct UnderlyingType<CheckedNumeric<NumericType>> { | |
195 using type = NumericType; | |
196 }; | |
197 | |
198 CheckedNumericState<T> state_; | 188 CheckedNumericState<T> state_; |
199 }; | 189 }; |
200 | 190 |
201 // This is the boilerplate for the standard arithmetic operator overloads. A | 191 // This is the boilerplate for the standard arithmetic operator overloads. A |
202 // macro isn't the prettiest solution, but it beats rewriting these five times. | 192 // macro isn't the prettiest solution, but it beats rewriting these five times. |
203 // Some details worth noting are: | 193 // Some details worth noting are: |
204 // * We apply the standard arithmetic promotions. | 194 // * We apply the standard arithmetic promotions. |
205 // * We skip range checks for floating points. | 195 // * We skip range checks for floating points. |
206 // * We skip range checks for destination integers with sufficient range. | 196 // * We skip range checks for destination integers with sufficient range. |
207 // TODO(jschuh): extract these out into templates. | 197 // TODO(jschuh): extract these out into templates. |
208 #define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME, OP, COMPOUND_OP) \ | 198 #define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME, OP, COMPOUND_OP) \ |
209 /* Binary arithmetic operator for CheckedNumerics of the same type. */ \ | 199 /* Binary arithmetic operator for CheckedNumerics of the same type. */ \ |
210 template <typename T> \ | 200 template <typename L, typename R> \ |
211 CheckedNumeric<typename ArithmeticPromotion<T>::type> operator OP( \ | 201 CheckedNumeric<typename ArithmeticPromotion<L, R>::type> operator OP( \ |
212 const CheckedNumeric<T>& lhs, const CheckedNumeric<T>& rhs) { \ | 202 const CheckedNumeric<L>& lhs, const CheckedNumeric<R>& rhs) { \ |
213 typedef typename ArithmeticPromotion<T>::type Promotion; \ | 203 using P = typename ArithmeticPromotion<L, R>::type; \ |
214 /* Floating point always takes the fast path */ \ | 204 if (!rhs.IsValid() || !lhs.IsValid()) \ |
215 if (std::numeric_limits<T>::is_iec559) \ | 205 return CheckedNumeric<P>(0, false); \ |
216 return CheckedNumeric<T>(lhs.ValueUnsafe() OP rhs.ValueUnsafe()); \ | 206 /* Floating point always takes the fast path */ \ |
217 if (!rhs.IsValid() || !lhs.IsValid()) \ | 207 if (std::is_floating_point<L>::value || std::is_floating_point<R>::value) \ |
218 return CheckedNumeric<Promotion>(0, false); \ | 208 return CheckedNumeric<P>(lhs.ValueUnsafe() OP rhs.ValueUnsafe()); \ |
219 if (IsIntegerArithmeticSafe<Promotion, T, T>::value) \ | 209 P result = 0; \ |
220 return CheckedNumeric<Promotion>(lhs.ValueUnsafe() \ | 210 bool is_valid = \ |
221 OP rhs.ValueUnsafe()); \ | 211 Checked##NAME(lhs.ValueUnsafe(), rhs.ValueUnsafe(), &result); \ |
222 Promotion result = 0; \ | 212 return CheckedNumeric<P>(result, is_valid); \ |
223 bool is_valid = \ | 213 } \ |
224 Checked##NAME(static_cast<Promotion>(lhs.ValueUnsafe()), \ | 214 /* Assignment arithmetic operator implementation from CheckedNumeric. */ \ |
225 static_cast<Promotion>(rhs.ValueUnsafe()), &result); \ | 215 template <typename L> \ |
226 return CheckedNumeric<Promotion>(result, is_valid); \ | 216 template <typename R> \ |
227 } \ | 217 CheckedNumeric<L>& CheckedNumeric<L>::operator COMPOUND_OP(R rhs) { \ |
228 /* Assignment arithmetic operator implementation from CheckedNumeric. */ \ | 218 *this = *this OP rhs; \ |
229 template <typename T> \ | 219 return *this; \ |
230 template <typename Src> \ | 220 } \ |
231 CheckedNumeric<T>& CheckedNumeric<T>::operator COMPOUND_OP(Src rhs) { \ | 221 /* Binary arithmetic operator for left CheckedNumeric and right numeric. */ \ |
232 *this = CheckedNumeric<T>::cast(*this) \ | 222 template <typename L, typename R, \ |
233 OP CheckedNumeric<typename UnderlyingType<Src>::type>::cast(rhs); \ | 223 typename std::enable_if<std::is_arithmetic<R>::value>::type* = \ |
234 return *this; \ | 224 nullptr> \ |
235 } \ | 225 CheckedNumeric<typename ArithmeticPromotion<L, R>::type> operator OP( \ |
236 /* Binary arithmetic operator for CheckedNumeric of different type. */ \ | 226 const CheckedNumeric<L>& lhs, R rhs) { \ |
237 template <typename T, typename Src> \ | 227 return lhs OP CheckedNumeric<R>(rhs); \ |
238 CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP( \ | 228 } \ |
239 const CheckedNumeric<Src>& lhs, const CheckedNumeric<T>& rhs) { \ | 229 /* Binary arithmetic operator for left numeric and right CheckedNumeric. */ \ |
240 typedef typename ArithmeticPromotion<T, Src>::type Promotion; \ | 230 template <typename L, typename R, \ |
241 if (!rhs.IsValid() || !lhs.IsValid()) \ | 231 typename std::enable_if<std::is_arithmetic<L>::value>::type* = \ |
242 return CheckedNumeric<Promotion>(0, false); \ | 232 nullptr> \ |
243 if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \ | 233 CheckedNumeric<typename ArithmeticPromotion<L, R>::type> operator OP( \ |
244 return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP rhs.ValueUnsafe());\ | 234 L lhs, const CheckedNumeric<R>& rhs) { \ |
245 return CheckedNumeric<Promotion>::cast(lhs) \ | 235 return CheckedNumeric<L>(lhs) OP rhs; \ |
246 OP CheckedNumeric<Promotion>::cast(rhs); \ | |
247 } \ | |
248 /* Binary arithmetic operator for left CheckedNumeric and right numeric. */ \ | |
249 template <typename T, typename Src, \ | |
250 typename std::enable_if<std::is_arithmetic<Src>::value>::type* = \ | |
251 nullptr> \ | |
252 CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP( \ | |
253 const CheckedNumeric<T>& lhs, Src rhs) { \ | |
254 typedef typename ArithmeticPromotion<T, Src>::type Promotion; \ | |
255 if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \ | |
256 return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP rhs, \ | |
257 lhs.IsValid()); \ | |
258 return CheckedNumeric<Promotion>::cast(lhs) \ | |
259 OP CheckedNumeric<Promotion>::cast(rhs); \ | |
260 } \ | |
261 /* Binary arithmetic operator for left numeric and right CheckedNumeric. */ \ | |
262 template <typename T, typename Src, \ | |
263 typename std::enable_if<std::is_arithmetic<Src>::value>::type* = \ | |
264 nullptr> \ | |
265 CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP( \ | |
266 Src lhs, const CheckedNumeric<T>& rhs) { \ | |
267 typedef typename ArithmeticPromotion<T, Src>::type Promotion; \ | |
268 if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \ | |
269 return CheckedNumeric<Promotion>(lhs OP rhs.ValueUnsafe(), \ | |
270 rhs.IsValid()); \ | |
271 return CheckedNumeric<Promotion>::cast(lhs) \ | |
272 OP CheckedNumeric<Promotion>::cast(rhs); \ | |
273 } | 236 } |
274 | 237 |
275 BASE_NUMERIC_ARITHMETIC_OPERATORS(Add, +, += ) | 238 BASE_NUMERIC_ARITHMETIC_OPERATORS(Add, +, += ) |
276 BASE_NUMERIC_ARITHMETIC_OPERATORS(Sub, -, -= ) | 239 BASE_NUMERIC_ARITHMETIC_OPERATORS(Sub, -, -= ) |
277 BASE_NUMERIC_ARITHMETIC_OPERATORS(Mul, *, *= ) | 240 BASE_NUMERIC_ARITHMETIC_OPERATORS(Mul, *, *= ) |
278 BASE_NUMERIC_ARITHMETIC_OPERATORS(Div, /, /= ) | 241 BASE_NUMERIC_ARITHMETIC_OPERATORS(Div, /, /= ) |
279 BASE_NUMERIC_ARITHMETIC_OPERATORS(Mod, %, %= ) | 242 BASE_NUMERIC_ARITHMETIC_OPERATORS(Mod, %, %= ) |
280 | 243 |
281 #undef BASE_NUMERIC_ARITHMETIC_OPERATORS | 244 #undef BASE_NUMERIC_ARITHMETIC_OPERATORS |
282 | 245 |
283 } // namespace internal | 246 } // namespace internal |
284 | 247 |
285 using internal::CheckedNumeric; | 248 using internal::CheckedNumeric; |
286 | 249 |
287 } // namespace base | 250 } // namespace base |
288 | 251 |
289 #endif // BASE_NUMERICS_SAFE_MATH_H_ | 252 #endif // BASE_NUMERICS_SAFE_MATH_H_ |
OLD | NEW |