// -*- C++ -*-
#ifndef _EZCXX_LIMITS
#define _EZCXX_LIMITS

#pragma clang system_header

namespace std {

enum float_denorm_style {
    denorm_indeterminate = -1,
    denorm_absent        = 0,
    denorm_present       = 1
};

enum float_round_style {
    round_indeterminate       = -1,
    round_toward_zero         = 0,
    round_to_nearest          = 1,
    round_toward_infinity     = 2,
    round_toward_neg_infinity = 3
};

namespace __detail::numeric_limits {
struct __base {
    static constexpr bool is_specialized = false;

    static constexpr bool is_signed = false, is_integer = false, is_exact = false;
    static constexpr int radix = 0;

    static constexpr int digits = 0, digits10 = 0;
#if __cplusplus >= 201103L
    static constexpr int max_digits10 = 0;
#endif

    static constexpr int min_exponent = 0, min_exponent10 = 0, max_exponent = 0, max_exponent10 = 0;

    static constexpr bool has_infinity = false, has_quiet_NaN = false, has_signaling_NaN = false, has_denorm_loss = false;
    static constexpr float_denorm_style has_denorm = denorm_absent;

    static constexpr bool is_iec559 = false, is_bounded = false, is_modulo = false;

    static constexpr bool traps = false, tinyness_before = false;
    static constexpr float_round_style round_style = round_toward_zero;
};
struct __arithmetic_base : __base {
    static constexpr bool is_specialized = true;

    static constexpr bool is_bounded = true;
};
struct __integral_base : __arithmetic_base {
    static constexpr bool is_integer = true, is_exact = true;
    static constexpr int radix = 2;
};
template<typename _Tp>
struct __integral : __integral_base {
    static constexpr bool is_signed = _Tp(_Tp() - 1) < _Tp();
    static constexpr bool is_modulo = !is_signed;

    static constexpr int digits = __CHAR_BIT__ * sizeof(_Tp) - is_signed;
    static constexpr int digits10 = digits * 643L / 2136;

    static constexpr _Tp max() noexcept { return (((_Tp(1) << (digits - 1)) - 1) << 1) + 1; }
    static constexpr _Tp min() noexcept { return _Tp(-max()) - 1; }
#if __cplusplus >= 201103L
    static constexpr _Tp lowest() noexcept { return min(); }
#endif

    static constexpr _Tp epsilon() noexcept { return _Tp(); }
    static constexpr _Tp round_error() noexcept { return _Tp(); }

    static constexpr _Tp infinity() noexcept { return _Tp(); }
    static constexpr _Tp quiet_NaN() noexcept { return _Tp(); }
    static constexpr _Tp signaling_NaN() noexcept { return _Tp(); }
    static constexpr _Tp denorm_min() noexcept { return _Tp(); }
};
struct __floating_point_base : __arithmetic_base {
    static constexpr bool is_signed = true;

    static constexpr int radix = __FLT_RADIX__;
};
} // namespace __detail::numeric_limits

template<class _Tp> struct numeric_limits : __detail::numeric_limits::__base {
    static constexpr _Tp min() noexcept { return _Tp(); }
    static constexpr _Tp max() noexcept { return _Tp(); }
#if __cplusplus >= 201103L
    static constexpr _Tp lowest() noexcept { return _Tp(); }
#endif

    static constexpr _Tp epsilon() noexcept { return _Tp(); }
    static constexpr _Tp round_error() noexcept { return _Tp(); }

    static constexpr _Tp infinity() noexcept { return _Tp(); }
    static constexpr _Tp quiet_NaN() noexcept { return _Tp(); }
    static constexpr _Tp signaling_NaN() noexcept { return _Tp(); }
    static constexpr _Tp denorm_min() noexcept { return _Tp(); }
};

template<> struct numeric_limits<              bool> : __detail::numeric_limits::__integral<              bool> { static constexpr int digits = 1, digits10 = 0; };
template<> struct numeric_limits<              char> : __detail::numeric_limits::__integral<              char> {};
template<> struct numeric_limits<   signed     char> : __detail::numeric_limits::__integral<  signed      char> {};
template<> struct numeric_limits< unsigned     char> : __detail::numeric_limits::__integral<unsigned      char> {};
template<> struct numeric_limits<           wchar_t> : __detail::numeric_limits::__integral<           wchar_t> {};
#if __cplusplus >= 202002L
template<> struct numeric_limits<           char8_t> : __detail::numeric_limits::__integral<           char8_t> {};
#endif
template<> struct numeric_limits<          char16_t> : __detail::numeric_limits::__integral<          char16_t> {};
template<> struct numeric_limits<          char32_t> : __detail::numeric_limits::__integral<          char32_t> {};
template<> struct numeric_limits<  signed     short> : __detail::numeric_limits::__integral<  signed     short> {};
template<> struct numeric_limits<unsigned     short> : __detail::numeric_limits::__integral<unsigned     short> {};
template<> struct numeric_limits<  signed       int> : __detail::numeric_limits::__integral<  signed       int> {};
template<> struct numeric_limits<unsigned       int> : __detail::numeric_limits::__integral<unsigned       int> {};
template<> struct numeric_limits<  signed      long> : __detail::numeric_limits::__integral<  signed      long> {};
template<> struct numeric_limits<unsigned      long> : __detail::numeric_limits::__integral<unsigned      long> {};
template<> struct numeric_limits<  signed   __int48> : __detail::numeric_limits::__integral<  signed   __int48> {};
template<> struct numeric_limits<unsigned   __int48> : __detail::numeric_limits::__integral<unsigned   __int48> {};
template<> struct numeric_limits<  signed long long> : __detail::numeric_limits::__integral<  signed long long> {};
template<> struct numeric_limits<unsigned long long> : __detail::numeric_limits::__integral<unsigned long long> {};
template<> struct numeric_limits<float> : __detail::numeric_limits::__floating_point_base {
    static constexpr int digits = __FLT_MANT_DIG__, digits10 = __FLT_DIG__;
#if __cplusplus >= 201103L
    static constexpr int max_digits10 = digits10 + 2;
#endif

    static constexpr int min_exponent = __FLT_MIN_EXP__, min_exponent10 = __FLT_MIN_10_EXP__, max_exponent = __FLT_MAX_EXP__, max_exponent10 = __FLT_MAX_10_EXP__;

    static constexpr bool has_infinity = __FLT_HAS_INFINITY__, has_quiet_NaN = __FLT_HAS_QUIET_NAN__, has_signaling_NaN = has_quiet_NaN;
    static constexpr float_denorm_style has_denorm = __FLT_HAS_DENORM__ ? denorm_present : denorm_absent;
    static constexpr bool is_iec559 = has_infinity && has_quiet_NaN && has_denorm == denorm_present;

    static constexpr float min() noexcept { return __FLT_MIN__; }
    static constexpr float max() noexcept { return __FLT_MAX__; }
#if __cplusplus >= 201103L
    static constexpr float lowest() noexcept { return -max(); }
#endif

    static constexpr float epsilon() noexcept { return __FLT_EPSILON__; }
    static constexpr float round_error() noexcept { return .5F; }

    static constexpr float infinity() noexcept { return __builtin_huge_valf(); }
    static constexpr float quiet_NaN() noexcept { return __builtin_nanf(""); }
    static constexpr float signaling_NaN() noexcept { return __builtin_nansf(""); }
    static constexpr float denorm_min() noexcept { return __FLT_DENORM_MIN__; }
};
template<> struct numeric_limits<double> : __detail::numeric_limits::__floating_point_base {
    static constexpr int digits = __DBL_MANT_DIG__, digits10 = __DBL_DIG__;
#if __cplusplus >= 201103L
    static constexpr int max_digits10 = digits10 + 2;
#endif

    static constexpr int min_exponent = __DBL_MIN_EXP__, min_exponent10 = __DBL_MIN_10_EXP__, max_exponent = __DBL_MAX_EXP__, max_exponent10 = __DBL_MAX_10_EXP__;

    static constexpr bool has_infinity = __DBL_HAS_INFINITY__, has_quiet_NaN = __DBL_HAS_QUIET_NAN__, has_signaling_NaN = has_quiet_NaN;
    static constexpr float_denorm_style has_denorm = __DBL_HAS_DENORM__ ? denorm_present : denorm_absent;
    static constexpr bool is_iec559 = has_infinity && has_quiet_NaN && has_denorm == denorm_present;

    static constexpr double min() noexcept { return __DBL_MIN__; }
    static constexpr double max() noexcept { return __DBL_MAX__; }
#if __cplusplus >= 201103L
    static constexpr double lowest() noexcept { return -max(); }
#endif

    static constexpr double epsilon() noexcept { return __DBL_EPSILON__; }
    static constexpr double round_error() noexcept { return .5; }

    static constexpr double infinity() noexcept { return __builtin_huge_val(); }
    static constexpr double quiet_NaN() noexcept { return __builtin_nan(""); }
    static constexpr double signaling_NaN() noexcept { return __builtin_nans(""); }
    static constexpr double denorm_min() noexcept { return __DBL_DENORM_MIN__; }
};
template<> struct numeric_limits<long double> : __detail::numeric_limits::__floating_point_base {
    static constexpr int digits = __LDBL_MANT_DIG__, digits10 = __LDBL_DIG__;
#if __cplusplus >= 201103L
    static constexpr int max_digits10 = digits10 + 2;
#endif

    static constexpr int min_exponent = __LDBL_MIN_EXP__, min_exponent10 = __LDBL_MIN_10_EXP__, max_exponent = __LDBL_MAX_EXP__, max_exponent10 = __LDBL_MAX_10_EXP__;

    static constexpr bool has_infinity = __LDBL_HAS_INFINITY__, has_quiet_NaN = __LDBL_HAS_QUIET_NAN__, has_signaling_NaN = has_quiet_NaN;
    static constexpr float_denorm_style has_denorm = __LDBL_HAS_DENORM__ ? denorm_present : denorm_absent;
    static constexpr bool is_iec559 = has_infinity && has_quiet_NaN && has_denorm == denorm_present;

    static constexpr long double min() noexcept { return __LDBL_MIN__; }
    static constexpr long double max() noexcept { return __LDBL_MAX__; }
#if __cplusplus >= 201103L
    static constexpr long double lowest() noexcept { return -max(); }
#endif

    static constexpr long double epsilon() noexcept { return __LDBL_EPSILON__; }
    static constexpr long double round_error() noexcept { return .5L; }

    static constexpr long double infinity() noexcept { return __builtin_huge_vall(); }
    static constexpr long double quiet_NaN() noexcept { return __builtin_nanl(""); }
    static constexpr long double signaling_NaN() noexcept { return __builtin_nansl(""); }
    static constexpr long double denorm_min() noexcept { return __LDBL_DENORM_MIN__; }
};

} // namespace std

#endif // _EZCXX_LIMITS
