safe_math_shared_impl.h 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  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. #ifndef BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_
  5. #define BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_
  6. #include <stddef.h>
  7. #include <stdint.h>
  8. #include <cassert>
  9. #include <climits>
  10. #include <cmath>
  11. #include <cstdlib>
  12. #include <limits>
  13. #include <type_traits>
  14. #include "base/numerics/safe_conversions.h"
  15. #include "build/build_config.h"
  16. #if defined(OS_ASMJS)
  17. // Optimized safe math instructions are incompatible with asmjs.
  18. #define BASE_HAS_OPTIMIZED_SAFE_MATH (0)
  19. // Where available use builtin math overflow support on Clang and GCC.
  20. #elif !defined(__native_client__) && \
  21. ((defined(__clang__) && \
  22. ((__clang_major__ > 3) || \
  23. (__clang_major__ == 3 && __clang_minor__ >= 4))) || \
  24. (defined(__GNUC__) && __GNUC__ >= 5))
  25. #include "base/numerics/safe_math_clang_gcc_impl.h"
  26. #define BASE_HAS_OPTIMIZED_SAFE_MATH (1)
  27. #else
  28. #define BASE_HAS_OPTIMIZED_SAFE_MATH (0)
  29. #endif
  30. namespace base {
  31. namespace internal {
  32. // These are the non-functioning boilerplate implementations of the optimized
  33. // safe math routines.
  34. #if !BASE_HAS_OPTIMIZED_SAFE_MATH
  35. template <typename T, typename U>
  36. struct CheckedAddFastOp {
  37. static const bool is_supported = false;
  38. template <typename V>
  39. static constexpr bool Do(T, U, V*) {
  40. // Force a compile failure if instantiated.
  41. return CheckOnFailure::template HandleFailure<bool>();
  42. }
  43. };
  44. template <typename T, typename U>
  45. struct CheckedSubFastOp {
  46. static const bool is_supported = false;
  47. template <typename V>
  48. static constexpr bool Do(T, U, V*) {
  49. // Force a compile failure if instantiated.
  50. return CheckOnFailure::template HandleFailure<bool>();
  51. }
  52. };
  53. template <typename T, typename U>
  54. struct CheckedMulFastOp {
  55. static const bool is_supported = false;
  56. template <typename V>
  57. static constexpr bool Do(T, U, V*) {
  58. // Force a compile failure if instantiated.
  59. return CheckOnFailure::template HandleFailure<bool>();
  60. }
  61. };
  62. template <typename T, typename U>
  63. struct ClampedAddFastOp {
  64. static const bool is_supported = false;
  65. template <typename V>
  66. static constexpr V Do(T, U) {
  67. // Force a compile failure if instantiated.
  68. return CheckOnFailure::template HandleFailure<V>();
  69. }
  70. };
  71. template <typename T, typename U>
  72. struct ClampedSubFastOp {
  73. static const bool is_supported = false;
  74. template <typename V>
  75. static constexpr V Do(T, U) {
  76. // Force a compile failure if instantiated.
  77. return CheckOnFailure::template HandleFailure<V>();
  78. }
  79. };
  80. template <typename T, typename U>
  81. struct ClampedMulFastOp {
  82. static const bool is_supported = false;
  83. template <typename V>
  84. static constexpr V Do(T, U) {
  85. // Force a compile failure if instantiated.
  86. return CheckOnFailure::template HandleFailure<V>();
  87. }
  88. };
  89. template <typename T>
  90. struct ClampedNegFastOp {
  91. static const bool is_supported = false;
  92. static constexpr T Do(T) {
  93. // Force a compile failure if instantiated.
  94. return CheckOnFailure::template HandleFailure<T>();
  95. }
  96. };
  97. #endif // BASE_HAS_OPTIMIZED_SAFE_MATH
  98. #undef BASE_HAS_OPTIMIZED_SAFE_MATH
  99. // This is used for UnsignedAbs, where we need to support floating-point
  100. // template instantiations even though we don't actually support the operations.
  101. // However, there is no corresponding implementation of e.g. SafeUnsignedAbs,
  102. // so the float versions will not compile.
  103. template <typename Numeric,
  104. bool IsInteger = std::is_integral<Numeric>::value,
  105. bool IsFloat = std::is_floating_point<Numeric>::value>
  106. struct UnsignedOrFloatForSize;
  107. template <typename Numeric>
  108. struct UnsignedOrFloatForSize<Numeric, true, false> {
  109. using type = typename std::make_unsigned<Numeric>::type;
  110. };
  111. template <typename Numeric>
  112. struct UnsignedOrFloatForSize<Numeric, false, true> {
  113. using type = Numeric;
  114. };
  115. // Wrap the unary operations to allow SFINAE when instantiating integrals versus
  116. // floating points. These don't perform any overflow checking. Rather, they
  117. // exhibit well-defined overflow semantics and rely on the caller to detect
  118. // if an overflow occured.
  119. template <typename T,
  120. typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
  121. constexpr T NegateWrapper(T value) {
  122. using UnsignedT = typename std::make_unsigned<T>::type;
  123. // This will compile to a NEG on Intel, and is normal negation on ARM.
  124. return static_cast<T>(UnsignedT(0) - static_cast<UnsignedT>(value));
  125. }
  126. template <
  127. typename T,
  128. typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
  129. constexpr T NegateWrapper(T value) {
  130. return -value;
  131. }
  132. template <typename T,
  133. typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
  134. constexpr typename std::make_unsigned<T>::type InvertWrapper(T value) {
  135. return ~value;
  136. }
  137. template <typename T,
  138. typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
  139. constexpr T AbsWrapper(T value) {
  140. return static_cast<T>(SafeUnsignedAbs(value));
  141. }
  142. template <
  143. typename T,
  144. typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
  145. constexpr T AbsWrapper(T value) {
  146. return value < 0 ? -value : value;
  147. }
  148. template <template <typename, typename, typename> class M,
  149. typename L,
  150. typename R>
  151. struct MathWrapper {
  152. using math = M<typename UnderlyingType<L>::type,
  153. typename UnderlyingType<R>::type,
  154. void>;
  155. using type = typename math::result_type;
  156. };
  157. // These variadic templates work out the return types.
  158. // TODO(jschuh): Rip all this out once we have C++14 non-trailing auto support.
  159. template <template <typename, typename, typename> class M,
  160. typename L,
  161. typename R,
  162. typename... Args>
  163. struct ResultType;
  164. template <template <typename, typename, typename> class M,
  165. typename L,
  166. typename R>
  167. struct ResultType<M, L, R> {
  168. using type = typename MathWrapper<M, L, R>::type;
  169. };
  170. template <template <typename, typename, typename> class M,
  171. typename L,
  172. typename R,
  173. typename... Args>
  174. struct ResultType {
  175. using type =
  176. typename ResultType<M, typename ResultType<M, L, R>::type, Args...>::type;
  177. };
  178. // The following macros are just boilerplate for the standard arithmetic
  179. // operator overloads and variadic function templates. A macro isn't the nicest
  180. // solution, but it beats rewriting these over and over again.
  181. #define BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME) \
  182. template <typename L, typename R, typename... Args> \
  183. constexpr CLASS##Numeric< \
  184. typename ResultType<CLASS##OP_NAME##Op, L, R, Args...>::type> \
  185. CL_ABBR##OP_NAME(const L lhs, const R rhs, const Args... args) { \
  186. return CL_ABBR##MathOp<CLASS##OP_NAME##Op, L, R, Args...>(lhs, rhs, \
  187. args...); \
  188. }
  189. #define BASE_NUMERIC_ARITHMETIC_OPERATORS(CLASS, CL_ABBR, OP_NAME, OP, CMP_OP) \
  190. /* Binary arithmetic operator for all CLASS##Numeric operations. */ \
  191. template <typename L, typename R, \
  192. typename std::enable_if<Is##CLASS##Op<L, R>::value>::type* = \
  193. nullptr> \
  194. constexpr CLASS##Numeric< \
  195. typename MathWrapper<CLASS##OP_NAME##Op, L, R>::type> \
  196. operator OP(const L lhs, const R rhs) { \
  197. return decltype(lhs OP rhs)::template MathOp<CLASS##OP_NAME##Op>(lhs, \
  198. rhs); \
  199. } \
  200. /* Assignment arithmetic operator implementation from CLASS##Numeric. */ \
  201. template <typename L> \
  202. template <typename R> \
  203. constexpr CLASS##Numeric<L>& CLASS##Numeric<L>::operator CMP_OP( \
  204. const R rhs) { \
  205. return MathOp<CLASS##OP_NAME##Op>(rhs); \
  206. } \
  207. /* Variadic arithmetic functions that return CLASS##Numeric. */ \
  208. BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME)
  209. } // namespace internal
  210. } // namespace base
  211. #endif // BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_