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