chromium/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/numerics/safe_math_shared_impl.h

// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef PARTITION_ALLOC_PARTITION_ALLOC_BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_
#define PARTITION_ALLOC_PARTITION_ALLOC_BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_

#include <cassert>
#include <climits>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <limits>
#include <type_traits>

#include "partition_alloc/build_config.h"
#include "partition_alloc/partition_alloc_base/numerics/safe_conversions.h"

#if PA_BUILDFLAG(IS_ASMJS)
// Optimized safe math instructions are incompatible with asmjs.
#define PA_BASE_HAS_OPTIMIZED_SAFE_MATH
// 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 "partition_alloc/partition_alloc_base/numerics/safe_math_clang_gcc_impl.h"
#define PA_BASE_HAS_OPTIMIZED_SAFE_MATH
#else
#define PA_BASE_HAS_OPTIMIZED_SAFE_MATH
#endif

namespace partition_alloc::internal::base::internal {

// These are the non-functioning boilerplate implementations of the optimized
// safe math routines.
#if !PA_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  // PA_BASE_HAS_OPTIMIZED_SAFE_MATH
#undef PA_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_v<Numeric>,
          bool IsFloat = std::is_floating_point_v<Numeric>>
struct UnsignedOrFloatForSize;

UnsignedOrFloatForSize<Numeric, true, false>;

UnsignedOrFloatForSize<Numeric, false, true>;

// 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 <typename T,
          typename std::enable_if<std::is_integral_v<T>>::type* = nullptr>
constexpr T NegateWrapper(T value) {}

template <typename T,
          typename std::enable_if<std::is_floating_point_v<T>>::type* = nullptr>
constexpr T NegateWrapper(T value) {}

template <typename T,
          typename std::enable_if<std::is_integral_v<T>>::type* = nullptr>
constexpr typename std::make_unsigned<T>::type InvertWrapper(T value) {}

template <typename T,
          typename std::enable_if<std::is_integral_v<T>>::type* = nullptr>
constexpr T AbsWrapper(T value) {}

template <typename T,
          typename std::enable_if<std::is_floating_point_v<T>>::type* = nullptr>
constexpr T AbsWrapper(T value) {}

template <template <typename, typename, typename> class M,
          typename L,
          typename R>
struct MathWrapper {};

// 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 PA_BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME)

#define PA_BASE_NUMERIC_ARITHMETIC_OPERATORS(CLASS, CL_ABBR, OP_NAME, OP,  \
                                             CMP_OP)

}  // namespace partition_alloc::internal::base::internal

#endif  // PARTITION_ALLOC_PARTITION_ALLOC_BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_