safe_conversions_impl.h 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851
  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
  3. // found in the LICENSE file.
  4. #ifndef BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
  5. #define BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
  6. #include <stdint.h>
  7. #include <limits>
  8. #include <type_traits>
  9. #if defined(__GNUC__) || defined(__clang__)
  10. #define BASE_NUMERICS_LIKELY(x) __builtin_expect(!!(x), 1)
  11. #define BASE_NUMERICS_UNLIKELY(x) __builtin_expect(!!(x), 0)
  12. #else
  13. #define BASE_NUMERICS_LIKELY(x) (x)
  14. #define BASE_NUMERICS_UNLIKELY(x) (x)
  15. #endif
  16. namespace base {
  17. namespace internal {
  18. // The std library doesn't provide a binary max_exponent for integers, however
  19. // we can compute an analog using std::numeric_limits<>::digits.
  20. template <typename NumericType>
  21. struct MaxExponent {
  22. static const int value = std::is_floating_point<NumericType>::value
  23. ? std::numeric_limits<NumericType>::max_exponent
  24. : std::numeric_limits<NumericType>::digits + 1;
  25. };
  26. // The number of bits (including the sign) in an integer. Eliminates sizeof
  27. // hacks.
  28. template <typename NumericType>
  29. struct IntegerBitsPlusSign {
  30. static const int value = std::numeric_limits<NumericType>::digits +
  31. std::is_signed<NumericType>::value;
  32. };
  33. // Helper templates for integer manipulations.
  34. template <typename Integer>
  35. struct PositionOfSignBit {
  36. static const size_t value = IntegerBitsPlusSign<Integer>::value - 1;
  37. };
  38. // Determines if a numeric value is negative without throwing compiler
  39. // warnings on: unsigned(value) < 0.
  40. template <typename T,
  41. typename std::enable_if<std::is_signed<T>::value>::type* = nullptr>
  42. constexpr bool IsValueNegative(T value) {
  43. static_assert(std::is_arithmetic<T>::value, "Argument must be numeric.");
  44. return value < 0;
  45. }
  46. template <typename T,
  47. typename std::enable_if<!std::is_signed<T>::value>::type* = nullptr>
  48. constexpr bool IsValueNegative(T) {
  49. static_assert(std::is_arithmetic<T>::value, "Argument must be numeric.");
  50. return false;
  51. }
  52. // This performs a fast negation, returning a signed value. It works on unsigned
  53. // arguments, but probably doesn't do what you want for any unsigned value
  54. // larger than max / 2 + 1 (i.e. signed min cast to unsigned).
  55. template <typename T>
  56. constexpr typename std::make_signed<T>::type ConditionalNegate(
  57. T x,
  58. bool is_negative) {
  59. static_assert(std::is_integral<T>::value, "Type must be integral");
  60. using SignedT = typename std::make_signed<T>::type;
  61. using UnsignedT = typename std::make_unsigned<T>::type;
  62. return static_cast<SignedT>(
  63. (static_cast<UnsignedT>(x) ^ -SignedT(is_negative)) + is_negative);
  64. }
  65. // This performs a safe, absolute value via unsigned overflow.
  66. template <typename T>
  67. constexpr typename std::make_unsigned<T>::type SafeUnsignedAbs(T value) {
  68. static_assert(std::is_integral<T>::value, "Type must be integral");
  69. using UnsignedT = typename std::make_unsigned<T>::type;
  70. return IsValueNegative(value)
  71. ? static_cast<UnsignedT>(0u - static_cast<UnsignedT>(value))
  72. : static_cast<UnsignedT>(value);
  73. }
  74. // This allows us to switch paths on known compile-time constants.
  75. #if defined(__clang__) || defined(__GNUC__)
  76. constexpr bool CanDetectCompileTimeConstant() {
  77. return true;
  78. }
  79. template <typename T>
  80. constexpr bool IsCompileTimeConstant(const T v) {
  81. return __builtin_constant_p(v);
  82. }
  83. #else
  84. constexpr bool CanDetectCompileTimeConstant() {
  85. return false;
  86. }
  87. template <typename T>
  88. constexpr bool IsCompileTimeConstant(const T) {
  89. return false;
  90. }
  91. #endif
  92. template <typename T>
  93. constexpr bool MustTreatAsConstexpr(const T v) {
  94. // Either we can't detect a compile-time constant, and must always use the
  95. // constexpr path, or we know we have a compile-time constant.
  96. return !CanDetectCompileTimeConstant() || IsCompileTimeConstant(v);
  97. }
  98. // Forces a crash, like a CHECK(false). Used for numeric boundary errors.
  99. // Also used in a constexpr template to trigger a compilation failure on
  100. // an error condition.
  101. struct CheckOnFailure {
  102. template <typename T>
  103. static T HandleFailure() {
  104. #if defined(_MSC_VER)
  105. __debugbreak();
  106. #elif defined(__GNUC__) || defined(__clang__)
  107. __builtin_trap();
  108. #else
  109. ((void)(*(volatile char*)0 = 0));
  110. #endif
  111. return T();
  112. }
  113. };
  114. enum IntegerRepresentation {
  115. INTEGER_REPRESENTATION_UNSIGNED,
  116. INTEGER_REPRESENTATION_SIGNED
  117. };
  118. // A range for a given nunmeric Src type is contained for a given numeric Dst
  119. // type if both numeric_limits<Src>::max() <= numeric_limits<Dst>::max() and
  120. // numeric_limits<Src>::lowest() >= numeric_limits<Dst>::lowest() are true.
  121. // We implement this as template specializations rather than simple static
  122. // comparisons to ensure type correctness in our comparisons.
  123. enum NumericRangeRepresentation {
  124. NUMERIC_RANGE_NOT_CONTAINED,
  125. NUMERIC_RANGE_CONTAINED
  126. };
  127. // Helper templates to statically determine if our destination type can contain
  128. // maximum and minimum values represented by the source type.
  129. template <typename Dst,
  130. typename Src,
  131. IntegerRepresentation DstSign = std::is_signed<Dst>::value
  132. ? INTEGER_REPRESENTATION_SIGNED
  133. : INTEGER_REPRESENTATION_UNSIGNED,
  134. IntegerRepresentation SrcSign = std::is_signed<Src>::value
  135. ? INTEGER_REPRESENTATION_SIGNED
  136. : INTEGER_REPRESENTATION_UNSIGNED>
  137. struct StaticDstRangeRelationToSrcRange;
  138. // Same sign: Dst is guaranteed to contain Src only if its range is equal or
  139. // larger.
  140. template <typename Dst, typename Src, IntegerRepresentation Sign>
  141. struct StaticDstRangeRelationToSrcRange<Dst, Src, Sign, Sign> {
  142. static const NumericRangeRepresentation value =
  143. MaxExponent<Dst>::value >= MaxExponent<Src>::value
  144. ? NUMERIC_RANGE_CONTAINED
  145. : NUMERIC_RANGE_NOT_CONTAINED;
  146. };
  147. // Unsigned to signed: Dst is guaranteed to contain source only if its range is
  148. // larger.
  149. template <typename Dst, typename Src>
  150. struct 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;
  158. };
  159. // Signed to unsigned: Dst cannot be statically determined to contain Src.
  160. template <typename Dst, typename Src>
  161. struct StaticDstRangeRelationToSrcRange<Dst,
  162. Src,
  163. INTEGER_REPRESENTATION_UNSIGNED,
  164. INTEGER_REPRESENTATION_SIGNED> {
  165. static const NumericRangeRepresentation value = NUMERIC_RANGE_NOT_CONTAINED;
  166. };
  167. // This class wraps the range constraints as separate booleans so the compiler
  168. // can identify constants and eliminate unused code paths.
  169. class RangeCheck {
  170. public:
  171. constexpr RangeCheck(bool is_in_lower_bound, bool is_in_upper_bound)
  172. : is_underflow_(!is_in_lower_bound), is_overflow_(!is_in_upper_bound) {}
  173. constexpr RangeCheck() : is_underflow_(0), is_overflow_(0) {}
  174. constexpr bool IsValid() const { return !is_overflow_ && !is_underflow_; }
  175. constexpr bool IsInvalid() const { return is_overflow_ && is_underflow_; }
  176. constexpr bool IsOverflow() const { return is_overflow_ && !is_underflow_; }
  177. constexpr bool IsUnderflow() const { return !is_overflow_ && is_underflow_; }
  178. constexpr bool IsOverflowFlagSet() const { return is_overflow_; }
  179. constexpr bool IsUnderflowFlagSet() const { return is_underflow_; }
  180. constexpr bool operator==(const RangeCheck rhs) const {
  181. return is_underflow_ == rhs.is_underflow_ &&
  182. is_overflow_ == rhs.is_overflow_;
  183. }
  184. constexpr bool operator!=(const RangeCheck rhs) const {
  185. return !(*this == rhs);
  186. }
  187. private:
  188. // Do not change the order of these member variables. The integral conversion
  189. // optimization depends on this exact order.
  190. const bool is_underflow_;
  191. const bool is_overflow_;
  192. };
  193. // The following helper template addresses a corner case in range checks for
  194. // conversion from a floating-point type to an integral type of smaller range
  195. // but larger precision (e.g. float -> unsigned). The problem is as follows:
  196. // 1. Integral maximum is always one less than a power of two, so it must be
  197. // truncated to fit the mantissa of the floating point. The direction of
  198. // rounding is implementation defined, but by default it's always IEEE
  199. // floats, which round to nearest and thus result in a value of larger
  200. // magnitude than the integral value.
  201. // Example: float f = UINT_MAX; // f is 4294967296f but UINT_MAX
  202. // // is 4294967295u.
  203. // 2. If the floating point value is equal to the promoted integral maximum
  204. // value, a range check will erroneously pass.
  205. // Example: (4294967296f <= 4294967295u) // This is true due to a precision
  206. // // loss in rounding up to float.
  207. // 3. When the floating point value is then converted to an integral, the
  208. // resulting value is out of range for the target integral type and
  209. // thus is implementation defined.
  210. // Example: unsigned u = (float)INT_MAX; // u will typically overflow to 0.
  211. // To fix this bug we manually truncate the maximum value when the destination
  212. // type is an integral of larger precision than the source floating-point type,
  213. // such that the resulting maximum is represented exactly as a floating point.
  214. template <typename Dst, typename Src, template <typename> class Bounds>
  215. struct NarrowingRange {
  216. using SrcLimits = std::numeric_limits<Src>;
  217. using DstLimits = typename std::numeric_limits<Dst>;
  218. // Computes the mask required to make an accurate comparison between types.
  219. static const int kShift =
  220. (MaxExponent<Src>::value > MaxExponent<Dst>::value &&
  221. SrcLimits::digits < DstLimits::digits)
  222. ? (DstLimits::digits - SrcLimits::digits)
  223. : 0;
  224. template <
  225. typename T,
  226. typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
  227. // Masks out the integer bits that are beyond the precision of the
  228. // intermediate type used for comparison.
  229. static constexpr T Adjust(T value) {
  230. static_assert(std::is_same<T, Dst>::value, "");
  231. static_assert(kShift < DstLimits::digits, "");
  232. return static_cast<T>(
  233. ConditionalNegate(SafeUnsignedAbs(value) & ~((T(1) << kShift) - T(1)),
  234. IsValueNegative(value)));
  235. }
  236. template <typename T,
  237. typename std::enable_if<std::is_floating_point<T>::value>::type* =
  238. nullptr>
  239. static constexpr T Adjust(T value) {
  240. static_assert(std::is_same<T, Dst>::value, "");
  241. static_assert(kShift == 0, "");
  242. return value;
  243. }
  244. static constexpr Dst max() { return Adjust(Bounds<Dst>::max()); }
  245. static constexpr Dst lowest() { return Adjust(Bounds<Dst>::lowest()); }
  246. };
  247. template <typename Dst,
  248. typename Src,
  249. template <typename> class Bounds,
  250. IntegerRepresentation DstSign = std::is_signed<Dst>::value
  251. ? INTEGER_REPRESENTATION_SIGNED
  252. : INTEGER_REPRESENTATION_UNSIGNED,
  253. IntegerRepresentation SrcSign = std::is_signed<Src>::value
  254. ? INTEGER_REPRESENTATION_SIGNED
  255. : INTEGER_REPRESENTATION_UNSIGNED,
  256. NumericRangeRepresentation DstRange =
  257. StaticDstRangeRelationToSrcRange<Dst, Src>::value>
  258. struct DstRangeRelationToSrcRangeImpl;
  259. // The following templates are for ranges that must be verified at runtime. We
  260. // split it into checks based on signedness to avoid confusing casts and
  261. // compiler warnings on signed an unsigned comparisons.
  262. // Same sign narrowing: The range is contained for normal limits.
  263. template <typename Dst,
  264. typename Src,
  265. template <typename> class Bounds,
  266. IntegerRepresentation DstSign,
  267. IntegerRepresentation SrcSign>
  268. struct DstRangeRelationToSrcRangeImpl<Dst,
  269. Src,
  270. Bounds,
  271. DstSign,
  272. SrcSign,
  273. NUMERIC_RANGE_CONTAINED> {
  274. static constexpr RangeCheck Check(Src value) {
  275. using SrcLimits = std::numeric_limits<Src>;
  276. using DstLimits = NarrowingRange<Dst, Src, Bounds>;
  277. return RangeCheck(
  278. static_cast<Dst>(SrcLimits::lowest()) >= DstLimits::lowest() ||
  279. static_cast<Dst>(value) >= DstLimits::lowest(),
  280. static_cast<Dst>(SrcLimits::max()) <= DstLimits::max() ||
  281. static_cast<Dst>(value) <= DstLimits::max());
  282. }
  283. };
  284. // Signed to signed narrowing: Both the upper and lower boundaries may be
  285. // exceeded for standard limits.
  286. template <typename Dst, typename Src, template <typename> class Bounds>
  287. struct DstRangeRelationToSrcRangeImpl<Dst,
  288. Src,
  289. Bounds,
  290. INTEGER_REPRESENTATION_SIGNED,
  291. INTEGER_REPRESENTATION_SIGNED,
  292. NUMERIC_RANGE_NOT_CONTAINED> {
  293. static constexpr RangeCheck Check(Src value) {
  294. using DstLimits = NarrowingRange<Dst, Src, Bounds>;
  295. return RangeCheck(value >= DstLimits::lowest(), value <= DstLimits::max());
  296. }
  297. };
  298. // Unsigned to unsigned narrowing: Only the upper bound can be exceeded for
  299. // standard limits.
  300. template <typename Dst, typename Src, template <typename> class Bounds>
  301. struct DstRangeRelationToSrcRangeImpl<Dst,
  302. Src,
  303. Bounds,
  304. INTEGER_REPRESENTATION_UNSIGNED,
  305. INTEGER_REPRESENTATION_UNSIGNED,
  306. NUMERIC_RANGE_NOT_CONTAINED> {
  307. static constexpr RangeCheck Check(Src value) {
  308. using DstLimits = NarrowingRange<Dst, Src, Bounds>;
  309. return RangeCheck(
  310. DstLimits::lowest() == Dst(0) || value >= DstLimits::lowest(),
  311. value <= DstLimits::max());
  312. }
  313. };
  314. // Unsigned to signed: Only the upper bound can be exceeded for standard limits.
  315. template <typename Dst, typename Src, template <typename> class Bounds>
  316. struct DstRangeRelationToSrcRangeImpl<Dst,
  317. Src,
  318. Bounds,
  319. INTEGER_REPRESENTATION_SIGNED,
  320. INTEGER_REPRESENTATION_UNSIGNED,
  321. NUMERIC_RANGE_NOT_CONTAINED> {
  322. static constexpr RangeCheck Check(Src value) {
  323. using DstLimits = NarrowingRange<Dst, Src, Bounds>;
  324. using Promotion = decltype(Src() + Dst());
  325. return RangeCheck(DstLimits::lowest() <= Dst(0) ||
  326. static_cast<Promotion>(value) >=
  327. static_cast<Promotion>(DstLimits::lowest()),
  328. static_cast<Promotion>(value) <=
  329. static_cast<Promotion>(DstLimits::max()));
  330. }
  331. };
  332. // Signed to unsigned: The upper boundary may be exceeded for a narrower Dst,
  333. // and any negative value exceeds the lower boundary for standard limits.
  334. template <typename Dst, typename Src, template <typename> class Bounds>
  335. struct DstRangeRelationToSrcRangeImpl<Dst,
  336. Src,
  337. Bounds,
  338. INTEGER_REPRESENTATION_UNSIGNED,
  339. INTEGER_REPRESENTATION_SIGNED,
  340. NUMERIC_RANGE_NOT_CONTAINED> {
  341. static constexpr RangeCheck Check(Src value) {
  342. using SrcLimits = std::numeric_limits<Src>;
  343. using DstLimits = NarrowingRange<Dst, Src, Bounds>;
  344. using Promotion = decltype(Src() + Dst());
  345. return RangeCheck(
  346. value >= Src(0) && (DstLimits::lowest() == 0 ||
  347. static_cast<Dst>(value) >= DstLimits::lowest()),
  348. static_cast<Promotion>(SrcLimits::max()) <=
  349. static_cast<Promotion>(DstLimits::max()) ||
  350. static_cast<Promotion>(value) <=
  351. static_cast<Promotion>(DstLimits::max()));
  352. }
  353. };
  354. // Simple wrapper for statically checking if a type's range is contained.
  355. template <typename Dst, typename Src>
  356. struct IsTypeInRangeForNumericType {
  357. static const bool value = StaticDstRangeRelationToSrcRange<Dst, Src>::value ==
  358. NUMERIC_RANGE_CONTAINED;
  359. };
  360. template <typename Dst,
  361. template <typename> class Bounds = std::numeric_limits,
  362. typename Src>
  363. constexpr RangeCheck DstRangeRelationToSrcRange(Src value) {
  364. static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric.");
  365. static_assert(std::is_arithmetic<Dst>::value, "Result must be numeric.");
  366. static_assert(Bounds<Dst>::lowest() < Bounds<Dst>::max(), "");
  367. return DstRangeRelationToSrcRangeImpl<Dst, Src, Bounds>::Check(value);
  368. }
  369. // Integer promotion templates used by the portable checked integer arithmetic.
  370. template <size_t Size, bool IsSigned>
  371. struct IntegerForDigitsAndSign;
  372. #define INTEGER_FOR_DIGITS_AND_SIGN(I) \
  373. template <> \
  374. struct IntegerForDigitsAndSign<IntegerBitsPlusSign<I>::value, \
  375. std::is_signed<I>::value> { \
  376. using type = I; \
  377. }
  378. INTEGER_FOR_DIGITS_AND_SIGN(int8_t);
  379. INTEGER_FOR_DIGITS_AND_SIGN(uint8_t);
  380. INTEGER_FOR_DIGITS_AND_SIGN(int16_t);
  381. INTEGER_FOR_DIGITS_AND_SIGN(uint16_t);
  382. INTEGER_FOR_DIGITS_AND_SIGN(int32_t);
  383. INTEGER_FOR_DIGITS_AND_SIGN(uint32_t);
  384. INTEGER_FOR_DIGITS_AND_SIGN(int64_t);
  385. INTEGER_FOR_DIGITS_AND_SIGN(uint64_t);
  386. #undef INTEGER_FOR_DIGITS_AND_SIGN
  387. // WARNING: We have no IntegerForSizeAndSign<16, *>. If we ever add one to
  388. // support 128-bit math, then the ArithmeticPromotion template below will need
  389. // to be updated (or more likely replaced with a decltype expression).
  390. static_assert(IntegerBitsPlusSign<intmax_t>::value == 64,
  391. "Max integer size not supported for this toolchain.");
  392. template <typename Integer, bool IsSigned = std::is_signed<Integer>::value>
  393. struct TwiceWiderInteger {
  394. using type =
  395. typename IntegerForDigitsAndSign<IntegerBitsPlusSign<Integer>::value * 2,
  396. IsSigned>::type;
  397. };
  398. enum ArithmeticPromotionCategory {
  399. LEFT_PROMOTION, // Use the type of the left-hand argument.
  400. RIGHT_PROMOTION // Use the type of the right-hand argument.
  401. };
  402. // Determines the type that can represent the largest positive value.
  403. template <typename Lhs,
  404. typename Rhs,
  405. ArithmeticPromotionCategory Promotion =
  406. (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value)
  407. ? LEFT_PROMOTION
  408. : RIGHT_PROMOTION>
  409. struct MaxExponentPromotion;
  410. template <typename Lhs, typename Rhs>
  411. struct MaxExponentPromotion<Lhs, Rhs, LEFT_PROMOTION> {
  412. using type = Lhs;
  413. };
  414. template <typename Lhs, typename Rhs>
  415. struct MaxExponentPromotion<Lhs, Rhs, RIGHT_PROMOTION> {
  416. using type = Rhs;
  417. };
  418. // Determines the type that can represent the lowest arithmetic value.
  419. template <typename Lhs,
  420. typename Rhs,
  421. ArithmeticPromotionCategory Promotion =
  422. std::is_signed<Lhs>::value
  423. ? (std::is_signed<Rhs>::value
  424. ? (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value
  425. ? LEFT_PROMOTION
  426. : RIGHT_PROMOTION)
  427. : LEFT_PROMOTION)
  428. : (std::is_signed<Rhs>::value
  429. ? RIGHT_PROMOTION
  430. : (MaxExponent<Lhs>::value < MaxExponent<Rhs>::value
  431. ? LEFT_PROMOTION
  432. : RIGHT_PROMOTION))>
  433. struct LowestValuePromotion;
  434. template <typename Lhs, typename Rhs>
  435. struct LowestValuePromotion<Lhs, Rhs, LEFT_PROMOTION> {
  436. using type = Lhs;
  437. };
  438. template <typename Lhs, typename Rhs>
  439. struct LowestValuePromotion<Lhs, Rhs, RIGHT_PROMOTION> {
  440. using type = Rhs;
  441. };
  442. // Determines the type that is best able to represent an arithmetic result.
  443. template <
  444. typename Lhs,
  445. typename Rhs = Lhs,
  446. bool is_intmax_type =
  447. std::is_integral<typename MaxExponentPromotion<Lhs, Rhs>::type>::value&&
  448. IntegerBitsPlusSign<typename MaxExponentPromotion<Lhs, Rhs>::type>::
  449. value == IntegerBitsPlusSign<intmax_t>::value,
  450. bool is_max_exponent =
  451. StaticDstRangeRelationToSrcRange<
  452. typename MaxExponentPromotion<Lhs, Rhs>::type,
  453. Lhs>::value ==
  454. NUMERIC_RANGE_CONTAINED&& StaticDstRangeRelationToSrcRange<
  455. typename MaxExponentPromotion<Lhs, Rhs>::type,
  456. Rhs>::value == NUMERIC_RANGE_CONTAINED>
  457. struct BigEnoughPromotion;
  458. // The side with the max exponent is big enough.
  459. template <typename Lhs, typename Rhs, bool is_intmax_type>
  460. struct BigEnoughPromotion<Lhs, Rhs, is_intmax_type, true> {
  461. using type = typename MaxExponentPromotion<Lhs, Rhs>::type;
  462. static const bool is_contained = true;
  463. };
  464. // We can use a twice wider type to fit.
  465. template <typename Lhs, typename Rhs>
  466. struct BigEnoughPromotion<Lhs, Rhs, false, false> {
  467. using type =
  468. typename TwiceWiderInteger<typename MaxExponentPromotion<Lhs, Rhs>::type,
  469. std::is_signed<Lhs>::value ||
  470. std::is_signed<Rhs>::value>::type;
  471. static const bool is_contained = true;
  472. };
  473. // No type is large enough.
  474. template <typename Lhs, typename Rhs>
  475. struct BigEnoughPromotion<Lhs, Rhs, true, false> {
  476. using type = typename MaxExponentPromotion<Lhs, Rhs>::type;
  477. static const bool is_contained = false;
  478. };
  479. // We can statically check if operations on the provided types can wrap, so we
  480. // can skip the checked operations if they're not needed. So, for an integer we
  481. // care if the destination type preserves the sign and is twice the width of
  482. // the source.
  483. template <typename T, typename Lhs, typename Rhs = Lhs>
  484. struct IsIntegerArithmeticSafe {
  485. static const bool value =
  486. !std::is_floating_point<T>::value &&
  487. !std::is_floating_point<Lhs>::value &&
  488. !std::is_floating_point<Rhs>::value &&
  489. std::is_signed<T>::value >= std::is_signed<Lhs>::value &&
  490. IntegerBitsPlusSign<T>::value >= (2 * IntegerBitsPlusSign<Lhs>::value) &&
  491. std::is_signed<T>::value >= std::is_signed<Rhs>::value &&
  492. IntegerBitsPlusSign<T>::value >= (2 * IntegerBitsPlusSign<Rhs>::value);
  493. };
  494. // Promotes to a type that can represent any possible result of a binary
  495. // arithmetic operation with the source types.
  496. template <typename Lhs,
  497. typename Rhs,
  498. bool is_promotion_possible = IsIntegerArithmeticSafe<
  499. typename std::conditional<std::is_signed<Lhs>::value ||
  500. std::is_signed<Rhs>::value,
  501. intmax_t,
  502. uintmax_t>::type,
  503. typename MaxExponentPromotion<Lhs, Rhs>::type>::value>
  504. struct FastIntegerArithmeticPromotion;
  505. template <typename Lhs, typename Rhs>
  506. struct FastIntegerArithmeticPromotion<Lhs, Rhs, true> {
  507. using type =
  508. typename TwiceWiderInteger<typename MaxExponentPromotion<Lhs, Rhs>::type,
  509. std::is_signed<Lhs>::value ||
  510. std::is_signed<Rhs>::value>::type;
  511. static_assert(IsIntegerArithmeticSafe<type, Lhs, Rhs>::value, "");
  512. static const bool is_contained = true;
  513. };
  514. template <typename Lhs, typename Rhs>
  515. struct FastIntegerArithmeticPromotion<Lhs, Rhs, false> {
  516. using type = typename BigEnoughPromotion<Lhs, Rhs>::type;
  517. static const bool is_contained = false;
  518. };
  519. // Extracts the underlying type from an enum.
  520. template <typename T, bool is_enum = std::is_enum<T>::value>
  521. struct ArithmeticOrUnderlyingEnum;
  522. template <typename T>
  523. struct ArithmeticOrUnderlyingEnum<T, true> {
  524. using type = typename std::underlying_type<T>::type;
  525. static const bool value = std::is_arithmetic<type>::value;
  526. };
  527. template <typename T>
  528. struct ArithmeticOrUnderlyingEnum<T, false> {
  529. using type = T;
  530. static const bool value = std::is_arithmetic<type>::value;
  531. };
  532. // The following are helper templates used in the CheckedNumeric class.
  533. template <typename T>
  534. class CheckedNumeric;
  535. template <typename T>
  536. class ClampedNumeric;
  537. template <typename T>
  538. class StrictNumeric;
  539. // Used to treat CheckedNumeric and arithmetic underlying types the same.
  540. template <typename T>
  541. struct UnderlyingType {
  542. using type = typename ArithmeticOrUnderlyingEnum<T>::type;
  543. static const bool is_numeric = std::is_arithmetic<type>::value;
  544. static const bool is_checked = false;
  545. static const bool is_clamped = false;
  546. static const bool is_strict = false;
  547. };
  548. template <typename T>
  549. struct UnderlyingType<CheckedNumeric<T>> {
  550. using type = T;
  551. static const bool is_numeric = true;
  552. static const bool is_checked = true;
  553. static const bool is_clamped = false;
  554. static const bool is_strict = false;
  555. };
  556. template <typename T>
  557. struct UnderlyingType<ClampedNumeric<T>> {
  558. using type = T;
  559. static const bool is_numeric = true;
  560. static const bool is_checked = false;
  561. static const bool is_clamped = true;
  562. static const bool is_strict = false;
  563. };
  564. template <typename T>
  565. struct UnderlyingType<StrictNumeric<T>> {
  566. using type = T;
  567. static const bool is_numeric = true;
  568. static const bool is_checked = false;
  569. static const bool is_clamped = false;
  570. static const bool is_strict = true;
  571. };
  572. template <typename L, typename R>
  573. struct IsCheckedOp {
  574. static const bool value =
  575. UnderlyingType<L>::is_numeric && UnderlyingType<R>::is_numeric &&
  576. (UnderlyingType<L>::is_checked || UnderlyingType<R>::is_checked);
  577. };
  578. template <typename L, typename R>
  579. struct IsClampedOp {
  580. static const bool value =
  581. UnderlyingType<L>::is_numeric && UnderlyingType<R>::is_numeric &&
  582. (UnderlyingType<L>::is_clamped || UnderlyingType<R>::is_clamped) &&
  583. !(UnderlyingType<L>::is_checked || UnderlyingType<R>::is_checked);
  584. };
  585. template <typename L, typename R>
  586. struct IsStrictOp {
  587. static const bool value =
  588. UnderlyingType<L>::is_numeric && UnderlyingType<R>::is_numeric &&
  589. (UnderlyingType<L>::is_strict || UnderlyingType<R>::is_strict) &&
  590. !(UnderlyingType<L>::is_checked || UnderlyingType<R>::is_checked) &&
  591. !(UnderlyingType<L>::is_clamped || UnderlyingType<R>::is_clamped);
  592. };
  593. // as_signed<> returns the supplied integral value (or integral castable
  594. // Numeric template) cast as a signed integral of equivalent precision.
  595. // I.e. it's mostly an alias for: static_cast<std::make_signed<T>::type>(t)
  596. template <typename Src>
  597. constexpr typename std::make_signed<
  598. typename base::internal::UnderlyingType<Src>::type>::type
  599. as_signed(const Src value) {
  600. static_assert(std::is_integral<decltype(as_signed(value))>::value,
  601. "Argument must be a signed or unsigned integer type.");
  602. return static_cast<decltype(as_signed(value))>(value);
  603. }
  604. // as_unsigned<> returns the supplied integral value (or integral castable
  605. // Numeric template) cast as an unsigned integral of equivalent precision.
  606. // I.e. it's mostly an alias for: static_cast<std::make_unsigned<T>::type>(t)
  607. template <typename Src>
  608. constexpr typename std::make_unsigned<
  609. typename base::internal::UnderlyingType<Src>::type>::type
  610. as_unsigned(const Src value) {
  611. static_assert(std::is_integral<decltype(as_unsigned(value))>::value,
  612. "Argument must be a signed or unsigned integer type.");
  613. return static_cast<decltype(as_unsigned(value))>(value);
  614. }
  615. template <typename L, typename R>
  616. constexpr bool IsLessImpl(const L lhs,
  617. const R rhs,
  618. const RangeCheck l_range,
  619. const RangeCheck r_range) {
  620. return l_range.IsUnderflow() || r_range.IsOverflow() ||
  621. (l_range == r_range &&
  622. static_cast<decltype(lhs + rhs)>(lhs) <
  623. static_cast<decltype(lhs + rhs)>(rhs));
  624. }
  625. template <typename L, typename R>
  626. struct IsLess {
  627. static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
  628. "Types must be numeric.");
  629. static constexpr bool Test(const L lhs, const R rhs) {
  630. return IsLessImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs),
  631. DstRangeRelationToSrcRange<L>(rhs));
  632. }
  633. };
  634. template <typename L, typename R>
  635. constexpr bool IsLessOrEqualImpl(const L lhs,
  636. const R rhs,
  637. const RangeCheck l_range,
  638. const RangeCheck r_range) {
  639. return l_range.IsUnderflow() || r_range.IsOverflow() ||
  640. (l_range == r_range &&
  641. static_cast<decltype(lhs + rhs)>(lhs) <=
  642. static_cast<decltype(lhs + rhs)>(rhs));
  643. }
  644. template <typename L, typename R>
  645. struct IsLessOrEqual {
  646. static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
  647. "Types must be numeric.");
  648. static constexpr bool Test(const L lhs, const R rhs) {
  649. return IsLessOrEqualImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs),
  650. DstRangeRelationToSrcRange<L>(rhs));
  651. }
  652. };
  653. template <typename L, typename R>
  654. constexpr bool IsGreaterImpl(const L lhs,
  655. const R rhs,
  656. const RangeCheck l_range,
  657. const RangeCheck r_range) {
  658. return l_range.IsOverflow() || r_range.IsUnderflow() ||
  659. (l_range == r_range &&
  660. static_cast<decltype(lhs + rhs)>(lhs) >
  661. static_cast<decltype(lhs + rhs)>(rhs));
  662. }
  663. template <typename L, typename R>
  664. struct IsGreater {
  665. static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
  666. "Types must be numeric.");
  667. static constexpr bool Test(const L lhs, const R rhs) {
  668. return IsGreaterImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs),
  669. DstRangeRelationToSrcRange<L>(rhs));
  670. }
  671. };
  672. template <typename L, typename R>
  673. constexpr bool IsGreaterOrEqualImpl(const L lhs,
  674. const R rhs,
  675. const RangeCheck l_range,
  676. const RangeCheck r_range) {
  677. return l_range.IsOverflow() || r_range.IsUnderflow() ||
  678. (l_range == r_range &&
  679. static_cast<decltype(lhs + rhs)>(lhs) >=
  680. static_cast<decltype(lhs + rhs)>(rhs));
  681. }
  682. template <typename L, typename R>
  683. struct IsGreaterOrEqual {
  684. static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
  685. "Types must be numeric.");
  686. static constexpr bool Test(const L lhs, const R rhs) {
  687. return IsGreaterOrEqualImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs),
  688. DstRangeRelationToSrcRange<L>(rhs));
  689. }
  690. };
  691. template <typename L, typename R>
  692. struct IsEqual {
  693. static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
  694. "Types must be numeric.");
  695. static constexpr bool Test(const L lhs, const R rhs) {
  696. return DstRangeRelationToSrcRange<R>(lhs) ==
  697. DstRangeRelationToSrcRange<L>(rhs) &&
  698. static_cast<decltype(lhs + rhs)>(lhs) ==
  699. static_cast<decltype(lhs + rhs)>(rhs);
  700. }
  701. };
  702. template <typename L, typename R>
  703. struct IsNotEqual {
  704. static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
  705. "Types must be numeric.");
  706. static constexpr bool Test(const L lhs, const R rhs) {
  707. return DstRangeRelationToSrcRange<R>(lhs) !=
  708. DstRangeRelationToSrcRange<L>(rhs) ||
  709. static_cast<decltype(lhs + rhs)>(lhs) !=
  710. static_cast<decltype(lhs + rhs)>(rhs);
  711. }
  712. };
  713. // These perform the actual math operations on the CheckedNumerics.
  714. // Binary arithmetic operations.
  715. template <template <typename, typename> class C, typename L, typename R>
  716. constexpr bool SafeCompare(const L lhs, const R rhs) {
  717. static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
  718. "Types must be numeric.");
  719. using Promotion = BigEnoughPromotion<L, R>;
  720. using BigType = typename Promotion::type;
  721. return Promotion::is_contained
  722. // Force to a larger type for speed if both are contained.
  723. ? C<BigType, BigType>::Test(
  724. static_cast<BigType>(static_cast<L>(lhs)),
  725. static_cast<BigType>(static_cast<R>(rhs)))
  726. // Let the template functions figure it out for mixed types.
  727. : C<L, R>::Test(lhs, rhs);
  728. }
  729. template <typename Dst, typename Src>
  730. constexpr bool IsMaxInRangeForNumericType() {
  731. return IsGreaterOrEqual<Dst, Src>::Test(std::numeric_limits<Dst>::max(),
  732. std::numeric_limits<Src>::max());
  733. }
  734. template <typename Dst, typename Src>
  735. constexpr bool IsMinInRangeForNumericType() {
  736. return IsLessOrEqual<Dst, Src>::Test(std::numeric_limits<Dst>::lowest(),
  737. std::numeric_limits<Src>::lowest());
  738. }
  739. template <typename Dst, typename Src>
  740. constexpr Dst CommonMax() {
  741. return !IsMaxInRangeForNumericType<Dst, Src>()
  742. ? Dst(std::numeric_limits<Dst>::max())
  743. : Dst(std::numeric_limits<Src>::max());
  744. }
  745. template <typename Dst, typename Src>
  746. constexpr Dst CommonMin() {
  747. return !IsMinInRangeForNumericType<Dst, Src>()
  748. ? Dst(std::numeric_limits<Dst>::lowest())
  749. : Dst(std::numeric_limits<Src>::lowest());
  750. }
  751. // This is a wrapper to generate return the max or min for a supplied type.
  752. // If the argument is false, the returned value is the maximum. If true the
  753. // returned value is the minimum.
  754. template <typename Dst, typename Src = Dst>
  755. constexpr Dst CommonMaxOrMin(bool is_min) {
  756. return is_min ? CommonMin<Dst, Src>() : CommonMax<Dst, Src>();
  757. }
  758. } // namespace internal
  759. } // namespace base
  760. #endif // BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_