123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 |
- // Copyright 2017 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #ifndef BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_
- #define BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_
- #include <stddef.h>
- #include <stdint.h>
- #include <cassert>
- #include <climits>
- #include <cmath>
- #include <cstdlib>
- #include <limits>
- #include <type_traits>
- #include "base/numerics/safe_conversions.h"
- #include "build/build_config.h"
- #if defined(OS_ASMJS)
- // Optimized safe math instructions are incompatible with asmjs.
- #define BASE_HAS_OPTIMIZED_SAFE_MATH (0)
- // Where available use builtin math overflow support on Clang and GCC.
- #elif !defined(__native_client__) && \
- ((defined(__clang__) && \
- ((__clang_major__ > 3) || \
- (__clang_major__ == 3 && __clang_minor__ >= 4))) || \
- (defined(__GNUC__) && __GNUC__ >= 5))
- #include "base/numerics/safe_math_clang_gcc_impl.h"
- #define BASE_HAS_OPTIMIZED_SAFE_MATH (1)
- #else
- #define BASE_HAS_OPTIMIZED_SAFE_MATH (0)
- #endif
- namespace base {
- namespace internal {
- // These are the non-functioning boilerplate implementations of the optimized
- // safe math routines.
- #if !BASE_HAS_OPTIMIZED_SAFE_MATH
- template <typename T, typename U>
- struct CheckedAddFastOp {
- static const bool is_supported = false;
- template <typename V>
- static constexpr bool Do(T, U, V*) {
- // Force a compile failure if instantiated.
- return CheckOnFailure::template HandleFailure<bool>();
- }
- };
- template <typename T, typename U>
- struct CheckedSubFastOp {
- static const bool is_supported = false;
- template <typename V>
- static constexpr bool Do(T, U, V*) {
- // Force a compile failure if instantiated.
- return CheckOnFailure::template HandleFailure<bool>();
- }
- };
- template <typename T, typename U>
- struct CheckedMulFastOp {
- static const bool is_supported = false;
- template <typename V>
- static constexpr bool Do(T, U, V*) {
- // Force a compile failure if instantiated.
- return CheckOnFailure::template HandleFailure<bool>();
- }
- };
- template <typename T, typename U>
- struct ClampedAddFastOp {
- static const bool is_supported = false;
- template <typename V>
- static constexpr V Do(T, U) {
- // Force a compile failure if instantiated.
- return CheckOnFailure::template HandleFailure<V>();
- }
- };
- template <typename T, typename U>
- struct ClampedSubFastOp {
- static const bool is_supported = false;
- template <typename V>
- static constexpr V Do(T, U) {
- // Force a compile failure if instantiated.
- return CheckOnFailure::template HandleFailure<V>();
- }
- };
- template <typename T, typename U>
- struct ClampedMulFastOp {
- static const bool is_supported = false;
- template <typename V>
- static constexpr V Do(T, U) {
- // Force a compile failure if instantiated.
- return CheckOnFailure::template HandleFailure<V>();
- }
- };
- template <typename T>
- struct ClampedNegFastOp {
- static const bool is_supported = false;
- static constexpr T Do(T) {
- // Force a compile failure if instantiated.
- return CheckOnFailure::template HandleFailure<T>();
- }
- };
- #endif // BASE_HAS_OPTIMIZED_SAFE_MATH
- #undef BASE_HAS_OPTIMIZED_SAFE_MATH
- // This is used for UnsignedAbs, where we need to support floating-point
- // template instantiations even though we don't actually support the operations.
- // However, there is no corresponding implementation of e.g. SafeUnsignedAbs,
- // so the float versions will not compile.
- template <typename Numeric,
- bool IsInteger = std::is_integral<Numeric>::value,
- bool IsFloat = std::is_floating_point<Numeric>::value>
- struct UnsignedOrFloatForSize;
- template <typename Numeric>
- struct UnsignedOrFloatForSize<Numeric, true, false> {
- using type = typename std::make_unsigned<Numeric>::type;
- };
- template <typename Numeric>
- struct UnsignedOrFloatForSize<Numeric, false, true> {
- using type = Numeric;
- };
- // Wrap the unary operations to allow SFINAE when instantiating integrals versus
- // floating points. These don't perform any overflow checking. Rather, they
- // exhibit well-defined overflow semantics and rely on the caller to detect
- // if an overflow occured.
- template <typename T,
- typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
- constexpr T NegateWrapper(T value) {
- using UnsignedT = typename std::make_unsigned<T>::type;
- // This will compile to a NEG on Intel, and is normal negation on ARM.
- return static_cast<T>(UnsignedT(0) - static_cast<UnsignedT>(value));
- }
- template <
- typename T,
- typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
- constexpr T NegateWrapper(T value) {
- return -value;
- }
- template <typename T,
- typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
- constexpr typename std::make_unsigned<T>::type InvertWrapper(T value) {
- return ~value;
- }
- template <typename T,
- typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
- constexpr T AbsWrapper(T value) {
- return static_cast<T>(SafeUnsignedAbs(value));
- }
- template <
- typename T,
- typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
- constexpr T AbsWrapper(T value) {
- return value < 0 ? -value : value;
- }
- template <template <typename, typename, typename> class M,
- typename L,
- typename R>
- struct MathWrapper {
- using math = M<typename UnderlyingType<L>::type,
- typename UnderlyingType<R>::type,
- void>;
- using type = typename math::result_type;
- };
- // These variadic templates work out the return types.
- // TODO(jschuh): Rip all this out once we have C++14 non-trailing auto support.
- template <template <typename, typename, typename> class M,
- typename L,
- typename R,
- typename... Args>
- struct ResultType;
- template <template <typename, typename, typename> class M,
- typename L,
- typename R>
- struct ResultType<M, L, R> {
- using type = typename MathWrapper<M, L, R>::type;
- };
- template <template <typename, typename, typename> class M,
- typename L,
- typename R,
- typename... Args>
- struct ResultType {
- using type =
- typename ResultType<M, typename ResultType<M, L, R>::type, Args...>::type;
- };
- // The following macros are just boilerplate for the standard arithmetic
- // operator overloads and variadic function templates. A macro isn't the nicest
- // solution, but it beats rewriting these over and over again.
- #define BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME) \
- template <typename L, typename R, typename... Args> \
- constexpr CLASS##Numeric< \
- typename ResultType<CLASS##OP_NAME##Op, L, R, Args...>::type> \
- CL_ABBR##OP_NAME(const L lhs, const R rhs, const Args... args) { \
- return CL_ABBR##MathOp<CLASS##OP_NAME##Op, L, R, Args...>(lhs, rhs, \
- args...); \
- }
- #define BASE_NUMERIC_ARITHMETIC_OPERATORS(CLASS, CL_ABBR, OP_NAME, OP, CMP_OP) \
- /* Binary arithmetic operator for all CLASS##Numeric operations. */ \
- template <typename L, typename R, \
- typename std::enable_if<Is##CLASS##Op<L, R>::value>::type* = \
- nullptr> \
- constexpr CLASS##Numeric< \
- typename MathWrapper<CLASS##OP_NAME##Op, L, R>::type> \
- operator OP(const L lhs, const R rhs) { \
- return decltype(lhs OP rhs)::template MathOp<CLASS##OP_NAME##Op>(lhs, \
- rhs); \
- } \
- /* Assignment arithmetic operator implementation from CLASS##Numeric. */ \
- template <typename L> \
- template <typename R> \
- constexpr CLASS##Numeric<L>& CLASS##Numeric<L>::operator CMP_OP( \
- const R rhs) { \
- return MathOp<CLASS##OP_NAME##Op>(rhs); \
- } \
- /* Variadic arithmetic functions that return CLASS##Numeric. */ \
- BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME)
- } // namespace internal
- } // namespace base
- #endif // BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_
|