#ifndef BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_
#define BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_
#include <concepts>
#include <type_traits>
#include "base/numerics/safe_conversions.h"
#if defined(__asmjs__) || defined(__wasm__)
#define BASE_HAS_OPTIMIZED_SAFE_MATH (0)
#else
#include "base/numerics/safe_math_clang_gcc_impl.h"
#define BASE_HAS_OPTIMIZED_SAFE_MATH (1)
#endif
namespace base {
namespace numerics_internal {
#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*) {
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*) {
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*) {
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) {
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) {
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) {
return CheckOnFailure::template HandleFailure<V>();
}
};
template <typename T>
struct ClampedNegFastOp {
static const bool is_supported = false;
static constexpr T Do(T) {
return CheckOnFailure::template HandleFailure<T>();
}
};
#endif
#undef BASE_HAS_OPTIMIZED_SAFE_MATH
template <typename Numeric>
struct UnsignedOrFloatForSize;
template <typename Numeric>
requires(std::integral<Numeric>)
struct UnsignedOrFloatForSize<Numeric> {
using type = typename std::make_unsigned<Numeric>::type;
};
template <typename Numeric>
requires(std::floating_point<Numeric>)
struct UnsignedOrFloatForSize<Numeric> {
using type = Numeric;
};
template <typename T>
requires(std::integral<T>)
constexpr T NegateWrapper(T value) {
using UnsignedT = typename std::make_unsigned<T>::type;
return static_cast<T>(UnsignedT(0) - static_cast<UnsignedT>(value));
}
template <typename T>
requires(std::floating_point<T>)
constexpr T NegateWrapper(T value) {
return -value;
}
template <typename T>
requires(std::integral<T>)
constexpr typename std::make_unsigned<T>::type InvertWrapper(T value) {
return ~value;
}
template <typename T>
requires(std::integral<T>)
constexpr T AbsWrapper(T value) {
return static_cast<T>(SafeUnsignedAbs(value));
}
template <typename T>
requires(std::floating_point<T>)
constexpr T AbsWrapper(T value) {
return value < 0 ? -value : value;
}
template <template <typename, typename> class M,
typename L,
typename R,
typename Math = M<UnderlyingType<L>, UnderlyingType<R>>>
requires requires { typename Math::result_type; }
struct MathWrapper {
using math = Math;
using type = typename math::result_type;
};
#define BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME) \
template <typename L, typename R, typename... Args> \
constexpr auto CL_ABBR##OP_NAME(L lhs, R rhs, 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) \
\
template <typename L, typename R> \
requires(Is##CLASS##Op<L, R>) \
constexpr CLASS##Numeric< \
typename MathWrapper<CLASS##OP_NAME##Op, L, R>::type> \
operator OP(L lhs, R rhs) { \
return decltype(lhs OP rhs)::template MathOp<CLASS##OP_NAME##Op>(lhs, \
rhs); \
} \
\
template <typename L> \
requires std::is_arithmetic_v<L> \
template <typename R> \
constexpr CLASS##Numeric<L>& CLASS##Numeric<L>::operator CMP_OP(R rhs) { \
return MathOp<CLASS##OP_NAME##Op>(rhs); \
} \
\
BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME)
}
}
#endif