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

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

Issue 2522543002: Convert simple CheckedNumeric functions to constexpr (Closed)
Patch Set: complete Created 4 years 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 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
66 }; 66 };
67 67
68 template <typename T> 68 template <typename T>
69 class CheckedNumeric { 69 class CheckedNumeric {
70 static_assert(std::is_arithmetic<T>::value, 70 static_assert(std::is_arithmetic<T>::value,
71 "CheckedNumeric<T>: T must be a numeric type."); 71 "CheckedNumeric<T>: T must be a numeric type.");
72 72
73 public: 73 public:
74 typedef T type; 74 typedef T type;
75 75
76 CheckedNumeric() {} 76 constexpr CheckedNumeric() {}
77 77
78 // Copy constructor. 78 // Copy constructor.
79 template <typename Src> 79 template <typename Src>
80 CheckedNumeric(const CheckedNumeric<Src>& rhs) 80 constexpr CheckedNumeric(const CheckedNumeric<Src>& rhs)
81 : state_(rhs.state_.value(), rhs.IsValid()) {} 81 : state_(rhs.state_.value(), rhs.IsValid()) {}
82 82
83 template <typename Src> 83 template <typename Src>
84 friend class CheckedNumeric; 84 friend class CheckedNumeric;
85 85
86 // This is not an explicit constructor because we implicitly upgrade regular 86 // This is not an explicit constructor because we implicitly upgrade regular
87 // numerics to CheckedNumerics to make them easier to use. 87 // numerics to CheckedNumerics to make them easier to use.
88 template <typename Src> 88 template <typename Src>
89 CheckedNumeric(Src value) // NOLINT(runtime/explicit) 89 constexpr CheckedNumeric(Src value) // NOLINT(runtime/explicit)
90 : state_(value) { 90 : state_(value) {
91 static_assert(std::numeric_limits<Src>::is_specialized, 91 static_assert(std::numeric_limits<Src>::is_specialized,
92 "Argument must be numeric."); 92 "Argument must be numeric.");
93 } 93 }
94 94
95 // This is not an explicit constructor because we want a seamless conversion 95 // This is not an explicit constructor because we want a seamless conversion
96 // from StrictNumeric types. 96 // from StrictNumeric types.
97 template <typename Src> 97 template <typename Src>
98 CheckedNumeric(StrictNumeric<Src> value) // NOLINT(runtime/explicit) 98 constexpr CheckedNumeric(
99 : state_(static_cast<Src>(value)) { 99 StrictNumeric<Src> value) // NOLINT(runtime/explicit)
100 } 100 : state_(static_cast<Src>(value)) {}
101 101
102 // IsValid() is the public API to test if a CheckedNumeric is currently valid. 102 // IsValid() is the public API to test if a CheckedNumeric is currently valid.
103 bool IsValid() const { return state_.is_valid(); } 103 constexpr bool IsValid() const { return state_.is_valid(); }
104 104
105 // ValueOrDie() The primary accessor for the underlying value. If the current 105 // ValueOrDie() The primary accessor for the underlying value. If the current
106 // state is not valid it will CHECK and crash. 106 // state is not valid it will CHECK and crash.
107 T ValueOrDie() const { 107 constexpr T ValueOrDie() const {
108 CHECK(IsValid()); 108 return IsValid() ? state_.value() : CheckOnFailure::HandleFailure<T>();
109 return state_.value();
110 } 109 }
111 110
112 // ValueOrDefault(T default_value) A convenience method that returns the 111 // ValueOrDefault(T default_value) A convenience method that returns the
113 // current value if the state is valid, and the supplied default_value for 112 // current value if the state is valid, and the supplied default_value for
114 // any other state. 113 // any other state.
115 T ValueOrDefault(T default_value) const { 114 constexpr T ValueOrDefault(T default_value) const {
116 return IsValid() ? state_.value() : default_value; 115 return IsValid() ? state_.value() : default_value;
117 } 116 }
118 117
119 // ValueFloating() - Since floating point values include their validity state, 118 // ValueFloating() - Since floating point values include their validity state,
120 // we provide an easy method for extracting them directly, without a risk of 119 // we provide an easy method for extracting them directly, without a risk of
121 // crashing on a CHECK. 120 // crashing on a CHECK.
122 T ValueFloating() const { 121 constexpr T ValueFloating() const {
123 static_assert(std::numeric_limits<T>::is_iec559, "Argument must be float."); 122 static_assert(std::numeric_limits<T>::is_iec559, "Argument must be float.");
124 return state_.value(); 123 return state_.value();
125 } 124 }
126 125
127 // This friend method is available solely for providing more detailed logging 126 // This friend method is available solely for providing more detailed logging
128 // in the the tests. Do not implement it in production code, because the 127 // in the the tests. Do not implement it in production code, because the
129 // underlying values may change at any time. 128 // underlying values may change at any time.
130 template <typename U> 129 template <typename U>
131 friend U GetNumericValueForTest(const CheckedNumeric<U>& src); 130 friend U GetNumericValueForTest(const CheckedNumeric<U>& src);
132 131
(...skipping 25 matching lines...) Expand all
158 // Absolute value is always valid for floating point. 157 // Absolute value is always valid for floating point.
159 T value = 0; 158 T value = 0;
160 bool is_valid = (std::numeric_limits<T>::is_iec559 || IsValid()) && 159 bool is_valid = (std::numeric_limits<T>::is_iec559 || IsValid()) &&
161 CheckedAbs(state_.value(), &value); 160 CheckedAbs(state_.value(), &value);
162 return CheckedNumeric<T>(value, is_valid); 161 return CheckedNumeric<T>(value, is_valid);
163 } 162 }
164 163
165 // This function is available only for integral types. It returns an unsigned 164 // This function is available only for integral types. It returns an unsigned
166 // integer of the same width as the source type, containing the absolute value 165 // integer of the same width as the source type, containing the absolute value
167 // of the source, and properly handling signed min. 166 // of the source, and properly handling signed min.
168 CheckedNumeric<typename UnsignedOrFloatForSize<T>::type> UnsignedAbs() const { 167 constexpr CheckedNumeric<typename UnsignedOrFloatForSize<T>::type>
168 UnsignedAbs() const {
169 return CheckedNumeric<typename UnsignedOrFloatForSize<T>::type>( 169 return CheckedNumeric<typename UnsignedOrFloatForSize<T>::type>(
170 SafeUnsignedAbs(state_.value()), state_.is_valid()); 170 SafeUnsignedAbs(state_.value()), state_.is_valid());
171 } 171 }
172 172
173 CheckedNumeric& operator++() { 173 CheckedNumeric& operator++() {
174 *this += 1; 174 *this += 1;
175 return *this; 175 return *this;
176 } 176 }
177 177
178 CheckedNumeric operator++(int) { 178 CheckedNumeric operator++(int) {
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
215 bool is_valid = state_.is_valid() && Wrapper<R>::is_valid(rhs) && 215 bool is_valid = state_.is_valid() && Wrapper<R>::is_valid(rhs) &&
216 Math::Op(state_.value(), Wrapper<R>::value(rhs), &result); 216 Math::Op(state_.value(), Wrapper<R>::value(rhs), &result);
217 *this = CheckedNumeric<T>(result, is_valid); 217 *this = CheckedNumeric<T>(result, is_valid);
218 return *this; 218 return *this;
219 }; 219 };
220 220
221 private: 221 private:
222 CheckedNumericState<T> state_; 222 CheckedNumericState<T> state_;
223 223
224 template <typename Src> 224 template <typename Src>
225 CheckedNumeric(Src value, bool is_valid) : state_(value, is_valid) {} 225 constexpr CheckedNumeric(Src value, bool is_valid)
226 : state_(value, is_valid) {}
226 227
227 // These wrappers allow us to handle state the same way for both 228 // These wrappers allow us to handle state the same way for both
228 // CheckedNumeric and POD arithmetic types. 229 // CheckedNumeric and POD arithmetic types.
229 template <typename Src> 230 template <typename Src>
230 struct Wrapper { 231 struct Wrapper {
231 static bool is_valid(Src) { return true; } 232 static constexpr bool is_valid(Src) { return true; }
232 static Src value(Src value) { return value; } 233 static constexpr Src value(Src value) { return value; }
233 }; 234 };
234 235
235 template <typename Src> 236 template <typename Src>
236 struct Wrapper<CheckedNumeric<Src>> { 237 struct Wrapper<CheckedNumeric<Src>> {
237 static bool is_valid(const CheckedNumeric<Src>& v) { return v.IsValid(); } 238 static constexpr bool is_valid(const CheckedNumeric<Src>& v) {
238 static Src value(const CheckedNumeric<Src>& v) { return v.state_.value(); } 239 return v.IsValid();
240 }
241 static constexpr Src value(const CheckedNumeric<Src>& v) {
242 return v.state_.value();
243 }
239 }; 244 };
240 }; 245 };
241 246
242 // This is just boilerplate for the standard arithmetic operator overloads. 247 // This is just boilerplate for the standard arithmetic operator overloads.
243 // A macro isn't the nicest solution, but it beats rewriting these repeatedly. 248 // A macro isn't the nicest solution, but it beats rewriting these repeatedly.
244 #define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME, OP, COMPOUND_OP) \ 249 #define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME, OP, COMPOUND_OP) \
245 /* Binary arithmetic operator for all CheckedNumeric operations. */ \ 250 /* Binary arithmetic operator for all CheckedNumeric operations. */ \
246 template <typename L, typename R, \ 251 template <typename L, typename R, \
247 typename std::enable_if<UnderlyingType<L>::is_numeric && \ 252 typename std::enable_if<UnderlyingType<L>::is_numeric && \
248 UnderlyingType<R>::is_numeric && \ 253 UnderlyingType<R>::is_numeric && \
(...skipping 23 matching lines...) Expand all
272 277
273 #undef BASE_NUMERIC_ARITHMETIC_OPERATORS 278 #undef BASE_NUMERIC_ARITHMETIC_OPERATORS
274 279
275 } // namespace internal 280 } // namespace internal
276 281
277 using internal::CheckedNumeric; 282 using internal::CheckedNumeric;
278 283
279 } // namespace base 284 } // namespace base
280 285
281 #endif // BASE_NUMERICS_SAFE_MATH_H_ 286 #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