text: // 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"
  
  #ifdef __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_
  