// 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 #include #include #include #include #include #include #include #include "base/numerics/safe_conversions.h" #include "build/build_config.h" #if BUILDFLAG(IS_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 struct CheckedAddFastOp { static const bool is_supported = false; template static constexpr bool Do(T, U, V*) { // Force a compile failure if instantiated. return CheckOnFailure::template HandleFailure(); } }; template struct CheckedSubFastOp { static const bool is_supported = false; template static constexpr bool Do(T, U, V*) { // Force a compile failure if instantiated. return CheckOnFailure::template HandleFailure(); } }; template struct CheckedMulFastOp { static const bool is_supported = false; template static constexpr bool Do(T, U, V*) { // Force a compile failure if instantiated. return CheckOnFailure::template HandleFailure(); } }; template struct ClampedAddFastOp { static const bool is_supported = false; template static constexpr V Do(T, U) { // Force a compile failure if instantiated. return CheckOnFailure::template HandleFailure(); } }; template struct ClampedSubFastOp { static const bool is_supported = false; template static constexpr V Do(T, U) { // Force a compile failure if instantiated. return CheckOnFailure::template HandleFailure(); } }; template struct ClampedMulFastOp { static const bool is_supported = false; template static constexpr V Do(T, U) { // Force a compile failure if instantiated. return CheckOnFailure::template HandleFailure(); } }; template struct ClampedNegFastOp { static const bool is_supported = false; static constexpr T Do(T) { // Force a compile failure if instantiated. return CheckOnFailure::template HandleFailure(); } }; #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 ::value, bool IsFloat = std::is_floating_point::value> struct UnsignedOrFloatForSize; template struct UnsignedOrFloatForSize { using type = typename std::make_unsigned::type; }; template struct UnsignedOrFloatForSize { 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 occurred. template ::value>::type* = nullptr> constexpr T NegateWrapper(T value) { using UnsignedT = typename std::make_unsigned::type; // This will compile to a NEG on Intel, and is normal negation on ARM. return static_cast(UnsignedT(0) - static_cast(value)); } template < typename T, typename std::enable_if::value>::type* = nullptr> constexpr T NegateWrapper(T value) { return -value; } template ::value>::type* = nullptr> constexpr typename std::make_unsigned::type InvertWrapper(T value) { return ~value; } template ::value>::type* = nullptr> constexpr T AbsWrapper(T value) { return static_cast(SafeUnsignedAbs(value)); } template < typename T, typename std::enable_if::value>::type* = nullptr> constexpr T AbsWrapper(T value) { return value < 0 ? -value : value; } template