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

Side by Side Diff: base/numerics/safe_math.h

Issue 2496143003: Simplify CheckedNumeric macros (Closed)
Patch Set: nits Created 4 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
« no previous file with comments | « no previous file | base/numerics/safe_math_impl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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_
OLDNEW
« no previous file with comments | « no previous file | base/numerics/safe_math_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698