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

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

Issue 2931323002: Split out code to be shared between CheckedNumeric and ClampedNumeric (Closed)
Patch Set: iwyu Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_
6 #define BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_
7
8 #include <stddef.h>
9 #include <stdint.h>
10
11 #include <climits>
12 #include <cmath>
13 #include <cstdlib>
14 #include <limits>
15 #include <type_traits>
16
17 #include "base/numerics/safe_conversions.h"
18
19 namespace base {
20 namespace internal {
21
22 // This is used for UnsignedAbs, where we need to support floating-point
23 // template instantiations even though we don't actually support the operations.
24 // However, there is no corresponding implementation of e.g. SafeUnsignedAbs,
25 // so the float versions will not compile.
26 template <typename Numeric,
27 bool IsInteger = std::is_integral<Numeric>::value,
28 bool IsFloat = std::is_floating_point<Numeric>::value>
29 struct UnsignedOrFloatForSize;
30
31 template <typename Numeric>
32 struct UnsignedOrFloatForSize<Numeric, true, false> {
33 using type = typename std::make_unsigned<Numeric>::type;
34 };
35
36 template <typename Numeric>
37 struct UnsignedOrFloatForSize<Numeric, false, true> {
38 using type = Numeric;
39 };
40
41 // Wrap the unary operations to allow SFINAE when instantiating integrals versus
42 // floating points. These don't perform any overflow checking. Rather, they
43 // exhibit well-defined overflow semantics and rely on the caller to detect
44 // if an overflow occured.
45
46 template <typename T,
47 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
48 constexpr T NegateWrapper(T value) {
49 using UnsignedT = typename std::make_unsigned<T>::type;
50 // This will compile to a NEG on Intel, and is normal negation on ARM.
51 return static_cast<T>(UnsignedT(0) - static_cast<UnsignedT>(value));
52 }
53
54 template <
55 typename T,
56 typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
57 constexpr T NegateWrapper(T value) {
58 return -value;
59 }
60
61 template <typename T,
62 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
63 constexpr typename std::make_unsigned<T>::type InvertWrapper(T value) {
64 return ~value;
65 }
66
67 template <typename T,
68 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
69 constexpr T AbsWrapper(T value) {
70 return static_cast<T>(SafeUnsignedAbs(value));
71 }
72
73 template <
74 typename T,
75 typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
76 constexpr T AbsWrapper(T value) {
77 return value < 0 ? -value : value;
78 }
79
80 template <template <typename, typename, typename> class M,
81 typename L,
82 typename R>
83 struct MathWrapper {
84 using math = M<typename UnderlyingType<L>::type,
85 typename UnderlyingType<R>::type,
86 void>;
87 using type = typename math::result_type;
88 };
89
90 // These variadic templates work out the return types.
91 // TODO(jschuh): Rip all this out once we have C++14 non-trailing auto support.
92 template <template <typename, typename, typename> class M,
93 typename L,
94 typename R,
95 typename... Args>
96 struct ResultType;
97
98 template <template <typename, typename, typename> class M,
99 typename L,
100 typename R>
101 struct ResultType<M, L, R> {
102 using type = typename MathWrapper<M, L, R>::type;
103 };
104
105 template <template <typename, typename, typename> class M,
106 typename L,
107 typename R,
108 typename... Args>
109 struct ResultType {
110 using type =
111 typename ResultType<M, typename ResultType<M, L, R>::type, Args...>::type;
112 };
113
114 // The following macros are just boilerplate for the standard arithmetic
115 // operator overloads and variadic function templates. A macro isn't the nicest
116 // solution, but it beats rewriting these over and over again.
117 #define BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME) \
118 template <typename L, typename R, typename... Args> \
119 CLASS##Numeric<typename ResultType<CLASS##OP_NAME##Op, L, R, Args...>::type> \
120 CL_ABBR##OP_NAME(const L lhs, const R rhs, const Args... args) { \
121 return ChkMathOp<CLASS##OP_NAME##Op, L, R, Args...>(lhs, rhs, args...); \
122 }
123
124 #define BASE_NUMERIC_ARITHMETIC_OPERATORS(CLASS, CL_ABBR, OP_NAME, OP, CMP_OP) \
125 /* Binary arithmetic operator for all CheckedNumeric operations. */ \
126 template <typename L, typename R, \
127 typename std::enable_if<IsCheckedOp<L, R>::value>::type* = \
128 nullptr> \
129 CheckedNumeric<typename MathWrapper<CLASS##OP_NAME##Op, L, R>::type> \
130 operator OP(const L lhs, const R rhs) { \
131 return decltype(lhs OP rhs)::template MathOp<CLASS##OP_NAME##Op>(lhs, \
132 rhs); \
133 } \
134 /* Assignment arithmetic operator implementation from CheckedNumeric. */ \
135 template <typename L> \
136 template <typename R> \
137 CheckedNumeric<L>& CheckedNumeric<L>::operator CMP_OP(const R rhs) { \
138 return MathOp<CLASS##OP_NAME##Op>(rhs); \
139 } \
140 /* Variadic arithmetic functions that return CheckedNumeric. */ \
141 BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME)
142
143 } // namespace internal
144 } // namespace base
145
146 #endif // BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_
OLDNEW
« base/numerics/checked_math_impl.h ('K') | « base/numerics/safe_math_impl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698