chromium/base/numerics/checked_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 BASE_NUMERICS_CHECKED_MATH_IMPL_H_
#define BASE_NUMERICS_CHECKED_MATH_IMPL_H_

// IWYU pragma: private, include "base/numerics/checked_math.h"

#include <stdint.h>

#include <cmath>
#include <concepts>
#include <limits>
#include <type_traits>

#include "base/numerics/safe_conversions.h"
#include "base/numerics/safe_math_shared_impl.h"  // IWYU pragma: export

namespace base {
namespace internal {

template <typename T>
constexpr bool CheckedAddImpl(T x, T y, T* result) {}

template <typename T, typename U>
struct CheckedAddOp {};

CheckedAddOp<T, U>;

template <typename T>
constexpr bool CheckedSubImpl(T x, T y, T* result) {}

template <typename T, typename U>
struct CheckedSubOp {};

CheckedSubOp<T, U>;

template <typename T>
constexpr bool CheckedMulImpl(T x, T y, T* result) {}

template <typename T, typename U>
struct CheckedMulOp {};

CheckedMulOp<T, U>;

// Division just requires a check for a zero denominator or an invalid negation
// on signed min/-1.
template <typename T, typename U>
struct CheckedDivOp {};

CheckedDivOp<T, U>;

template <typename T, typename U>
struct CheckedModOp {};

CheckedModOp<T, U>;

template <typename T, typename U>
struct CheckedLshOp {};

// Left shift. Shifts less than 0 or greater than or equal to the number
// of bits in the promoted type are undefined. Shifts of negative values
// are undefined. Otherwise it is defined when the result fits.
CheckedLshOp<T, U>;

template <typename T, typename U>
struct CheckedRshOp {};

// Right shift. Shifts less than 0 or greater than or equal to the number
// of bits in the promoted type are undefined. Otherwise, it is always defined,
// but a right shift of a negative value is implementation-dependent.
CheckedRshOp<T, U>;

template <typename T, typename U>
struct CheckedAndOp {};

// For simplicity we support only unsigned integer results.
CheckedAndOp<T, U>;

template <typename T, typename U>
struct CheckedOrOp {};

// For simplicity we support only unsigned integers.
CheckedOrOp<T, U>;

template <typename T, typename U>
struct CheckedXorOp {};

// For simplicity we support only unsigned integers.
CheckedXorOp<T, U>;

// Max doesn't really need to be implemented this way because it can't fail,
// but it makes the code much cleaner to use the MathOp wrappers.
template <typename T, typename U>
struct CheckedMaxOp {};

CheckedMaxOp<T, U>;

// Min doesn't really need to be implemented this way because it can't fail,
// but it makes the code much cleaner to use the MathOp wrappers.
template <typename T, typename U>
struct CheckedMinOp {};

CheckedMinOp<T, U>;

// 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 BASE_FLOAT_ARITHMETIC_OPS

BASE_FLOAT_ARITHMETIC_OPS
BASE_FLOAT_ARITHMETIC_OPS
BASE_FLOAT_ARITHMETIC_OPS
BASE_FLOAT_ARITHMETIC_OPS

#undef BASE_FLOAT_ARITHMETIC_OPS

// Floats carry around their validity state with them, but integers do not. So,
// we wrap the underlying value in a specialization in order to hide that detail
// and expose an interface via accessors.
enum NumericRepresentation {};

template <typename NumericType>
struct GetNumericRepresentation {};

template <typename T,
          NumericRepresentation type = GetNumericRepresentation<T>::value>
class CheckedNumericState {};

// Integrals require quite a bit of additional housekeeping to manage state.
CheckedNumericState<T, NUMERIC_INTEGER>;

// Floating points maintain their own validity, but need translation wrappers.
CheckedNumericState<T, NUMERIC_FLOATING>;

}  // namespace internal
}  // namespace base

#endif  // BASE_NUMERICS_CHECKED_MATH_IMPL_H_