// limits standard header (core)

// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#pragma once
#ifndef _LIMITS_
#define _LIMITS_
#include <yvals_core.h>
#if _STL_COMPILER_PREPROCESSOR
#include <cfloat>
#include <climits>
#include <cwchar>
#include <isa_availability.h>
#include <xtr1common>

#include _STL_INTRIN_HEADER

// TRANSITION, GH-2129, move down to _Arm64_popcount
#if (defined(_M_ARM64) || defined(_M_ARM64EC)) && !defined(_M_CEE_PURE) && !defined(__CUDACC__) \
    && !defined(__INTEL_COMPILER) && !defined(__clang__) // TRANSITION, LLVM-51488
#define _HAS_NEON_INTRINSICS 1
#else // ^^^ intrinsics available / intrinsics unavailable vvv
#define _HAS_NEON_INTRINSICS 0
#endif // ^^^ intrinsics unavailable ^^^

#if _HAS_NEON_INTRINSICS
#include <arm64_neon.h> // TRANSITION, GH-2129
#endif

#pragma pack(push, _CRT_PACKING)
#pragma warning(push, _STL_WARNING_LEVEL)
#pragma warning(disable : _STL_DISABLED_WARNINGS)
_STL_DISABLE_CLANG_WARNINGS
#pragma push_macro("new")
#undef new

_STD_BEGIN
// constants for different IEEE float denormalization styles
_EXPORT_STD enum _CXX23_DEPRECATE_DENORM float_denorm_style {
    denorm_indeterminate = -1,
    denorm_absent        = 0,
    denorm_present       = 1
};

_EXPORT_STD enum float_round_style { // constants for different IEEE rounding styles
    round_indeterminate       = -1,
    round_toward_zero         = 0,
    round_to_nearest          = 1,
    round_toward_infinity     = 2,
    round_toward_neg_infinity = 3
};

struct _Num_base { // base for all types, with common defaults
    _STL_DISABLE_DEPRECATED_WARNING
    _CXX23_DEPRECATE_DENORM static constexpr float_denorm_style has_denorm = denorm_absent;
    _CXX23_DEPRECATE_DENORM static constexpr bool has_denorm_loss          = false;
    _STL_RESTORE_DEPRECATED_WARNING

    static constexpr bool has_infinity             = false;
    static constexpr bool has_quiet_NaN            = false;
    static constexpr bool has_signaling_NaN        = false;
    static constexpr bool is_bounded               = false;
    static constexpr bool is_exact                 = false;
    static constexpr bool is_iec559                = false;
    static constexpr bool is_integer               = false;
    static constexpr bool is_modulo                = false;
    static constexpr bool is_signed                = false;
    static constexpr bool is_specialized           = false;
    static constexpr bool tinyness_before          = false;
    static constexpr bool traps                    = false;
    static constexpr float_round_style round_style = round_toward_zero;
    static constexpr int digits                    = 0;
    static constexpr int digits10                  = 0;
    static constexpr int max_digits10              = 0;
    static constexpr int max_exponent              = 0;
    static constexpr int max_exponent10            = 0;
    static constexpr int min_exponent              = 0;
    static constexpr int min_exponent10            = 0;
    static constexpr int radix                     = 0;
};

_EXPORT_STD template <class _Ty>
class numeric_limits : public _Num_base { // numeric limits for arbitrary type _Ty (say little or nothing)
public:
    _NODISCARD static constexpr _Ty(min)() noexcept {
        return _Ty();
    }

    _NODISCARD static constexpr _Ty(max)() noexcept {
        return _Ty();
    }

    _NODISCARD static constexpr _Ty lowest() noexcept {
        return _Ty();
    }

    _NODISCARD static constexpr _Ty epsilon() noexcept {
        return _Ty();
    }

    _NODISCARD static constexpr _Ty round_error() noexcept {
        return _Ty();
    }

    _NODISCARD static constexpr _Ty denorm_min() noexcept {
        return _Ty();
    }

    _NODISCARD static constexpr _Ty infinity() noexcept {
        return _Ty();
    }

    _NODISCARD static constexpr _Ty quiet_NaN() noexcept {
        return _Ty();
    }

    _NODISCARD static constexpr _Ty signaling_NaN() noexcept {
        return _Ty();
    }
};

template <class _Ty>
class numeric_limits<const _Ty> : public numeric_limits<_Ty> {}; // numeric limits for const types

template <class _Ty>
class numeric_limits<volatile _Ty> : public numeric_limits<_Ty> {}; // numeric limits for volatile types

template <class _Ty>
class numeric_limits<const volatile _Ty> : public numeric_limits<_Ty> {}; // numeric limits for const volatile types

struct _Num_int_base : _Num_base { // base for integer types
    static constexpr bool is_bounded     = true;
    static constexpr bool is_exact       = true;
    static constexpr bool is_integer     = true;
    static constexpr bool is_specialized = true;
    static constexpr int radix           = 2;
};

struct _Num_float_base : _Num_base { // base for floating-point types
    _STL_DISABLE_DEPRECATED_WARNING
    _CXX23_DEPRECATE_DENORM static constexpr float_denorm_style has_denorm = denorm_present;
    _STL_RESTORE_DEPRECATED_WARNING

    static constexpr bool has_infinity             = true;
    static constexpr bool has_quiet_NaN            = true;
    static constexpr bool has_signaling_NaN        = true;
    static constexpr bool is_bounded               = true;
    static constexpr bool is_iec559                = true;
    static constexpr bool is_signed                = true;
    static constexpr bool is_specialized           = true;
    static constexpr float_round_style round_style = round_to_nearest;
    static constexpr int radix                     = FLT_RADIX;
};

template <>
class numeric_limits<bool> : public _Num_int_base {
public:
    _NODISCARD static constexpr bool(min)() noexcept {
        return false;
    }

    _NODISCARD static constexpr bool(max)() noexcept {
        return true;
    }

    _NODISCARD static constexpr bool lowest() noexcept {
        return (min) ();
    }

    _NODISCARD static constexpr bool epsilon() noexcept {
        return 0;
    }

    _NODISCARD static constexpr bool round_error() noexcept {
        return 0;
    }

    _NODISCARD static constexpr bool denorm_min() noexcept {
        return 0;
    }

    _NODISCARD static constexpr bool infinity() noexcept {
        return 0;
    }

    _NODISCARD static constexpr bool quiet_NaN() noexcept {
        return 0;
    }

    _NODISCARD static constexpr bool signaling_NaN() noexcept {
        return 0;
    }

    static constexpr int digits = 1;
};

template <>
class numeric_limits<char> : public _Num_int_base {
public:
    _NODISCARD static constexpr char(min)() noexcept {
        return CHAR_MIN;
    }

    _NODISCARD static constexpr char(max)() noexcept {
        return CHAR_MAX;
    }

    _NODISCARD static constexpr char lowest() noexcept {
        return (min) ();
    }

    _NODISCARD static constexpr char epsilon() noexcept {
        return 0;
    }

    _NODISCARD static constexpr char round_error() noexcept {
        return 0;
    }

    _NODISCARD static constexpr char denorm_min() noexcept {
        return 0;
    }

    _NODISCARD static constexpr char infinity() noexcept {
        return 0;
    }

    _NODISCARD static constexpr char quiet_NaN() noexcept {
        return 0;
    }

    _NODISCARD static constexpr char signaling_NaN() noexcept {
        return 0;
    }

    static constexpr bool is_signed = CHAR_MIN != 0;
    static constexpr bool is_modulo = CHAR_MIN == 0;
    static constexpr int digits     = 8 - (CHAR_MIN != 0);
    static constexpr int digits10   = 2;
};

template <>
class numeric_limits<signed char> : public _Num_int_base {
public:
    _NODISCARD static constexpr signed char(min)() noexcept {
        return SCHAR_MIN;
    }

    _NODISCARD static constexpr signed char(max)() noexcept {
        return SCHAR_MAX;
    }

    _NODISCARD static constexpr signed char lowest() noexcept {
        return (min) ();
    }

    _NODISCARD static constexpr signed char epsilon() noexcept {
        return 0;
    }

    _NODISCARD static constexpr signed char round_error() noexcept {
        return 0;
    }

    _NODISCARD static constexpr signed char denorm_min() noexcept {
        return 0;
    }

    _NODISCARD static constexpr signed char infinity() noexcept {
        return 0;
    }

    _NODISCARD static constexpr signed char quiet_NaN() noexcept {
        return 0;
    }

    _NODISCARD static constexpr signed char signaling_NaN() noexcept {
        return 0;
    }

    static constexpr bool is_signed = true;
    static constexpr int digits     = 7;
    static constexpr int digits10   = 2;
};

template <>
class numeric_limits<unsigned char> : public _Num_int_base {
public:
    _NODISCARD static constexpr unsigned char(min)() noexcept {
        return 0;
    }

    _NODISCARD static constexpr unsigned char(max)() noexcept {
        return UCHAR_MAX;
    }

    _NODISCARD static constexpr unsigned char lowest() noexcept {
        return (min) ();
    }

    _NODISCARD static constexpr unsigned char epsilon() noexcept {
        return 0;
    }

    _NODISCARD static constexpr unsigned char round_error() noexcept {
        return 0;
    }

    _NODISCARD static constexpr unsigned char denorm_min() noexcept {
        return 0;
    }

    _NODISCARD static constexpr unsigned char infinity() noexcept {
        return 0;
    }

    _NODISCARD static constexpr unsigned char quiet_NaN() noexcept {
        return 0;
    }

    _NODISCARD static constexpr unsigned char signaling_NaN() noexcept {
        return 0;
    }

    static constexpr bool is_modulo = true;
    static constexpr int digits     = 8;
    static constexpr int digits10   = 2;
};

#ifdef __cpp_char8_t
template <>
class numeric_limits<char8_t> : public _Num_int_base {
public:
    _NODISCARD static constexpr char8_t(min)() noexcept {
        return 0;
    }

    _NODISCARD static constexpr char8_t(max)() noexcept {
        return UCHAR_MAX;
    }

    _NODISCARD static constexpr char8_t lowest() noexcept {
        return 0;
    }

    _NODISCARD static constexpr char8_t epsilon() noexcept {
        return 0;
    }

    _NODISCARD static constexpr char8_t round_error() noexcept {
        return 0;
    }

    _NODISCARD static constexpr char8_t denorm_min() noexcept {
        return 0;
    }

    _NODISCARD static constexpr char8_t infinity() noexcept {
        return 0;
    }

    _NODISCARD static constexpr char8_t quiet_NaN() noexcept {
        return 0;
    }

    _NODISCARD static constexpr char8_t signaling_NaN() noexcept {
        return 0;
    }

    static constexpr bool is_modulo = true;
    static constexpr int digits     = 8;
    static constexpr int digits10   = 2;
};
#endif // __cpp_char8_t

template <>
class numeric_limits<char16_t> : public _Num_int_base {
public:
    _NODISCARD static constexpr char16_t(min)() noexcept {
        return 0;
    }

    _NODISCARD static constexpr char16_t(max)() noexcept {
        return USHRT_MAX;
    }

    _NODISCARD static constexpr char16_t lowest() noexcept {
        return (min) ();
    }

    _NODISCARD static constexpr char16_t epsilon() noexcept {
        return 0;
    }

    _NODISCARD static constexpr char16_t round_error() noexcept {
        return 0;
    }

    _NODISCARD static constexpr char16_t denorm_min() noexcept {
        return 0;
    }

    _NODISCARD static constexpr char16_t infinity() noexcept {
        return 0;
    }

    _NODISCARD static constexpr char16_t quiet_NaN() noexcept {
        return 0;
    }

    _NODISCARD static constexpr char16_t signaling_NaN() noexcept {
        return 0;
    }

    static constexpr bool is_modulo = true;
    static constexpr int digits     = 16;
    static constexpr int digits10   = 4;
};

template <>
class numeric_limits<char32_t> : public _Num_int_base {
public:
    _NODISCARD static constexpr char32_t(min)() noexcept {
        return 0;
    }

    _NODISCARD static constexpr char32_t(max)() noexcept {
        return UINT_MAX;
    }

    _NODISCARD static constexpr char32_t lowest() noexcept {
        return (min) ();
    }

    _NODISCARD static constexpr char32_t epsilon() noexcept {
        return 0;
    }

    _NODISCARD static constexpr char32_t round_error() noexcept {
        return 0;
    }

    _NODISCARD static constexpr char32_t denorm_min() noexcept {
        return 0;
    }

    _NODISCARD static constexpr char32_t infinity() noexcept {
        return 0;
    }

    _NODISCARD static constexpr char32_t quiet_NaN() noexcept {
        return 0;
    }

    _NODISCARD static constexpr char32_t signaling_NaN() noexcept {
        return 0;
    }

    static constexpr bool is_modulo = true;
    static constexpr int digits     = 32;
    static constexpr int digits10   = 9;
};

template <>
class numeric_limits<wchar_t> : public _Num_int_base {
public:
    _NODISCARD static constexpr wchar_t(min)() noexcept {
        return WCHAR_MIN;
    }

    _NODISCARD static constexpr wchar_t(max)() noexcept {
        return WCHAR_MAX;
    }

    _NODISCARD static constexpr wchar_t lowest() noexcept {
        return (min) ();
    }

    _NODISCARD static constexpr wchar_t epsilon() noexcept {
        return 0;
    }

    _NODISCARD static constexpr wchar_t round_error() noexcept {
        return 0;
    }

    _NODISCARD static constexpr wchar_t denorm_min() noexcept {
        return 0;
    }

    _NODISCARD static constexpr wchar_t infinity() noexcept {
        return 0;
    }

    _NODISCARD static constexpr wchar_t quiet_NaN() noexcept {
        return 0;
    }

    _NODISCARD static constexpr wchar_t signaling_NaN() noexcept {
        return 0;
    }

    static constexpr bool is_modulo = true;
    static constexpr int digits     = 16;
    static constexpr int digits10   = 4;
};

template <>
class numeric_limits<short> : public _Num_int_base {
public:
    _NODISCARD static constexpr short(min)() noexcept {
        return SHRT_MIN;
    }

    _NODISCARD static constexpr short(max)() noexcept {
        return SHRT_MAX;
    }

    _NODISCARD static constexpr short lowest() noexcept {
        return (min) ();
    }

    _NODISCARD static constexpr short epsilon() noexcept {
        return 0;
    }

    _NODISCARD static constexpr short round_error() noexcept {
        return 0;
    }

    _NODISCARD static constexpr short denorm_min() noexcept {
        return 0;
    }

    _NODISCARD static constexpr short infinity() noexcept {
        return 0;
    }

    _NODISCARD static constexpr short quiet_NaN() noexcept {
        return 0;
    }

    _NODISCARD static constexpr short signaling_NaN() noexcept {
        return 0;
    }

    static constexpr bool is_signed = true;
    static constexpr int digits     = 15;
    static constexpr int digits10   = 4;
};

template <>
class numeric_limits<int> : public _Num_int_base {
public:
    _NODISCARD static constexpr int(min)() noexcept {
        return INT_MIN;
    }

    _NODISCARD static constexpr int(max)() noexcept {
        return INT_MAX;
    }

    _NODISCARD static constexpr int lowest() noexcept {
        return (min) ();
    }

    _NODISCARD static constexpr int epsilon() noexcept {
        return 0;
    }

    _NODISCARD static constexpr int round_error() noexcept {
        return 0;
    }

    _NODISCARD static constexpr int denorm_min() noexcept {
        return 0;
    }

    _NODISCARD static constexpr int infinity() noexcept {
        return 0;
    }

    _NODISCARD static constexpr int quiet_NaN() noexcept {
        return 0;
    }

    _NODISCARD static constexpr int signaling_NaN() noexcept {
        return 0;
    }

    static constexpr bool is_signed = true;
    static constexpr int digits     = 31;
    static constexpr int digits10   = 9;
};

template <>
class numeric_limits<long> : public _Num_int_base {
public:
    _NODISCARD static constexpr long(min)() noexcept {
        return LONG_MIN;
    }

    _NODISCARD static constexpr long(max)() noexcept {
        return LONG_MAX;
    }

    _NODISCARD static constexpr long lowest() noexcept {
        return (min) ();
    }

    _NODISCARD static constexpr long epsilon() noexcept {
        return 0;
    }

    _NODISCARD static constexpr long round_error() noexcept {
        return 0;
    }

    _NODISCARD static constexpr long denorm_min() noexcept {
        return 0;
    }

    _NODISCARD static constexpr long infinity() noexcept {
        return 0;
    }

    _NODISCARD static constexpr long quiet_NaN() noexcept {
        return 0;
    }

    _NODISCARD static constexpr long signaling_NaN() noexcept {
        return 0;
    }

    static_assert(sizeof(int) == sizeof(long), "LLP64 assumption");
    static constexpr bool is_signed = true;
    static constexpr int digits     = 31;
    static constexpr int digits10   = 9;
};

template <>
class numeric_limits<long long> : public _Num_int_base {
public:
    _NODISCARD static constexpr long long(min)() noexcept {
        return LLONG_MIN;
    }

    _NODISCARD static constexpr long long(max)() noexcept {
        return LLONG_MAX;
    }

    _NODISCARD static constexpr long long lowest() noexcept {
        return (min) ();
    }

    _NODISCARD static constexpr long long epsilon() noexcept {
        return 0;
    }

    _NODISCARD static constexpr long long round_error() noexcept {
        return 0;
    }

    _NODISCARD static constexpr long long denorm_min() noexcept {
        return 0;
    }

    _NODISCARD static constexpr long long infinity() noexcept {
        return 0;
    }

    _NODISCARD static constexpr long long quiet_NaN() noexcept {
        return 0;
    }

    _NODISCARD static constexpr long long signaling_NaN() noexcept {
        return 0;
    }

    static constexpr bool is_signed = true;
    static constexpr int digits     = 63;
    static constexpr int digits10   = 18;
};

#ifdef _NATIVE_WCHAR_T_DEFINED
template <>
class numeric_limits<unsigned short> : public _Num_int_base {
public:
    _NODISCARD static constexpr unsigned short(min)() noexcept {
        return 0;
    }

    _NODISCARD static constexpr unsigned short(max)() noexcept {
        return USHRT_MAX;
    }

    _NODISCARD static constexpr unsigned short lowest() noexcept {
        return (min) ();
    }

    _NODISCARD static constexpr unsigned short epsilon() noexcept {
        return 0;
    }

    _NODISCARD static constexpr unsigned short round_error() noexcept {
        return 0;
    }

    _NODISCARD static constexpr unsigned short denorm_min() noexcept {
        return 0;
    }

    _NODISCARD static constexpr unsigned short infinity() noexcept {
        return 0;
    }

    _NODISCARD static constexpr unsigned short quiet_NaN() noexcept {
        return 0;
    }

    _NODISCARD static constexpr unsigned short signaling_NaN() noexcept {
        return 0;
    }

    static constexpr bool is_modulo = true;
    static constexpr int digits     = 16;
    static constexpr int digits10   = 4;
};
#endif // _NATIVE_WCHAR_T_DEFINED

template <>
class numeric_limits<unsigned int> : public _Num_int_base {
public:
    _NODISCARD static constexpr unsigned int(min)() noexcept {
        return 0;
    }

    _NODISCARD static constexpr unsigned int(max)() noexcept {
        return UINT_MAX;
    }

    _NODISCARD static constexpr unsigned int lowest() noexcept {
        return (min) ();
    }

    _NODISCARD static constexpr unsigned int epsilon() noexcept {
        return 0;
    }

    _NODISCARD static constexpr unsigned int round_error() noexcept {
        return 0;
    }

    _NODISCARD static constexpr unsigned int denorm_min() noexcept {
        return 0;
    }

    _NODISCARD static constexpr unsigned int infinity() noexcept {
        return 0;
    }

    _NODISCARD static constexpr unsigned int quiet_NaN() noexcept {
        return 0;
    }

    _NODISCARD static constexpr unsigned int signaling_NaN() noexcept {
        return 0;
    }

    static constexpr bool is_modulo = true;
    static constexpr int digits     = 32;
    static constexpr int digits10   = 9;
};

template <>
class numeric_limits<unsigned long> : public _Num_int_base {
public:
    _NODISCARD static constexpr unsigned long(min)() noexcept {
        return 0;
    }

    _NODISCARD static constexpr unsigned long(max)() noexcept {
        return ULONG_MAX;
    }

    _NODISCARD static constexpr unsigned long lowest() noexcept {
        return (min) ();
    }

    _NODISCARD static constexpr unsigned long epsilon() noexcept {
        return 0;
    }

    _NODISCARD static constexpr unsigned long round_error() noexcept {
        return 0;
    }

    _NODISCARD static constexpr unsigned long denorm_min() noexcept {
        return 0;
    }

    _NODISCARD static constexpr unsigned long infinity() noexcept {
        return 0;
    }

    _NODISCARD static constexpr unsigned long quiet_NaN() noexcept {
        return 0;
    }

    _NODISCARD static constexpr unsigned long signaling_NaN() noexcept {
        return 0;
    }

    static_assert(sizeof(unsigned int) == sizeof(unsigned long), "LLP64 assumption");
    static constexpr bool is_modulo = true;
    static constexpr int digits     = 32;
    static constexpr int digits10   = 9;
};

template <>
class numeric_limits<unsigned long long> : public _Num_int_base {
public:
    _NODISCARD static constexpr unsigned long long(min)() noexcept {
        return 0;
    }

    _NODISCARD static constexpr unsigned long long(max)() noexcept {
        return ULLONG_MAX;
    }

    _NODISCARD static constexpr unsigned long long lowest() noexcept {
        return (min) ();
    }

    _NODISCARD static constexpr unsigned long long epsilon() noexcept {
        return 0;
    }

    _NODISCARD static constexpr unsigned long long round_error() noexcept {
        return 0;
    }

    _NODISCARD static constexpr unsigned long long denorm_min() noexcept {
        return 0;
    }

    _NODISCARD static constexpr unsigned long long infinity() noexcept {
        return 0;
    }

    _NODISCARD static constexpr unsigned long long quiet_NaN() noexcept {
        return 0;
    }

    _NODISCARD static constexpr unsigned long long signaling_NaN() noexcept {
        return 0;
    }

    static constexpr bool is_modulo = true;
    static constexpr int digits     = 64;
    static constexpr int digits10   = 19;
};

template <>
class numeric_limits<float> : public _Num_float_base {
public:
    _NODISCARD static constexpr float(min)() noexcept {
        return FLT_MIN;
    }

    _NODISCARD static constexpr float(max)() noexcept {
        return FLT_MAX;
    }

    _NODISCARD static constexpr float lowest() noexcept {
        return -(max) ();
    }

    _NODISCARD static constexpr float epsilon() noexcept {
        return FLT_EPSILON;
    }

    _NODISCARD static constexpr float round_error() noexcept {
        return 0.5F;
    }

    _NODISCARD static constexpr float denorm_min() noexcept {
        return FLT_TRUE_MIN;
    }

    _NODISCARD static constexpr float infinity() noexcept {
        return __builtin_huge_valf();
    }

    _NODISCARD static constexpr float quiet_NaN() noexcept {
        return __builtin_nanf("0");
    }

    _NODISCARD static constexpr float signaling_NaN() noexcept {
        return __builtin_nansf("1");
    }

    static constexpr int digits         = FLT_MANT_DIG;
    static constexpr int digits10       = FLT_DIG;
    static constexpr int max_digits10   = 9;
    static constexpr int max_exponent   = FLT_MAX_EXP;
    static constexpr int max_exponent10 = FLT_MAX_10_EXP;
    static constexpr int min_exponent   = FLT_MIN_EXP;
    static constexpr int min_exponent10 = FLT_MIN_10_EXP;
};

template <>
class numeric_limits<double> : public _Num_float_base {
public:
    _NODISCARD static constexpr double(min)() noexcept {
        return DBL_MIN;
    }

    _NODISCARD static constexpr double(max)() noexcept {
        return DBL_MAX;
    }

    _NODISCARD static constexpr double lowest() noexcept {
        return -(max) ();
    }

    _NODISCARD static constexpr double epsilon() noexcept {
        return DBL_EPSILON;
    }

    _NODISCARD static constexpr double round_error() noexcept {
        return 0.5;
    }

    _NODISCARD static constexpr double denorm_min() noexcept {
        return DBL_TRUE_MIN;
    }

    _NODISCARD static constexpr double infinity() noexcept {
        return __builtin_huge_val();
    }

    _NODISCARD static constexpr double quiet_NaN() noexcept {
        return __builtin_nan("0");
    }

    _NODISCARD static constexpr double signaling_NaN() noexcept {
        return __builtin_nans("1");
    }

    static constexpr int digits         = DBL_MANT_DIG;
    static constexpr int digits10       = DBL_DIG;
    static constexpr int max_digits10   = 17;
    static constexpr int max_exponent   = DBL_MAX_EXP;
    static constexpr int max_exponent10 = DBL_MAX_10_EXP;
    static constexpr int min_exponent   = DBL_MIN_EXP;
    static constexpr int min_exponent10 = DBL_MIN_10_EXP;
};

template <>
class numeric_limits<long double> : public _Num_float_base {
public:
    _NODISCARD static constexpr long double(min)() noexcept {
        return LDBL_MIN;
    }

    _NODISCARD static constexpr long double(max)() noexcept {
        return LDBL_MAX;
    }

    _NODISCARD static constexpr long double lowest() noexcept {
        return -(max) ();
    }

    _NODISCARD static constexpr long double epsilon() noexcept {
        return LDBL_EPSILON;
    }

    _NODISCARD static constexpr long double round_error() noexcept {
        return 0.5L;
    }

    _NODISCARD static constexpr long double denorm_min() noexcept {
        return LDBL_TRUE_MIN;
    }

    _NODISCARD static constexpr long double infinity() noexcept {
        return __builtin_huge_val();
    }

    _NODISCARD static constexpr long double quiet_NaN() noexcept {
        return __builtin_nan("0");
    }

    _NODISCARD static constexpr long double signaling_NaN() noexcept {
        return __builtin_nans("1");
    }

    static constexpr int digits         = LDBL_MANT_DIG;
    static constexpr int digits10       = LDBL_DIG;
    static constexpr int max_digits10   = 2 + LDBL_MANT_DIG * 301L / 1000;
    static constexpr int max_exponent   = LDBL_MAX_EXP;
    static constexpr int max_exponent10 = LDBL_MAX_10_EXP;
    static constexpr int min_exponent   = LDBL_MIN_EXP;
    static constexpr int min_exponent10 = LDBL_MIN_10_EXP;
};

// Implementation of countl_zero without using specialized CPU instructions.
// Used at compile time and when said instructions are not supported.
// see "Hacker's Delight" section 5-3
template <class _Ty>
_NODISCARD constexpr int _Countl_zero_fallback(_Ty _Val) noexcept {
    _Ty _Yy = 0;

    unsigned int _Nn = numeric_limits<_Ty>::digits;
    unsigned int _Cc = numeric_limits<_Ty>::digits / 2;
    do {
        _Yy = static_cast<_Ty>(_Val >> _Cc);
        if (_Yy != 0) {
            _Nn -= _Cc;
            _Val = _Yy;
        }
        _Cc >>= 1;
    } while (_Cc != 0);
    return static_cast<int>(_Nn) - static_cast<int>(_Val);
}

// Implementation of countr_zero without using specialized CPU instructions.
// Used at compile time and when said instructions are not supported.
// see "Hacker's Delight" section 5-4
template <class _Ty>
_NODISCARD constexpr int _Countr_zero_fallback(const _Ty _Val) noexcept {
    constexpr int _Digits = numeric_limits<_Ty>::digits;
    return _Digits - _Countl_zero_fallback(static_cast<_Ty>(static_cast<_Ty>(~_Val) & static_cast<_Ty>(_Val - 1)));
}

// Implementation of popcount without using specialized CPU instructions.
// Used at compile time and when said instructions are not supported.
template <class _Ty>
_NODISCARD constexpr int _Popcount_fallback(_Ty _Val) noexcept {
    constexpr int _Digits = numeric_limits<_Ty>::digits;
#if defined(_M_IX86) || defined(_M_ARM)
    if constexpr (_Digits == 64) {
        // 64-bit bit operations on architectures without 64-bit registers are less efficient,
        // hence we split the value so that it fits in 32-bit registers
        return _Popcount_fallback(static_cast<unsigned long>(_Val))
             + _Popcount_fallback(static_cast<unsigned long>(_Val >> 32));
    }
#endif // defined(_M_IX86) || defined(_M_ARM)
    // we static_cast these bit patterns in order to truncate them to the correct size
    _Val = static_cast<_Ty>(_Val - ((_Val >> 1) & static_cast<_Ty>(0x5555'5555'5555'5555ull)));
    _Val = static_cast<_Ty>((_Val & static_cast<_Ty>(0x3333'3333'3333'3333ull))
                            + ((_Val >> 2) & static_cast<_Ty>(0x3333'3333'3333'3333ull)));
    _Val = static_cast<_Ty>((_Val + (_Val >> 4)) & static_cast<_Ty>(0x0F0F'0F0F'0F0F'0F0Full));
    // Multiply by one in each byte, so that it will have the sum of all source bytes in the highest byte
    _Val = static_cast<_Ty>(_Val * static_cast<_Ty>(0x0101'0101'0101'0101ull));
    // Extract highest byte
    return static_cast<int>(_Val >> (_Digits - 8));
}

#if (defined(_M_IX86) || (defined(_M_X64) && !defined(_M_ARM64EC))) && !defined(_M_CEE_PURE) && !defined(__CUDACC__) \
    && !defined(__INTEL_COMPILER)
#define _HAS_TZCNT_BSF_INTRINSICS 1
#else // ^^^ intrinsics available / intrinsics unavailable vvv
#define _HAS_TZCNT_BSF_INTRINSICS 0
#endif // ^^^ intrinsics unavailable ^^^

#if _HAS_TZCNT_BSF_INTRINSICS
extern "C" {
extern int __isa_available;
}

#ifdef __clang__
#define _TZCNT_U32 __builtin_ia32_tzcnt_u32
#define _TZCNT_U64 __builtin_ia32_tzcnt_u64
#else // ^^^ __clang__ / !__clang__ vvv
#define _TZCNT_U32 _tzcnt_u32
#define _TZCNT_U64 _tzcnt_u64
#endif // __clang__

template <class _Ty>
_NODISCARD int _Countr_zero_tzcnt(const _Ty _Val) noexcept {
    constexpr int _Digits = numeric_limits<_Ty>::digits;
    constexpr _Ty _Max    = (numeric_limits<_Ty>::max)();

    if constexpr (_Digits <= 32) {
        // Intended widening to int. This operation means that a narrow 0 will widen
        // to 0xFFFF....FFFF0... instead of 0. We need this to avoid counting all the zeros
        // of the wider type.
        return static_cast<int>(_TZCNT_U32(static_cast<unsigned int>(~_Max | _Val)));
    } else {
#ifdef _M_IX86
        const auto _Low = static_cast<unsigned int>(_Val);
        if (_Low == 0) {
            const unsigned int _High = _Val >> 32;
            return static_cast<int>(32 + _TZCNT_U32(_High));
        } else {
            return static_cast<int>(_TZCNT_U32(_Low));
        }
#else // ^^^ _M_IX86 / !_M_IX86 vvv
        return static_cast<int>(_TZCNT_U64(_Val));
#endif // _M_IX86
    }
}

#undef _TZCNT_U32
#undef _TZCNT_U64

template <class _Ty>
_NODISCARD int _Countr_zero_bsf(const _Ty _Val) noexcept {
    constexpr int _Digits = numeric_limits<_Ty>::digits;
    constexpr _Ty _Max    = (numeric_limits<_Ty>::max)();

    unsigned long _Result;
    if constexpr (_Digits <= 32) {
        // Intended widening to int. This operation means that a narrow 0 will widen
        // to 0xFFFF....FFFF0... instead of 0. We need this to avoid counting all the zeros
        // of the wider type.
        if (!_BitScanForward(&_Result, static_cast<unsigned int>(~_Max | _Val))) {
            return _Digits;
        }
    } else {
#ifdef _M_IX86
        const auto _Low = static_cast<unsigned int>(_Val);
        if (_BitScanForward(&_Result, _Low)) {
            return static_cast<int>(_Result);
        }

        const unsigned int _High = _Val >> 32;
        if (!_BitScanForward(&_Result, _High)) {
            return _Digits;
        } else {
            return static_cast<int>(_Result + 32);
        }
#else // ^^^ _M_IX86 / !_M_IX86 vvv
        if (!_BitScanForward64(&_Result, _Val)) {
            return _Digits;
        }
#endif // _M_IX86
    }
    return static_cast<int>(_Result);
}

template <class _Ty>
_NODISCARD int _Checked_x86_x64_countr_zero(const _Ty _Val) noexcept {
#ifdef __AVX2__
    return _Countr_zero_tzcnt(_Val);
#else // __AVX2__
    const bool _Definitely_have_tzcnt = __isa_available >= __ISA_AVAILABLE_AVX2;
    if (_Definitely_have_tzcnt) {
        return _Countr_zero_tzcnt(_Val);
    } else {
        return _Countr_zero_bsf(_Val);
    }
#endif // __AVX2__
}

#endif // _HAS_TZCNT_BSF_INTRINSICS

#if (defined(_M_IX86) || (defined(_M_X64) && !defined(_M_ARM64EC))) && !defined(_M_CEE_PURE) && !defined(__CUDACC__) \
    && !defined(__INTEL_COMPILER)
#define _HAS_POPCNT_INTRINSICS 1
#else // ^^^ intrinsics available / intrinsics unavailable vvv
#define _HAS_POPCNT_INTRINSICS 0
#endif // ^^^ intrinsics unavailable ^^^

#if _HAS_POPCNT_INTRINSICS
template <class _Ty>
_NODISCARD int _Unchecked_x86_x64_popcount(const _Ty _Val) noexcept {
    constexpr int _Digits = numeric_limits<_Ty>::digits;
    if constexpr (_Digits <= 16) {
        return static_cast<int>(__popcnt16(_Val));
    } else if constexpr (_Digits == 32) {
        return static_cast<int>(__popcnt(_Val));
    } else {
#ifdef _M_IX86
        return static_cast<int>(__popcnt(_Val >> 32) + __popcnt(static_cast<unsigned int>(_Val)));
#else // ^^^ _M_IX86 / !_M_IX86 vvv
        return static_cast<int>(__popcnt64(_Val));
#endif // _M_IX86
    }
}

template <class _Ty>
_NODISCARD int _Checked_x86_x64_popcount(const _Ty _Val) noexcept {
#ifndef __AVX__
    const bool _Definitely_have_popcnt = __isa_available >= __ISA_AVAILABLE_SSE42;
    if (!_Definitely_have_popcnt) {
        return _Popcount_fallback(_Val);
    }
#endif // !defined(__AVX__)
    return _Unchecked_x86_x64_popcount(_Val);
}
#endif // _HAS_POPCNT_INTRINSICS

#if _HAS_NEON_INTRINSICS
_NODISCARD inline int _Arm64_popcount(const unsigned long long _Val) noexcept {
    const __n64 _Temp = neon_cnt(__uint64ToN64_v(_Val));
    return neon_addv8(_Temp).n8_i8[0];
}
#endif // _HAS_NEON_INTRINSICS

template <class _Ty>
constexpr bool _Is_standard_unsigned_integer =
    _Is_any_of_v<remove_cv_t<_Ty>, unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long>;

template <class _Ty, enable_if_t<_Is_standard_unsigned_integer<_Ty>, int> = 0>
_NODISCARD _CONSTEXPR20 int _Countr_zero(const _Ty _Val) noexcept {
#if _HAS_TZCNT_BSF_INTRINSICS
#if _HAS_CXX20
    if (!_STD is_constant_evaluated())
#endif // _HAS_CXX20
    {
        return _Checked_x86_x64_countr_zero(_Val);
    }
#endif // _HAS_TZCNT_BSF_INTRINSICS
    return _Countr_zero_fallback(_Val);
}

template <class _Ty, class _Fn>
constexpr decltype(auto) _Select_countr_zero_impl(_Fn _Callback) {
    // TRANSITION, DevCom-1527995: Lambdas in this function ensure inlining
#if _HAS_TZCNT_BSF_INTRINSICS && _HAS_CXX20
    if (!_STD is_constant_evaluated()) {
#ifdef __AVX2__
        return _Callback([](_Ty _Val) { return _Countr_zero_tzcnt(_Val); });
#else // ^^^ AVX2 / not AVX2 vvv
        const bool _Definitely_have_tzcnt = __isa_available >= __ISA_AVAILABLE_AVX2;
        if (_Definitely_have_tzcnt) {
            return _Callback([](_Ty _Val) { return _Countr_zero_tzcnt(_Val); });
        } else {
            return _Callback([](_Ty _Val) { return _Countr_zero_bsf(_Val); });
        }
#endif // ^^^ not AVX2 ^^^
    }
#endif // ^^^ _HAS_TZCNT_BSF_INTRINSICS && _HAS_CXX20 ^^^
    // C++17 constexpr gcd() calls this function, so it should be constexpr unless we detect runtime evaluation.
    return _Callback([](_Ty _Val) { return _Countr_zero_fallback(_Val); });
}

template <class _Ty, enable_if_t<_Is_standard_unsigned_integer<_Ty>, int> = 0>
_NODISCARD _CONSTEXPR20 int _Popcount(const _Ty _Val) noexcept {
#if _HAS_POPCNT_INTRINSICS || _HAS_NEON_INTRINSICS
#if _HAS_CXX20
    if (!_STD is_constant_evaluated())
#endif // _HAS_CXX20
    {
#if _HAS_POPCNT_INTRINSICS
        return _Checked_x86_x64_popcount(_Val);
#elif _HAS_NEON_INTRINSICS // ^^^ x86/x64 intrinsics available / ARM64 intrinsics available vvv
        return _Arm64_popcount(_Val);
#endif // ^^^ ARM64 intrinsics available ^^^
    }
#endif // ^^^ any intrinsics available ^^^
    return _Popcount_fallback(_Val);
}

template <class _Ty, class _Fn>
_CONSTEXPR20 decltype(auto) _Select_popcount_impl(_Fn _Callback) {
    // TRANSITION, DevCom-1527995: Lambdas in this function ensure inlining
#if _HAS_POPCNT_INTRINSICS || _HAS_NEON_INTRINSICS
#if _HAS_CXX20
    if (!_STD is_constant_evaluated())
#endif // _HAS_CXX20
    {
#if _HAS_POPCNT_INTRINSICS
#ifndef __AVX__
        const bool _Definitely_have_popcnt = __isa_available >= __ISA_AVAILABLE_SSE42;
        if (!_Definitely_have_popcnt) {
            return _Callback([](_Ty _Val) { return _Popcount_fallback(_Val); });
        }
#endif // !defined(__AVX__)
        return _Callback([](_Ty _Val) { return _Unchecked_x86_x64_popcount(_Val); });
#elif _HAS_NEON_INTRINSICS // ^^^ x86/x64 intrinsics available / ARM64 intrinsics available vvv
        return _Callback([](_Ty _Val) { return _Arm64_popcount(_Val); });
#endif // ^^^ ARM64 intrinsics available ^^^
    }
#endif // ^^^ any intrinsics available ^^^
    return _Callback([](_Ty _Val) { return _Popcount_fallback(_Val); });
}

#undef _HAS_POPCNT_INTRINSICS
#undef _HAS_TZCNT_BSF_INTRINSICS
#undef _HAS_NEON_INTRINSICS

_STD_END
#pragma pop_macro("new")
_STL_RESTORE_CLANG_WARNINGS
#pragma warning(pop)
#pragma pack(pop)
#endif // _STL_COMPILER_PREPROCESSOR
#endif // _LIMITS_
