blob: 270d5916b983b102a9247c51100a3ad1f85f78d5 [file] [log] [blame]
[email protected]4efb2c32014-01-16 06:57:251// Copyright 2014 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
danakj0a448602015-03-10 00:31:165#ifndef BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
6#define BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
[email protected]4efb2c32014-01-16 06:57:257
avi9b6f42932015-12-26 22:15:148#include <stdint.h>
9
rickyzd2fe3e242016-05-10 13:47:3710#include <limits>
thomasanderson61500f22016-08-31 01:30:3711#include <type_traits>
rickyzd2fe3e242016-05-10 13:47:3712
[email protected]4efb2c32014-01-16 06:57:2513namespace base {
14namespace internal {
15
[email protected]5bfecbc52014-02-27 13:49:0416// The std library doesn't provide a binary max_exponent for integers, however
jschuh5030b00c2016-12-05 18:21:4817// we can compute an analog using std::numeric_limits<>::digits.
[email protected]5bfecbc52014-02-27 13:49:0418template <typename NumericType>
19struct MaxExponent {
jschuh5030b00c2016-12-05 18:21:4820 static const int value = std::is_floating_point<NumericType>::value
[email protected]5bfecbc52014-02-27 13:49:0421 ? std::numeric_limits<NumericType>::max_exponent
jschuh5030b00c2016-12-05 18:21:4822 : std::numeric_limits<NumericType>::digits + 1;
23};
24
25// The number of bits (including the sign) in an integer. Eliminates sizeof
26// hacks.
27template <typename NumericType>
28struct IntegerBitsPlusSign {
29 static const int value = std::numeric_limits<NumericType>::digits +
30 std::is_signed<NumericType>::value;
[email protected]4efb2c32014-01-16 06:57:2531};
32
jschuhba3c4f942016-12-10 14:03:5533// Helper templates for integer manipulations.
34
35template <typename Integer>
36struct PositionOfSignBit {
37 static const size_t value = IntegerBitsPlusSign<Integer>::value - 1;
38};
39
40template <typename T>
41constexpr bool HasSignBit(T x) {
42 // Cast to unsigned since right shift on signed is undefined.
43 return !!(static_cast<typename std::make_unsigned<T>::type>(x) >>
44 PositionOfSignBit<T>::value);
45}
46
47// This wrapper undoes the standard integer promotions.
48template <typename T>
49constexpr T BinaryComplement(T x) {
50 return static_cast<T>(~x);
51}
52
jschuh71b669a2016-12-17 01:13:3153// Determines if a numeric value is negative without throwing compiler
54// warnings on: unsigned(value) < 0.
55template <typename T,
56 typename std::enable_if<std::is_signed<T>::value>::type* = nullptr>
57constexpr bool IsValueNegative(T value) {
58 static_assert(std::is_arithmetic<T>::value, "Argument must be numeric.");
59 return value < 0;
60}
61
62template <typename T,
63 typename std::enable_if<!std::is_signed<T>::value>::type* = nullptr>
64constexpr bool IsValueNegative(T) {
65 static_assert(std::is_arithmetic<T>::value, "Argument must be numeric.");
66 return false;
67}
68
69// This performs a fast negation, returning a signed value. It works on unsigned
70// arguments, but probably doesn't do what you want for any unsigned value
71// larger than max / 2 + 1 (i.e. signed min cast to unsigned).
72template <typename T>
73constexpr typename std::make_signed<T>::type ConditionalNegate(
74 T x,
75 bool is_negative) {
76 static_assert(std::is_integral<T>::value, "Type must be integral");
77 using SignedT = typename std::make_signed<T>::type;
78 using UnsignedT = typename std::make_unsigned<T>::type;
79 return static_cast<SignedT>(
80 (static_cast<UnsignedT>(x) ^ -SignedT(is_negative)) + is_negative);
81}
82
jschuhba3c4f942016-12-10 14:03:5583// This performs a safe, non-branching absolute value via unsigned overflow.
84template <typename T>
85constexpr T SafeUnsignedAbsImpl(T value, T sign_mask) {
86 static_assert(!std::is_signed<T>::value, "Types must be unsigned.");
jschuhe2d3dd92016-12-13 02:41:1387 return (value ^ sign_mask) - sign_mask;
jschuhba3c4f942016-12-10 14:03:5588}
89
90template <typename T,
91 typename std::enable_if<std::is_integral<T>::value &&
92 std::is_signed<T>::value>::type* = nullptr>
93constexpr typename std::make_unsigned<T>::type SafeUnsignedAbs(T value) {
94 using UnsignedT = typename std::make_unsigned<T>::type;
95 return SafeUnsignedAbsImpl(
96 static_cast<UnsignedT>(value),
97 // The sign mask is all ones for negative and zero otherwise.
98 static_cast<UnsignedT>(-static_cast<T>(HasSignBit(value))));
99}
100
101template <typename T,
102 typename std::enable_if<std::is_integral<T>::value &&
103 !std::is_signed<T>::value>::type* = nullptr>
104constexpr T SafeUnsignedAbs(T value) {
105 // T is unsigned, so |value| must already be positive.
106 return static_cast<T>(value);
107}
108
[email protected]5bfecbc52014-02-27 13:49:04109enum IntegerRepresentation {
110 INTEGER_REPRESENTATION_UNSIGNED,
111 INTEGER_REPRESENTATION_SIGNED
[email protected]4efb2c32014-01-16 06:57:25112};
113
[email protected]5bfecbc52014-02-27 13:49:04114// A range for a given nunmeric Src type is contained for a given numeric Dst
115// type if both numeric_limits<Src>::max() <= numeric_limits<Dst>::max() and
jschuh5030b00c2016-12-05 18:21:48116// numeric_limits<Src>::lowest() >= numeric_limits<Dst>::lowest() are true.
[email protected]5bfecbc52014-02-27 13:49:04117// We implement this as template specializations rather than simple static
118// comparisons to ensure type correctness in our comparisons.
119enum NumericRangeRepresentation {
120 NUMERIC_RANGE_NOT_CONTAINED,
121 NUMERIC_RANGE_CONTAINED
[email protected]4efb2c32014-01-16 06:57:25122};
123
124// Helper templates to statically determine if our destination type can contain
[email protected]5bfecbc52014-02-27 13:49:04125// maximum and minimum values represented by the source type.
[email protected]4efb2c32014-01-16 06:57:25126
jschuh5030b00c2016-12-05 18:21:48127template <typename Dst,
128 typename Src,
129 IntegerRepresentation DstSign = std::is_signed<Dst>::value
130 ? INTEGER_REPRESENTATION_SIGNED
131 : INTEGER_REPRESENTATION_UNSIGNED,
132 IntegerRepresentation SrcSign = std::is_signed<Src>::value
133 ? INTEGER_REPRESENTATION_SIGNED
134 : INTEGER_REPRESENTATION_UNSIGNED>
[email protected]5bfecbc52014-02-27 13:49:04135struct StaticDstRangeRelationToSrcRange;
[email protected]4efb2c32014-01-16 06:57:25136
[email protected]5bfecbc52014-02-27 13:49:04137// Same sign: Dst is guaranteed to contain Src only if its range is equal or
138// larger.
139template <typename Dst, typename Src, IntegerRepresentation Sign>
140struct StaticDstRangeRelationToSrcRange<Dst, Src, Sign, Sign> {
141 static const NumericRangeRepresentation value =
142 MaxExponent<Dst>::value >= MaxExponent<Src>::value
143 ? NUMERIC_RANGE_CONTAINED
144 : NUMERIC_RANGE_NOT_CONTAINED;
145};
146
147// Unsigned to signed: Dst is guaranteed to contain source only if its range is
148// larger.
[email protected]4efb2c32014-01-16 06:57:25149template <typename Dst, typename Src>
[email protected]5bfecbc52014-02-27 13:49:04150struct StaticDstRangeRelationToSrcRange<Dst,
151 Src,
152 INTEGER_REPRESENTATION_SIGNED,
153 INTEGER_REPRESENTATION_UNSIGNED> {
154 static const NumericRangeRepresentation value =
155 MaxExponent<Dst>::value > MaxExponent<Src>::value
156 ? NUMERIC_RANGE_CONTAINED
157 : NUMERIC_RANGE_NOT_CONTAINED;
[email protected]4efb2c32014-01-16 06:57:25158};
159
[email protected]5bfecbc52014-02-27 13:49:04160// Signed to unsigned: Dst cannot be statically determined to contain Src.
[email protected]4efb2c32014-01-16 06:57:25161template <typename Dst, typename Src>
[email protected]5bfecbc52014-02-27 13:49:04162struct StaticDstRangeRelationToSrcRange<Dst,
163 Src,
164 INTEGER_REPRESENTATION_UNSIGNED,
165 INTEGER_REPRESENTATION_SIGNED> {
166 static const NumericRangeRepresentation value = NUMERIC_RANGE_NOT_CONTAINED;
[email protected]4efb2c32014-01-16 06:57:25167};
168
jschuh3e898ba2016-12-19 21:13:25169enum RangeConstraint {
jschuhe3bd1f62016-12-20 05:11:30170 RANGE_VALID = 0x0, // Value can be represented by the destination type.
171 RANGE_UNDERFLOW = 0x1, // Value would underflow.
172 RANGE_OVERFLOW = 0x2, // Value would overflow.
[email protected]5bfecbc52014-02-27 13:49:04173 RANGE_INVALID = RANGE_UNDERFLOW | RANGE_OVERFLOW // Invalid (i.e. NaN).
[email protected]4efb2c32014-01-16 06:57:25174};
175
jschuhe3bd1f62016-12-20 05:11:30176// This class wraps the range constraints as separate booleans so the compiler
177// can identify constants and eliminate unused code paths.
178class RangeCheck {
179 public:
180 constexpr RangeCheck(bool is_in_upper_bound, bool is_in_lower_bound)
181 : is_overflow_(!is_in_upper_bound), is_underflow_(!is_in_lower_bound) {}
182 constexpr RangeCheck() : is_overflow_(0), is_underflow_(0) {}
183 constexpr bool IsValid() const { return !is_overflow_ && !is_underflow_; }
184 constexpr bool IsInvalid() const { return is_overflow_ && is_underflow_; }
185 constexpr bool IsOverflow() const { return is_overflow_ && !is_underflow_; }
186 constexpr bool IsUnderflow() const { return !is_overflow_ && is_underflow_; }
[email protected]4efb2c32014-01-16 06:57:25187
jschuhe3bd1f62016-12-20 05:11:30188 // These are some wrappers to make the tests a bit cleaner.
189 constexpr operator RangeConstraint() const {
190 return static_cast<RangeConstraint>(static_cast<int>(is_overflow_) << 1 |
191 static_cast<int>(is_underflow_));
192 }
193 constexpr bool operator==(const RangeConstraint rhs) const {
194 return rhs == static_cast<RangeConstraint>(*this);
195 }
196
197 private:
198 const bool is_overflow_;
199 const bool is_underflow_;
200};
[email protected]4efb2c32014-01-16 06:57:25201
jschuhfafe0712015-09-14 20:21:24202// The following helper template addresses a corner case in range checks for
203// conversion from a floating-point type to an integral type of smaller range
204// but larger precision (e.g. float -> unsigned). The problem is as follows:
205// 1. Integral maximum is always one less than a power of two, so it must be
206// truncated to fit the mantissa of the floating point. The direction of
207// rounding is implementation defined, but by default it's always IEEE
208// floats, which round to nearest and thus result in a value of larger
209// magnitude than the integral value.
210// Example: float f = UINT_MAX; // f is 4294967296f but UINT_MAX
211// // is 4294967295u.
212// 2. If the floating point value is equal to the promoted integral maximum
213// value, a range check will erroneously pass.
214// Example: (4294967296f <= 4294967295u) // This is true due to a precision
215// // loss in rounding up to float.
216// 3. When the floating point value is then converted to an integral, the
217// resulting value is out of range for the target integral type and
218// thus is implementation defined.
219// Example: unsigned u = (float)INT_MAX; // u will typically overflow to 0.
220// To fix this bug we manually truncate the maximum value when the destination
221// type is an integral of larger precision than the source floating-point type,
222// such that the resulting maximum is represented exactly as a floating point.
jschuhe3bd1f62016-12-20 05:11:30223template <typename Dst, typename Src, template <typename> class Bounds>
jschuhfafe0712015-09-14 20:21:24224struct NarrowingRange {
jschuhe3bd1f62016-12-20 05:11:30225 using SrcLimits = std::numeric_limits<Src>;
jschuh5030b00c2016-12-05 18:21:48226 using DstLimits = typename std::numeric_limits<Dst>;
jschuhfafe0712015-09-14 20:21:24227
jschuh71b669a2016-12-17 01:13:31228 // Computes the mask required to make an accurate comparison between types.
229 static const int kShift =
230 (MaxExponent<Src>::value > MaxExponent<Dst>::value &&
231 SrcLimits::digits < DstLimits::digits)
232 ? (DstLimits::digits - SrcLimits::digits)
233 : 0;
234 template <
235 typename T,
236 typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
237
238 // Masks out the integer bits that are beyond the precision of the
239 // intermediate type used for comparison.
240 static constexpr T Adjust(T value) {
241 static_assert(std::is_same<T, Dst>::value, "");
242 static_assert(kShift < DstLimits::digits, "");
243 return static_cast<T>(
244 ConditionalNegate(SafeUnsignedAbs(value) & ~((T(1) << kShift) - T(1)),
245 IsValueNegative(value)));
jschuhfafe0712015-09-14 20:21:24246 }
247
jschuh71b669a2016-12-17 01:13:31248 template <typename T,
249 typename std::enable_if<std::is_floating_point<T>::value>::type* =
250 nullptr>
251 static constexpr T Adjust(T value) {
252 static_assert(std::is_same<T, Dst>::value, "");
253 static_assert(kShift == 0, "");
254 return value;
255 }
256
257 static constexpr Dst max() { return Adjust(Bounds<Dst>::max()); }
258 static constexpr Dst lowest() { return Adjust(Bounds<Dst>::lowest()); }
jschuhfafe0712015-09-14 20:21:24259};
260
jschuh5030b00c2016-12-05 18:21:48261template <typename Dst,
262 typename Src,
jschuhe3bd1f62016-12-20 05:11:30263 template <typename> class Bounds,
jschuh5030b00c2016-12-05 18:21:48264 IntegerRepresentation DstSign = std::is_signed<Dst>::value
265 ? INTEGER_REPRESENTATION_SIGNED
266 : INTEGER_REPRESENTATION_UNSIGNED,
267 IntegerRepresentation SrcSign = std::is_signed<Src>::value
268 ? INTEGER_REPRESENTATION_SIGNED
269 : INTEGER_REPRESENTATION_UNSIGNED,
270 NumericRangeRepresentation DstRange =
271 StaticDstRangeRelationToSrcRange<Dst, Src>::value>
[email protected]5bfecbc52014-02-27 13:49:04272struct DstRangeRelationToSrcRangeImpl;
[email protected]4efb2c32014-01-16 06:57:25273
274// The following templates are for ranges that must be verified at runtime. We
275// split it into checks based on signedness to avoid confusing casts and
276// compiler warnings on signed an unsigned comparisons.
277
jschuhe3bd1f62016-12-20 05:11:30278// Same sign narrowing: The range is contained for normal limits.
[email protected]5bfecbc52014-02-27 13:49:04279template <typename Dst,
280 typename Src,
jschuhe3bd1f62016-12-20 05:11:30281 template <typename> class Bounds,
[email protected]5bfecbc52014-02-27 13:49:04282 IntegerRepresentation DstSign,
283 IntegerRepresentation SrcSign>
284struct DstRangeRelationToSrcRangeImpl<Dst,
285 Src,
jschuhe3bd1f62016-12-20 05:11:30286 Bounds,
[email protected]5bfecbc52014-02-27 13:49:04287 DstSign,
288 SrcSign,
289 NUMERIC_RANGE_CONTAINED> {
jschuhe3bd1f62016-12-20 05:11:30290 static constexpr RangeCheck Check(Src value) {
291 using SrcLimits = std::numeric_limits<Src>;
292 using DstLimits = NarrowingRange<Dst, Src, Bounds>;
293 return RangeCheck(
294 static_cast<Dst>(SrcLimits::max()) <= DstLimits::max() ||
295 static_cast<Dst>(value) <= DstLimits::max(),
296 static_cast<Dst>(SrcLimits::lowest()) >= DstLimits::lowest() ||
297 static_cast<Dst>(value) >= DstLimits::lowest());
298 }
[email protected]5bfecbc52014-02-27 13:49:04299};
300
301// Signed to signed narrowing: Both the upper and lower boundaries may be
jschuhe3bd1f62016-12-20 05:11:30302// exceeded for standard limits.
303template <typename Dst, typename Src, template <typename> class Bounds>
[email protected]5bfecbc52014-02-27 13:49:04304struct DstRangeRelationToSrcRangeImpl<Dst,
305 Src,
jschuhe3bd1f62016-12-20 05:11:30306 Bounds,
[email protected]5bfecbc52014-02-27 13:49:04307 INTEGER_REPRESENTATION_SIGNED,
308 INTEGER_REPRESENTATION_SIGNED,
309 NUMERIC_RANGE_NOT_CONTAINED> {
jschuhe3bd1f62016-12-20 05:11:30310 static constexpr RangeCheck Check(Src value) {
311 using DstLimits = NarrowingRange<Dst, Src, Bounds>;
312 return RangeCheck(value <= DstLimits::max(), value >= DstLimits::lowest());
[email protected]4efb2c32014-01-16 06:57:25313 }
314};
315
jschuhe3bd1f62016-12-20 05:11:30316// Unsigned to unsigned narrowing: Only the upper bound can be exceeded for
317// standard limits.
318template <typename Dst, typename Src, template <typename> class Bounds>
[email protected]5bfecbc52014-02-27 13:49:04319struct DstRangeRelationToSrcRangeImpl<Dst,
320 Src,
jschuhe3bd1f62016-12-20 05:11:30321 Bounds,
[email protected]5bfecbc52014-02-27 13:49:04322 INTEGER_REPRESENTATION_UNSIGNED,
323 INTEGER_REPRESENTATION_UNSIGNED,
324 NUMERIC_RANGE_NOT_CONTAINED> {
jschuhe3bd1f62016-12-20 05:11:30325 static constexpr RangeCheck Check(Src value) {
326 using DstLimits = NarrowingRange<Dst, Src, Bounds>;
327 return RangeCheck(
328 value <= DstLimits::max(),
329 DstLimits::lowest() == Dst(0) || value >= DstLimits::lowest());
[email protected]4efb2c32014-01-16 06:57:25330 }
331};
332
jschuhe3bd1f62016-12-20 05:11:30333// Unsigned to signed: Only the upper bound can be exceeded for standard limits.
334template <typename Dst, typename Src, template <typename> class Bounds>
[email protected]5bfecbc52014-02-27 13:49:04335struct DstRangeRelationToSrcRangeImpl<Dst,
336 Src,
jschuhe3bd1f62016-12-20 05:11:30337 Bounds,
[email protected]5bfecbc52014-02-27 13:49:04338 INTEGER_REPRESENTATION_SIGNED,
339 INTEGER_REPRESENTATION_UNSIGNED,
340 NUMERIC_RANGE_NOT_CONTAINED> {
jschuhe3bd1f62016-12-20 05:11:30341 static constexpr RangeCheck Check(Src value) {
342 using DstLimits = NarrowingRange<Dst, Src, Bounds>;
343 using Promotion = decltype(Src() + Dst());
344 return RangeCheck(static_cast<Promotion>(value) <=
345 static_cast<Promotion>(DstLimits::max()),
346 DstLimits::lowest() <= Dst(0) ||
347 static_cast<Promotion>(value) >=
348 static_cast<Promotion>(DstLimits::lowest()));
[email protected]4efb2c32014-01-16 06:57:25349 }
350};
351
[email protected]5bfecbc52014-02-27 13:49:04352// Signed to unsigned: The upper boundary may be exceeded for a narrower Dst,
jschuhe3bd1f62016-12-20 05:11:30353// and any negative value exceeds the lower boundary for standard limits.
354template <typename Dst, typename Src, template <typename> class Bounds>
[email protected]5bfecbc52014-02-27 13:49:04355struct DstRangeRelationToSrcRangeImpl<Dst,
356 Src,
jschuhe3bd1f62016-12-20 05:11:30357 Bounds,
[email protected]5bfecbc52014-02-27 13:49:04358 INTEGER_REPRESENTATION_UNSIGNED,
359 INTEGER_REPRESENTATION_SIGNED,
360 NUMERIC_RANGE_NOT_CONTAINED> {
jschuhe3bd1f62016-12-20 05:11:30361 static constexpr RangeCheck Check(Src value) {
362 using SrcLimits = std::numeric_limits<Src>;
363 using DstLimits = NarrowingRange<Dst, Src, Bounds>;
364 using Promotion = decltype(Src() + Dst());
365 return RangeCheck(
366 static_cast<Promotion>(SrcLimits::max()) <=
367 static_cast<Promotion>(DstLimits::max()) ||
368 static_cast<Promotion>(value) <=
369 static_cast<Promotion>(DstLimits::max()),
370 value >= Src(0) && (DstLimits::lowest() == 0 ||
371 static_cast<Dst>(value) >= DstLimits::lowest()));
[email protected]4efb2c32014-01-16 06:57:25372 }
373};
374
jschuhe3bd1f62016-12-20 05:11:30375template <typename Dst,
376 template <typename> class Bounds = std::numeric_limits,
377 typename Src>
378constexpr RangeCheck DstRangeRelationToSrcRange(Src value) {
jschuh5030b00c2016-12-05 18:21:48379 static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric.");
380 static_assert(std::is_arithmetic<Dst>::value, "Result must be numeric.");
jschuhe3bd1f62016-12-20 05:11:30381 static_assert(Bounds<Dst>::lowest() < Bounds<Dst>::max(), "");
382 return DstRangeRelationToSrcRangeImpl<Dst, Src, Bounds>::Check(value);
[email protected]4efb2c32014-01-16 06:57:25383}
384
jschuh23a4b062016-12-02 02:55:08385// Integer promotion templates used by the portable checked integer arithmetic.
386template <size_t Size, bool IsSigned>
jschuh5030b00c2016-12-05 18:21:48387struct IntegerForDigitsAndSign;
388
389#define INTEGER_FOR_DIGITS_AND_SIGN(I) \
390 template <> \
391 struct IntegerForDigitsAndSign<IntegerBitsPlusSign<I>::value, \
392 std::is_signed<I>::value> { \
393 using type = I; \
394 }
395
396INTEGER_FOR_DIGITS_AND_SIGN(int8_t);
397INTEGER_FOR_DIGITS_AND_SIGN(uint8_t);
398INTEGER_FOR_DIGITS_AND_SIGN(int16_t);
399INTEGER_FOR_DIGITS_AND_SIGN(uint16_t);
400INTEGER_FOR_DIGITS_AND_SIGN(int32_t);
401INTEGER_FOR_DIGITS_AND_SIGN(uint32_t);
402INTEGER_FOR_DIGITS_AND_SIGN(int64_t);
403INTEGER_FOR_DIGITS_AND_SIGN(uint64_t);
404#undef INTEGER_FOR_DIGITS_AND_SIGN
jschuh23a4b062016-12-02 02:55:08405
406// WARNING: We have no IntegerForSizeAndSign<16, *>. If we ever add one to
407// support 128-bit math, then the ArithmeticPromotion template below will need
408// to be updated (or more likely replaced with a decltype expression).
jschuh5030b00c2016-12-05 18:21:48409static_assert(IntegerBitsPlusSign<intmax_t>::value == 64,
410 "Max integer size not supported for this toolchain.");
jschuh23a4b062016-12-02 02:55:08411
jschuh5030b00c2016-12-05 18:21:48412template <typename Integer, bool IsSigned = std::is_signed<Integer>::value>
jschuh23a4b062016-12-02 02:55:08413struct TwiceWiderInteger {
jschuh5030b00c2016-12-05 18:21:48414 using type =
415 typename IntegerForDigitsAndSign<IntegerBitsPlusSign<Integer>::value * 2,
416 IsSigned>::type;
jschuh23a4b062016-12-02 02:55:08417};
418
jschuh23a4b062016-12-02 02:55:08419enum ArithmeticPromotionCategory {
jschuh466e9842016-12-02 21:01:39420 LEFT_PROMOTION, // Use the type of the left-hand argument.
421 RIGHT_PROMOTION // Use the type of the right-hand argument.
jschuh23a4b062016-12-02 02:55:08422};
423
jschuh711ac6a2016-12-04 07:17:48424// Determines the type that can represent the largest positive value.
jschuh23a4b062016-12-02 02:55:08425template <typename Lhs,
426 typename Rhs,
427 ArithmeticPromotionCategory Promotion =
428 (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value)
429 ? LEFT_PROMOTION
430 : RIGHT_PROMOTION>
431struct MaxExponentPromotion;
432
433template <typename Lhs, typename Rhs>
434struct MaxExponentPromotion<Lhs, Rhs, LEFT_PROMOTION> {
435 using type = Lhs;
436};
437
438template <typename Lhs, typename Rhs>
439struct MaxExponentPromotion<Lhs, Rhs, RIGHT_PROMOTION> {
440 using type = Rhs;
441};
442
jschuh711ac6a2016-12-04 07:17:48443// Determines the type that can represent the lowest arithmetic value.
444template <typename Lhs,
445 typename Rhs,
446 ArithmeticPromotionCategory Promotion =
447 std::is_signed<Lhs>::value
448 ? (std::is_signed<Rhs>::value
449 ? (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value
450 ? LEFT_PROMOTION
451 : RIGHT_PROMOTION)
452 : LEFT_PROMOTION)
453 : (std::is_signed<Rhs>::value
454 ? RIGHT_PROMOTION
455 : (MaxExponent<Lhs>::value < MaxExponent<Rhs>::value
456 ? LEFT_PROMOTION
457 : RIGHT_PROMOTION))>
458struct LowestValuePromotion;
459
460template <typename Lhs, typename Rhs>
461struct LowestValuePromotion<Lhs, Rhs, LEFT_PROMOTION> {
462 using type = Lhs;
463};
464
465template <typename Lhs, typename Rhs>
466struct LowestValuePromotion<Lhs, Rhs, RIGHT_PROMOTION> {
467 using type = Rhs;
468};
469
470// Determines the type that is best able to represent an arithmetic result.
jschuh5030b00c2016-12-05 18:21:48471template <
472 typename Lhs,
473 typename Rhs = Lhs,
474 bool is_intmax_type =
475 std::is_integral<typename MaxExponentPromotion<Lhs, Rhs>::type>::value&&
476 IntegerBitsPlusSign<typename MaxExponentPromotion<Lhs, Rhs>::type>::
477 value == IntegerBitsPlusSign<intmax_t>::value,
478 bool is_max_exponent =
479 StaticDstRangeRelationToSrcRange<
480 typename MaxExponentPromotion<Lhs, Rhs>::type,
481 Lhs>::value ==
482 NUMERIC_RANGE_CONTAINED&& StaticDstRangeRelationToSrcRange<
483 typename MaxExponentPromotion<Lhs, Rhs>::type,
484 Rhs>::value == NUMERIC_RANGE_CONTAINED>
jschuh23a4b062016-12-02 02:55:08485struct BigEnoughPromotion;
486
487// The side with the max exponent is big enough.
488template <typename Lhs, typename Rhs, bool is_intmax_type>
489struct BigEnoughPromotion<Lhs, Rhs, is_intmax_type, true> {
490 using type = typename MaxExponentPromotion<Lhs, Rhs>::type;
491 static const bool is_contained = true;
492};
493
494// We can use a twice wider type to fit.
495template <typename Lhs, typename Rhs>
496struct BigEnoughPromotion<Lhs, Rhs, false, false> {
jschuh5030b00c2016-12-05 18:21:48497 using type =
498 typename TwiceWiderInteger<typename MaxExponentPromotion<Lhs, Rhs>::type,
499 std::is_signed<Lhs>::value ||
500 std::is_signed<Rhs>::value>::type;
jschuh23a4b062016-12-02 02:55:08501 static const bool is_contained = true;
502};
503
504// No type is large enough.
505template <typename Lhs, typename Rhs>
506struct BigEnoughPromotion<Lhs, Rhs, true, false> {
507 using type = typename MaxExponentPromotion<Lhs, Rhs>::type;
508 static const bool is_contained = false;
509};
510
jschuh23a4b062016-12-02 02:55:08511// We can statically check if operations on the provided types can wrap, so we
512// can skip the checked operations if they're not needed. So, for an integer we
513// care if the destination type preserves the sign and is twice the width of
514// the source.
515template <typename T, typename Lhs, typename Rhs>
516struct IsIntegerArithmeticSafe {
jschuh5030b00c2016-12-05 18:21:48517 static const bool value =
518 !std::is_floating_point<T>::value &&
519 StaticDstRangeRelationToSrcRange<T, Lhs>::value ==
520 NUMERIC_RANGE_CONTAINED &&
521 IntegerBitsPlusSign<T>::value >= (2 * IntegerBitsPlusSign<Lhs>::value) &&
522 StaticDstRangeRelationToSrcRange<T, Rhs>::value !=
523 NUMERIC_RANGE_CONTAINED &&
524 IntegerBitsPlusSign<T>::value >= (2 * IntegerBitsPlusSign<Rhs>::value);
jschuh23a4b062016-12-02 02:55:08525};
526
527// This hacks around libstdc++ 4.6 missing stuff in type_traits.
528#if defined(__GLIBCXX__)
529#define PRIV_GLIBCXX_4_7_0 20120322
530#define PRIV_GLIBCXX_4_5_4 20120702
531#define PRIV_GLIBCXX_4_6_4 20121127
532#if (__GLIBCXX__ < PRIV_GLIBCXX_4_7_0 || __GLIBCXX__ == PRIV_GLIBCXX_4_5_4 || \
533 __GLIBCXX__ == PRIV_GLIBCXX_4_6_4)
534#define PRIV_USE_FALLBACKS_FOR_OLD_GLIBCXX
535#undef PRIV_GLIBCXX_4_7_0
536#undef PRIV_GLIBCXX_4_5_4
537#undef PRIV_GLIBCXX_4_6_4
538#endif
539#endif
540
541// Extracts the underlying type from an enum.
542template <typename T, bool is_enum = std::is_enum<T>::value>
543struct ArithmeticOrUnderlyingEnum;
544
545template <typename T>
546struct ArithmeticOrUnderlyingEnum<T, true> {
547#if defined(PRIV_USE_FALLBACKS_FOR_OLD_GLIBCXX)
548 using type = __underlying_type(T);
549#else
550 using type = typename std::underlying_type<T>::type;
551#endif
552 static const bool value = std::is_arithmetic<type>::value;
553};
554
555#if defined(PRIV_USE_FALLBACKS_FOR_OLD_GLIBCXX)
556#undef PRIV_USE_FALLBACKS_FOR_OLD_GLIBCXX
557#endif
558
559template <typename T>
560struct ArithmeticOrUnderlyingEnum<T, false> {
561 using type = T;
562 static const bool value = std::is_arithmetic<type>::value;
563};
564
565// The following are helper templates used in the CheckedNumeric class.
566template <typename T>
567class CheckedNumeric;
568
569template <typename T>
570class StrictNumeric;
571
572// Used to treat CheckedNumeric and arithmetic underlying types the same.
573template <typename T>
574struct UnderlyingType {
575 using type = typename ArithmeticOrUnderlyingEnum<T>::type;
576 static const bool is_numeric = std::is_arithmetic<type>::value;
577 static const bool is_checked = false;
578 static const bool is_strict = false;
579};
580
581template <typename T>
582struct UnderlyingType<CheckedNumeric<T>> {
583 using type = T;
584 static const bool is_numeric = true;
585 static const bool is_checked = true;
586 static const bool is_strict = false;
587};
588
589template <typename T>
590struct UnderlyingType<StrictNumeric<T>> {
591 using type = T;
592 static const bool is_numeric = true;
593 static const bool is_checked = false;
594 static const bool is_strict = true;
595};
596
597template <typename L, typename R>
598struct IsCheckedOp {
599 static const bool value =
600 UnderlyingType<L>::is_numeric && UnderlyingType<R>::is_numeric &&
601 (UnderlyingType<L>::is_checked || UnderlyingType<R>::is_checked);
602};
603
604template <typename L, typename R>
605struct IsStrictOp {
606 static const bool value =
607 UnderlyingType<L>::is_numeric && UnderlyingType<R>::is_numeric &&
608 (UnderlyingType<L>::is_strict || UnderlyingType<R>::is_strict);
609};
610
611template <typename L, typename R>
612constexpr bool IsLessImpl(const L lhs,
613 const R rhs,
jschuhe3bd1f62016-12-20 05:11:30614 const RangeCheck l_range,
615 const RangeCheck r_range) {
jschuh23a4b062016-12-02 02:55:08616 return l_range == RANGE_UNDERFLOW || r_range == RANGE_OVERFLOW ||
617 (l_range == r_range &&
618 static_cast<decltype(lhs + rhs)>(lhs) <
619 static_cast<decltype(lhs + rhs)>(rhs));
620}
621
622template <typename L, typename R>
623struct IsLess {
624 static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
625 "Types must be numeric.");
626 static constexpr bool Test(const L lhs, const R rhs) {
627 return IsLessImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs),
628 DstRangeRelationToSrcRange<L>(rhs));
629 }
630};
631
632template <typename L, typename R>
633constexpr bool IsLessOrEqualImpl(const L lhs,
634 const R rhs,
jschuhe3bd1f62016-12-20 05:11:30635 const RangeCheck l_range,
636 const RangeCheck r_range) {
jschuh23a4b062016-12-02 02:55:08637 return l_range == RANGE_UNDERFLOW || r_range == RANGE_OVERFLOW ||
638 (l_range == r_range &&
639 static_cast<decltype(lhs + rhs)>(lhs) <=
640 static_cast<decltype(lhs + rhs)>(rhs));
641}
642
643template <typename L, typename R>
644struct IsLessOrEqual {
645 static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
646 "Types must be numeric.");
647 static constexpr bool Test(const L lhs, const R rhs) {
648 return IsLessOrEqualImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs),
649 DstRangeRelationToSrcRange<L>(rhs));
650 }
651};
652
653template <typename L, typename R>
654constexpr bool IsGreaterImpl(const L lhs,
655 const R rhs,
jschuhe3bd1f62016-12-20 05:11:30656 const RangeCheck l_range,
657 const RangeCheck r_range) {
jschuh23a4b062016-12-02 02:55:08658 return l_range == RANGE_OVERFLOW || r_range == RANGE_UNDERFLOW ||
659 (l_range == r_range &&
660 static_cast<decltype(lhs + rhs)>(lhs) >
661 static_cast<decltype(lhs + rhs)>(rhs));
662}
663
664template <typename L, typename R>
665struct IsGreater {
666 static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
667 "Types must be numeric.");
668 static constexpr bool Test(const L lhs, const R rhs) {
669 return IsGreaterImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs),
670 DstRangeRelationToSrcRange<L>(rhs));
671 }
672};
673
674template <typename L, typename R>
675constexpr bool IsGreaterOrEqualImpl(const L lhs,
676 const R rhs,
jschuhe3bd1f62016-12-20 05:11:30677 const RangeCheck l_range,
678 const RangeCheck r_range) {
jschuh23a4b062016-12-02 02:55:08679 return l_range == RANGE_OVERFLOW || r_range == RANGE_UNDERFLOW ||
680 (l_range == r_range &&
681 static_cast<decltype(lhs + rhs)>(lhs) >=
682 static_cast<decltype(lhs + rhs)>(rhs));
683}
684
685template <typename L, typename R>
686struct IsGreaterOrEqual {
687 static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
688 "Types must be numeric.");
689 static constexpr bool Test(const L lhs, const R rhs) {
690 return IsGreaterOrEqualImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs),
691 DstRangeRelationToSrcRange<L>(rhs));
692 }
693};
694
695template <typename L, typename R>
696struct IsEqual {
697 static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
698 "Types must be numeric.");
699 static constexpr bool Test(const L lhs, const R rhs) {
700 return DstRangeRelationToSrcRange<R>(lhs) ==
701 DstRangeRelationToSrcRange<L>(rhs) &&
702 static_cast<decltype(lhs + rhs)>(lhs) ==
703 static_cast<decltype(lhs + rhs)>(rhs);
704 }
705};
706
707template <typename L, typename R>
708struct IsNotEqual {
709 static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
710 "Types must be numeric.");
711 static constexpr bool Test(const L lhs, const R rhs) {
712 return DstRangeRelationToSrcRange<R>(lhs) !=
713 DstRangeRelationToSrcRange<L>(rhs) ||
714 static_cast<decltype(lhs + rhs)>(lhs) !=
715 static_cast<decltype(lhs + rhs)>(rhs);
716 }
717};
718
719// These perform the actual math operations on the CheckedNumerics.
720// Binary arithmetic operations.
721template <template <typename, typename> class C, typename L, typename R>
722constexpr bool SafeCompare(const L lhs, const R rhs) {
723 static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
724 "Types must be numeric.");
jschuh466e9842016-12-02 21:01:39725 using Promotion = BigEnoughPromotion<L, R>;
jschuh23a4b062016-12-02 02:55:08726 using BigType = typename Promotion::type;
727 return Promotion::is_contained
728 // Force to a larger type for speed if both are contained.
729 ? C<BigType, BigType>::Test(
730 static_cast<BigType>(static_cast<L>(lhs)),
731 static_cast<BigType>(static_cast<R>(rhs)))
732 // Let the template functions figure it out for mixed types.
733 : C<L, R>::Test(lhs, rhs);
734};
735
[email protected]4efb2c32014-01-16 06:57:25736} // namespace internal
737} // namespace base
738
danakj0a448602015-03-10 00:31:16739#endif // BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_