chromium/third_party/dawn/src/tint/lang/core/number.h

// Copyright 2021 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
//    contributors may be used to endorse or promote products derived from
//    this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef SRC_TINT_LANG_CORE_NUMBER_H_
#define SRC_TINT_LANG_CORE_NUMBER_H_

#include <stdint.h>
#include <cmath>
#include <functional>
#include <limits>
#include <optional>

#include "src/tint/utils/macros/compiler.h"
#include "src/tint/utils/result/result.h"
#include "src/tint/utils/text/string_stream.h"
#include "src/tint/utils/traits/traits.h"

// Forward declaration
namespace tint::core {
/// Number wraps a integer or floating point number, enforcing explicit casting.
template <typename T>
struct Number;
}  // namespace tint::core

namespace tint::core::detail {
/// Base template for IsNumber
template <typename T>
struct IsNumber : std::false_type {};

/// Specialization for IsNumber
IsNumber<Number<T>>;

/// An empty structure used as a unique template type for Number when
/// specializing for the f16 type.
struct NumberKindF16 {};

/// Helper for obtaining the underlying type for a Number.
template <typename T>
struct NumberUnwrapper {};

/// NumberUnwrapper specialization for Number<T>.
NumberUnwrapper<Number<T>>;

}  // namespace tint::core::detail

namespace tint::core {

/// Evaluates to true iff T is a Number
IsNumber;

/// Resolves to the underlying type for a Number.
UnwrapNumber;

/// Evaluates to true iff T or Number<T> is a floating-point type or is NumberKindF16.
IsFloatingPoint;

/// Evaluates to true iff T or Number<T> is an integral type.
IsIntegral;

/// Evaluates to true iff T or Number<T> is a signed integer type.
IsSignedIntegral;

/// Evaluates to true iff T or Number<T> is an unsigned integer type.
IsUnsignedIntegral;

/// Evaluates to true iff T is an integer type, floating-point type or is NumberKindF16.
IsNumeric;

/// Returns the bit width of T
BitWidth;

/// NumberBase is a CRTP base class for Number<T>
template <typename NumberT>
struct NumberBase {};

/// Number wraps a integer or floating point number, enforcing explicit casting.
template <typename T>
struct Number : NumberBase<Number<T>> {};

/// Writes the number to the ostream.
/// @param out the stream to write to
/// @param num the Number
/// @return the stream so calls can be chained
template <typename STREAM, typename T, typename = traits::EnableIfIsOStream<STREAM>>
auto& operator<<(STREAM& out, Number<T> num) {}

/// The partial specification of Number for f16 type, storing the f16 value as float,
/// and enforcing proper explicit casting.
template <>
struct Number<tint::core::detail::NumberKindF16>
    : NumberBase<Number<tint::core::detail::NumberKindF16>> {};

/// `AInt` is a type alias to `Number<int64_t>`.
AInt;
/// `AFloat` is a type alias to `Number<double>`.
AFloat;

/// `i8` is a type alias to `Number<int8_t>`.
i8;
/// `i32` is a type alias to `Number<int32_t>`.
i32;
/// `u8` is a type alias to `Number<uint8_t>`.
u8;
/// `u32` is a type alias to `Number<uint32_t>`.
u32;
/// `f32` is a type alias to `Number<float>`
f32;
/// `f16` is a type alias to `Number<detail::NumberKindF16>`, which should be IEEE 754 binary16.
/// However since C++ don't have native binary16 type, the value is stored as float.
f16;

/// The algorithms in this module require support for infinity and quiet NaNs on
/// floating point types.
static_assert;
static_assert;
static_assert;
static_assert;

kPi;

/// True iff T is an abstract number type
IsAbstract;

/// @returns the friendly name of Number type T
template <typename T, tint::traits::EnableIf<IsNumber<T>>* = nullptr>
const char* FriendlyName() {}

/// @returns the friendly name of T when T is bool
template <typename T, tint::traits::EnableIf<std::is_same_v<T, bool>>* = nullptr>
const char* FriendlyName() {}

/// Enumerator of failure reasons when converting from one number to another.
enum class ConversionFailure {};

/// Writes the conversion failure message to the ostream.
/// @param out the stream to write to
/// @param failure the ConversionFailure
/// @return the stream so calls can be chained
template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
auto& operator<<(STREAM& out, ConversionFailure failure) {}

/// Converts a number from one type to another, checking that the value fits in the target type.
/// @param num the value to convert
/// @returns the resulting value of the conversion, or a failure reason.
template <typename TO, typename FROM>
tint::Result<TO, ConversionFailure> CheckedConvert(Number<FROM> num) {}

/// Equality operator.
/// @param a the LHS number
/// @param b the RHS number
/// @returns true if the numbers `a` and `b` are exactly equal.
/// For floating point types, negative zero equals zero.
/// IEEE 754 says "Comparison shall ignore the sign of zero (so +0 = -0)."
template <typename A, typename B>
bool operator==(Number<A> a, Number<B> b) {}

/// Inequality operator.
/// @param a the LHS number
/// @param b the RHS number
/// @returns true if the numbers `a` and `b` are exactly unequal. Also considers sign bit.
template <typename A, typename B>
bool operator!=(Number<A> a, Number<B> b) {}

/// Equality operator.
/// @param a the LHS number
/// @param b the RHS number
/// @returns true if the numbers `a` and `b` are exactly equal.
template <typename A, typename B>
std::enable_if_t<IsNumeric<B>, bool> operator==(Number<A> a, B b) {}

/// Inequality operator.
/// @param a the LHS number
/// @param b the RHS number
/// @returns true if the numbers `a` and `b` are exactly unequal.
template <typename A, typename B>
std::enable_if_t<IsNumeric<B>, bool> operator!=(Number<A> a, B b) {}

/// Equality operator.
/// @param a the LHS number
/// @param b the RHS number
/// @returns true if the numbers `a` and `b` are exactly equal.
template <typename A, typename B>
std::enable_if_t<IsNumeric<A>, bool> operator==(A a, Number<B> b) {}

/// Inequality operator.
/// @param a the LHS number
/// @param b the RHS number
/// @returns true if the numbers `a` and `b` are exactly unequal.
template <typename A, typename B>
std::enable_if_t<IsNumeric<A>, bool> operator!=(A a, Number<B> b) {}

/// Define 'TINT_HAS_OVERFLOW_BUILTINS' if the compiler provide overflow checking builtins.
/// If the compiler does not support these builtins, then these are emulated with algorithms
/// described in:
/// https://wiki.sei.cmu.edu/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow
#if defined(__GNUC__) && __GNUC__ >= 5
#define TINT_HAS_OVERFLOW_BUILTINS
#elif defined(__clang__)
#if __has_builtin(__builtin_add_overflow) && __has_builtin(__builtin_mul_overflow)
#define TINT_HAS_OVERFLOW_BUILTINS
#endif
#endif

/// @param a the LHS number
/// @param b the RHS number
/// @returns a + b, or an empty optional if the resulting value overflowed the AInt
inline std::optional<AInt> CheckedAdd(AInt a, AInt b) {}

/// @param a the LHS number
/// @param b the RHS number
/// @returns a + b, or an empty optional if the resulting value overflowed the float value
template <typename FloatingPointT,
          typename = tint::traits::EnableIf<IsFloatingPoint<FloatingPointT>>>
inline std::optional<FloatingPointT> CheckedAdd(FloatingPointT a, FloatingPointT b) {}

/// @param a the LHS number
/// @param b the RHS number
/// @returns a - b, or an empty optional if the resulting value overflowed the AInt
inline std::optional<AInt> CheckedSub(AInt a, AInt b) {}

/// @param a the LHS number
/// @param b the RHS number
/// @returns a + b, or an empty optional if the resulting value overflowed the float value
template <typename FloatingPointT,
          typename = tint::traits::EnableIf<IsFloatingPoint<FloatingPointT>>>
inline std::optional<FloatingPointT> CheckedSub(FloatingPointT a, FloatingPointT b) {}

/// @param a the LHS number
/// @param b the RHS number
/// @returns a * b, or an empty optional if the resulting value overflowed the AInt
inline std::optional<AInt> CheckedMul(AInt a, AInt b) {}

/// @param a the LHS number
/// @param b the RHS number
/// @returns a * b, or an empty optional if the resulting value overflowed the float value
template <typename FloatingPointT,
          typename = tint::traits::EnableIf<IsFloatingPoint<FloatingPointT>>>
inline std::optional<FloatingPointT> CheckedMul(FloatingPointT a, FloatingPointT b) {}

/// @param a the LHS number
/// @param b the RHS number
/// @returns a / b, or an empty optional if the resulting value overflowed the AInt
inline std::optional<AInt> CheckedDiv(AInt a, AInt b) {}

/// @param a the LHS number
/// @param b the RHS number
/// @returns a / b, or an empty optional if the resulting value overflowed the float value
template <typename FloatingPointT,
          typename = tint::traits::EnableIf<IsFloatingPoint<FloatingPointT>>>
inline std::optional<FloatingPointT> CheckedDiv(FloatingPointT a, FloatingPointT b) {}

namespace detail {
/// @param e1 the LHS number
/// @param e2 the RHS number
/// @returns the remainder of e1 / e2
template <typename T>
inline T Mod(T e1, T e2) {}
}  // namespace detail

/// @param a the LHS number
/// @param b the RHS number
/// @returns the remainder of a / b, or an empty optional if the resulting value overflowed the AInt
inline std::optional<AInt> CheckedMod(AInt a, AInt b) {}

/// @param a the LHS number
/// @param b the RHS number
/// @returns the remainder of a / b, or an empty optional if the resulting value overflowed the
/// float value
template <typename FloatingPointT,
          typename = tint::traits::EnableIf<IsFloatingPoint<FloatingPointT>>>
inline std::optional<FloatingPointT> CheckedMod(FloatingPointT a, FloatingPointT b) {}

/// @param a the LHS number of the multiply
/// @param b the RHS number of the multiply
/// @param c the RHS number of the addition
/// @returns a * b + c, or an empty optional if the value overflowed the AInt
inline std::optional<AInt> CheckedMadd(AInt a, AInt b, AInt c) {}

/// @param base the base number of the exponent operation
/// @param exp the exponent
/// @returns the value of `base` raised to the power `exp`, or an empty optional if the operation
/// cannot be performed.
template <typename FloatingPointT,
          typename = tint::traits::EnableIf<IsFloatingPoint<FloatingPointT>>>
inline std::optional<FloatingPointT> CheckedPow(FloatingPointT base, FloatingPointT exp) {}

}  // namespace tint::core

namespace tint::core::number_suffixes {

/// Literal suffix for abstract integer literals
inline AInt operator""_a(unsigned long long int value) {}

/// Literal suffix for abstract float literals
inline AFloat operator""_a(long double value) {}

/// Literal suffix for i32 literals
inline i32 operator""_i(unsigned long long int value) {}

/// Literal suffix for u32 literals
inline u32 operator""_u(unsigned long long int value) {}

/// Literal suffix for f32 literals
inline f32 operator""_f(long double value) {}

/// Literal suffix for f32 literals
inline f32 operator""_f(unsigned long long int value) {}

/// Literal suffix for f16 literals
inline f16 operator""_h(long double value) {}

/// Literal suffix for f16 literals
inline f16 operator""_h(unsigned long long int value) {}

}  // namespace tint::core::number_suffixes

namespace std {

/// Custom std::hash specialization for tint::Number<T>
hash<tint::core::Number<T>>;

}  // namespace std

#endif  // SRC_TINT_LANG_CORE_NUMBER_H_