chromium/base/allocator/partition_allocator/src/partition_alloc/partition_alloc_base/numerics/clamped_math_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_CLAMPED_MATH_IMPL_H_
#define PARTITION_ALLOC_PARTITION_ALLOC_BASE_NUMERICS_CLAMPED_MATH_IMPL_H_

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

#include "partition_alloc/partition_alloc_base/numerics/checked_math.h"
#include "partition_alloc/partition_alloc_base/numerics/safe_conversions.h"
#include "partition_alloc/partition_alloc_base/numerics/safe_math_shared_impl.h"

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

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

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

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

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

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

template <typename T, typename U, class Enable = void>
struct ClampedAddOp {};

ClampedAddOp<T, U, typename std::enable_if<std::is_integral_v<T> && std::is_integral_v<U>>::type>;

template <typename T, typename U, class Enable = void>
struct ClampedSubOp {};

ClampedSubOp<T, U, typename std::enable_if<std::is_integral_v<T> && std::is_integral_v<U>>::type>;

template <typename T, typename U, class Enable = void>
struct ClampedMulOp {};

ClampedMulOp<T, U, typename std::enable_if<std::is_integral_v<T> && std::is_integral_v<U>>::type>;

template <typename T, typename U, class Enable = void>
struct ClampedDivOp {};

ClampedDivOp<T, U, typename std::enable_if<std::is_integral_v<T> && std::is_integral_v<U>>::type>;

template <typename T, typename U, class Enable = void>
struct ClampedModOp {};

ClampedModOp<T, U, typename std::enable_if<std::is_integral_v<T> && std::is_integral_v<U>>::type>;

template <typename T, typename U, class Enable = void>
struct ClampedLshOp {};

// Left shift. Non-zero values saturate in the direction of the sign. A zero
// shifted by any value always results in zero.
ClampedLshOp<T, U, typename std::enable_if<std::is_integral_v<T> && std::is_integral_v<U>>::type>;

template <typename T, typename U, class Enable = void>
struct ClampedRshOp {};

// Right shift. Negative values saturate to -1. Positive or 0 saturates to 0.
ClampedRshOp<T, U, typename std::enable_if<std::is_integral_v<T> && std::is_integral_v<U>>::type>;

template <typename T, typename U, class Enable = void>
struct ClampedAndOp {};

ClampedAndOp<T, U, typename std::enable_if<std::is_integral_v<T> && std::is_integral_v<U>>::type>;

template <typename T, typename U, class Enable = void>
struct ClampedOrOp {};

// For simplicity we promote to unsigned integers.
ClampedOrOp<T, U, typename std::enable_if<std::is_integral_v<T> && std::is_integral_v<U>>::type>;

template <typename T, typename U, class Enable = void>
struct ClampedXorOp {};

// For simplicity we support only unsigned integers.
ClampedXorOp<T, U, typename std::enable_if<std::is_integral_v<T> && std::is_integral_v<U>>::type>;

template <typename T, typename U, class Enable = void>
struct ClampedMaxOp {};

ClampedMaxOp<T, U, typename std::enable_if<std::is_arithmetic_v<T> && std::is_arithmetic_v<U>>::type>;

template <typename T, typename U, class Enable = void>
struct ClampedMinOp {};

ClampedMinOp<T, U, typename std::enable_if<std::is_arithmetic_v<T> && std::is_arithmetic_v<U>>::type>;

// This is just boilerplate that wraps the standard floating point arithmetic.
// A macro isn't the nicest solution, but it beats rewriting these repeatedly.
#define PA_BASE_FLOAT_ARITHMETIC_OPS

PA_BASE_FLOAT_ARITHMETIC_OPS
PA_BASE_FLOAT_ARITHMETIC_OPS
PA_BASE_FLOAT_ARITHMETIC_OPS
PA_BASE_FLOAT_ARITHMETIC_OPS

#undef PA_BASE_FLOAT_ARITHMETIC_OPS

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

#endif  // PARTITION_ALLOC_PARTITION_ALLOC_BASE_NUMERICS_CLAMPED_MATH_IMPL_H_