// xlocnum internal header

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

#ifndef _XLOCNUM_
#define _XLOCNUM_
#include <yvals_core.h>
#if _STL_COMPILER_PREPROCESSOR
#include <cfloat>
#include <climits>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <iterator>
#include <streambuf>

#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

_EXTERN_C_UNLESS_PURE

_CRTIMP2_PURE long __CLRCALL_PURE_OR_CDECL _Stolx(
    const char*, _Out_opt_ _Deref_post_opt_valid_ char**, int, int*) noexcept;
_CRTIMP2_PURE unsigned long __CLRCALL_PURE_OR_CDECL _Stoulx(
    const char*, _Out_opt_ _Deref_post_opt_valid_ char**, int, int*) noexcept;
_CRTIMP2_PURE long long __CLRCALL_PURE_OR_CDECL _Stollx(
    const char*, _Out_opt_ _Deref_post_opt_valid_ char**, int, int*) noexcept;
_CRTIMP2_PURE unsigned long long __CLRCALL_PURE_OR_CDECL _Stoullx(
    const char*, _Out_opt_ _Deref_post_opt_valid_ char**, int, int*) noexcept;

_END_EXTERN_C_UNLESS_PURE

_STD_BEGIN

_INLINE_VAR constexpr size_t _Max_int_dig = 32; // integer properties

inline double _Stodx_v3(const char* _Str, char** _Endptr, int* _Perr) noexcept { // convert string to double
    int& _Errno_ref = errno; // Nonzero cost, pay it once
    const int _Orig = _Errno_ref;

    _Errno_ref  = 0;
    double _Val = _CSTD strtod(_Str, _Endptr);
    *_Perr      = _Errno_ref;
    _Errno_ref  = _Orig;

    return _Val;
}

inline float _Stofx_v3(const char* _Str, char** _Endptr, int* _Perr) noexcept { // convert string to float
    int& _Errno_ref = errno; // Nonzero cost, pay it once
    const int _Orig = _Errno_ref;

    _Errno_ref = 0;
    float _Val = _CSTD strtof(_Str, _Endptr);
    *_Perr     = _Errno_ref;
    _Errno_ref = _Orig;

    return _Val;
}

template <class _Elem, size_t _Base_size>
size_t _Find_elem(const _Elem (&_Base)[_Base_size], const _Elem _Ch) {
    // lookup _Ch in array storing NUL-terminated string _Base
    // pre: _Base contains no nulls except for _Base[_Base_size - 1]
    return static_cast<size_t>(_STD _Find_unchecked(_Base, _Base + (_Base_size - 1), _Ch) - _Base);
}

inline wchar_t* _Maklocwcs(const wchar_t* _Ptr) { // copy NTWCS to allocated storage
    const size_t _Count = _CSTD wcslen(_Ptr) + 1;

    wchar_t* _Ptrdest = static_cast<wchar_t*>(_calloc_dbg(_Count, sizeof(wchar_t), _CRT_BLOCK, __FILE__, __LINE__));

    if (!_Ptrdest) {
        _Xbad_alloc();
    }

    _CSTD wmemcpy(_Ptrdest, _Ptr, _Count);
    return _Ptrdest;
}

_EXPORT_STD template <class _Elem>
class numpunct : public locale::facet { // facet for defining numeric punctuation text
private:
    friend _Tidy_guard<numpunct>;

public:
    static_assert(!_ENFORCE_FACET_SPECIALIZATIONS || _Is_any_of_v<_Elem, char, wchar_t>, _FACET_SPECIALIZATION_MESSAGE);

    using string_type = basic_string<_Elem, char_traits<_Elem>, allocator<_Elem>>;
    using char_type   = _Elem;

    __PURE_APPDOMAIN_GLOBAL _CRTIMP2_PURE_IMPORT static locale::id id; // unique facet id

    _Elem decimal_point() const {
        return do_decimal_point();
    }

    _Elem thousands_sep() const {
        return do_thousands_sep();
    }

    string grouping() const {
        return do_grouping();
    }

    string_type falsename() const {
        return do_falsename();
    }

    string_type truename() const {
        return do_truename();
    }

    explicit numpunct(size_t _Refs = 0) : locale::facet(_Refs) { // construct from current locale
        _BEGIN_LOCINFO(_Lobj)
        _Init(_Lobj);
        if (_Kseparator == 0) {
            _Kseparator = // NB: differs from "C" locale
                _Maklocchr(',', static_cast<_Elem*>(nullptr), _Lobj._Getcvt());
        }
        _END_LOCINFO()
    }

    numpunct(const _Locinfo& _Lobj, size_t _Refs = 0, bool _Isdef = false) : locale::facet(_Refs) {
        _Init(_Lobj, _Isdef);
    }

    static size_t _Getcat(const locale::facet** _Ppf = nullptr, const locale* _Ploc = nullptr) {
        // return locale category mask and construct standard facet
        if (_Ppf && !*_Ppf) {
            *_Ppf = new numpunct<_Elem>(_Locinfo(_Ploc->_C_str()), 0, true);
        }
        return _X_NUMERIC;
    }

protected:
    __CLR_OR_THIS_CALL ~numpunct() noexcept override {
        _Tidy();
    }

    numpunct(const char* _Locname, size_t _Refs = 0, bool _Isdef = false) : locale::facet(_Refs) {
        _BEGIN_LOCINFO(_Lobj(_Locname))
        _Init(_Lobj, _Isdef);
        _END_LOCINFO()
    }

    void _Init(const _Locinfo& _Lobj, bool _Isdef = false) { // initialize from _Lobj
        const lconv* _Ptr      = _Lobj._Getlconv();
        _Locinfo::_Cvtvec _Cvt = _Lobj._Getcvt(); // conversion information

        _Grouping  = nullptr;
        _Falsename = nullptr;
        _Truename  = nullptr;

        _Tidy_guard<numpunct> _Guard{this};
        _Grouping      = _Maklocstr(_Isdef ? "" : _Ptr->grouping, static_cast<char*>(nullptr), _Cvt);
        _Falsename     = _Maklocstr(_Lobj._Getfalse(), static_cast<_Elem*>(nullptr), _Cvt);
        _Truename      = _Maklocstr(_Lobj._Gettrue(), static_cast<_Elem*>(nullptr), _Cvt);
        _Guard._Target = nullptr;

        if (_Isdef) { // apply defaults for required facets
            _Dp         = _Maklocchr('.', static_cast<_Elem*>(nullptr), _Cvt);
            _Kseparator = _Maklocchr(',', static_cast<_Elem*>(nullptr), _Cvt);
        } else {
            if constexpr (is_same_v<_Elem, wchar_t>) {
                _Dp         = _Ptr->_W_decimal_point[0];
                _Kseparator = _Ptr->_W_thousands_sep[0];
            } else {
                _Dp         = _Maklocchr(_Ptr->decimal_point[0], static_cast<_Elem*>(nullptr), _Cvt);
                _Kseparator = _Maklocchr(_Ptr->thousands_sep[0], static_cast<_Elem*>(nullptr), _Cvt);
            }
        }
    }

    virtual _Elem __CLR_OR_THIS_CALL do_decimal_point() const {
        return _Dp;
    }

    virtual _Elem __CLR_OR_THIS_CALL do_thousands_sep() const {
        return _Kseparator;
    }

    virtual string __CLR_OR_THIS_CALL do_grouping() const {
        return string{_Grouping};
    }

    virtual string_type __CLR_OR_THIS_CALL do_falsename() const {
        return string_type{_Falsename};
    }

    virtual string_type __CLR_OR_THIS_CALL do_truename() const {
        return string_type{_Truename};
    }

private:
    void _Tidy() noexcept { // free all storage
        _CSTD free(const_cast<char*>(_Grouping));
        _CSTD free(const_cast<_Elem*>(_Falsename));
        _CSTD free(const_cast<_Elem*>(_Truename));
    }

    const char* _Grouping; // grouping string, "" for "C" locale
    _Elem _Dp; // decimal point, '.' for "C" locale
    _Elem _Kseparator; // thousands separator, '\0' for "C" locale
    const _Elem* _Falsename; // name for false, "false" for "C" locale
    const _Elem* _Truename; // name for true, "true" for "C" locale
};

_EXPORT_STD template <class _Elem>
class numpunct_byname : public numpunct<_Elem> { // numpunct for named locale
public:
    static_assert(!_ENFORCE_FACET_SPECIALIZATIONS || _Is_any_of_v<_Elem, char, wchar_t>, _FACET_SPECIALIZATION_MESSAGE);

    explicit numpunct_byname(const char* _Locname, size_t _Refs = 0)
        : numpunct<_Elem>(_Locname, _Refs) {} // construct for named locale

    explicit numpunct_byname(const string& _Str, size_t _Refs = 0)
        : numpunct<_Elem>(_Str.c_str(), _Refs) {} // construct for named locale

protected:
    __CLR_OR_THIS_CALL ~numpunct_byname() noexcept override {}
};

#if !defined(_CRTBLD) || defined(CRTDLL2) || !defined(_DLL) || defined(_M_CEE_PURE) // TRANSITION, VSO-578955
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdllimport-static-field-def"
#endif // defined(__clang__)

template <class _Elem>
__PURE_APPDOMAIN_GLOBAL locale::id numpunct<_Elem>::id;

#ifdef __clang__
#pragma clang diagnostic pop
#endif // defined(__clang__)
#endif // !defined(_CRTBLD) || defined(CRTDLL2) || !defined(_DLL) || defined(_M_CEE_PURE)

struct _Num_get_parse_result {
    // For integers: negative values mean parsing failure, while the "actual" base (used by _Getifld) is ~_Base.
    // Otherwise, 0, 8, 10, or 16.
    // For floating-point numbers: 0 for parsing failure, otherwise 10 or 16.
    int8_t _Base;
    bool _Bad_grouping;
};

_EXPORT_STD extern "C++" template <class _Elem, class _InIt = istreambuf_iterator<_Elem, char_traits<_Elem>>>
class num_get : public locale::facet { // facet for converting text to encoded numbers
public:
    static_assert(!_ENFORCE_FACET_SPECIALIZATIONS || _Is_any_of_v<_Elem, char, wchar_t>, _FACET_SPECIALIZATION_MESSAGE);

    static size_t __CLRCALL_OR_CDECL _Getcat(const locale::facet** _Ppf = nullptr, const locale* _Ploc = nullptr) {
        // return locale category mask and construct standard facet
        if (_Ppf && !*_Ppf) {
            *_Ppf = new num_get<_Elem, _InIt>(_Locinfo(_Ploc->_C_str()));
        }

        return _X_NUMERIC;
    }

    __PURE_APPDOMAIN_GLOBAL static locale::id id; // unique facet id

protected:
    __CLR_OR_THIS_CALL ~num_get() noexcept override {}

    void _Init(const _Locinfo&) {} // initialize from _Locinfo object

public:
    explicit __CLR_OR_THIS_CALL num_get(size_t _Refs = 0) : locale::facet(_Refs) { // construct from current locale
        _BEGIN_LOCINFO(_Lobj)
        _Init(_Lobj);
        _END_LOCINFO()
    }

    __CLR_OR_THIS_CALL num_get(const _Locinfo& _Lobj, size_t _Refs = 0) : locale::facet(_Refs) {
        _Init(_Lobj);
    }

    using char_type = _Elem;
    using iter_type = _InIt;

    _InIt __CLR_OR_THIS_CALL get(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State,
        bool& _Val) const { // get bool from [_First, _Last) into _Val
        return do_get(_First, _Last, _Iosbase, _State, _Val);
    }

    _InIt __CLR_OR_THIS_CALL get(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State,
        unsigned short& _Val) const { // get unsigned short from [_First, _Last) into _Val
        return do_get(_First, _Last, _Iosbase, _State, _Val);
    }

    _InIt __CLR_OR_THIS_CALL get(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State,
        unsigned int& _Val) const { // get unsigned int from [_First, _Last) into _Val
        return do_get(_First, _Last, _Iosbase, _State, _Val);
    }

    _InIt __CLR_OR_THIS_CALL get(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State,
        long& _Val) const { // get long from [_First, _Last) into _Val
        return do_get(_First, _Last, _Iosbase, _State, _Val);
    }

    _InIt __CLR_OR_THIS_CALL get(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State,
        unsigned long& _Val) const { // get unsigned long from [_First, _Last) into _Val
        return do_get(_First, _Last, _Iosbase, _State, _Val);
    }

    _InIt __CLR_OR_THIS_CALL get(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State,
        long long& _Val) const { // get long long from [_First, _Last) into _Val
        return do_get(_First, _Last, _Iosbase, _State, _Val);
    }

    _InIt __CLR_OR_THIS_CALL get(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State,
        unsigned long long& _Val) const { // get unsigned long long from [_First, _Last) into _Val
        return do_get(_First, _Last, _Iosbase, _State, _Val);
    }

    _InIt __CLR_OR_THIS_CALL get(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State,
        float& _Val) const { // get float from [_First, _Last) into _Val
        return do_get(_First, _Last, _Iosbase, _State, _Val);
    }

    _InIt __CLR_OR_THIS_CALL get(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State,
        double& _Val) const { // get double from [_First, _Last) into _Val
        return do_get(_First, _Last, _Iosbase, _State, _Val);
    }

    _InIt __CLR_OR_THIS_CALL get(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State,
        long double& _Val) const { // get long double from [_First, _Last) into _Val
        return do_get(_First, _Last, _Iosbase, _State, _Val);
    }

    _InIt __CLR_OR_THIS_CALL get(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State,
        void*& _Val) const { // get void pointer from [_First, _Last) into _Val
        return do_get(_First, _Last, _Iosbase, _State, _Val);
    }

protected:
    virtual _InIt __CLR_OR_THIS_CALL do_get(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State,
        bool& _Val) const { // get bool from [_First, _Last) into _Val
        _Adl_verify_range(_First, _Last);
        if (_Iosbase.flags() & ios_base::boolalpha) { // get false name or true name
            const auto& _Punct_fac = _STD use_facet<numpunct<_Elem>>(_Iosbase.getloc());
            basic_string<_Elem> _Str(static_cast<size_t>(1), _Elem{});
            _Str += _Punct_fac.falsename();
            _Str.push_back(_Elem{});
            _Str += _Punct_fac.truename(); // construct "\0false\0true"
            switch (_Getloctxt(_First, _Last, 2, _Str.c_str(), _Case_sensitive::_Yes)) {
            case 0:
                _Val = false;
                break;
            case 1:
                _Val = true;
                break;
            default:
                _Val   = false;
                _State = ios_base::failbit;
                break;
            }
        } else { // get long value
            char _Ac[_Max_int_dig];
            const auto _Parse_result =
                _Parse_int_with_locale(_Ac, _First, _Last, _Iosbase.flags(), _Iosbase.getloc()); // gather field
            if (_Parse_result._Base < 0) {
                // N4950 [facet.num.get.virtuals]/3.9:
                //  "zero, if the conversion function does not convert the entire field."
                _Val   = false;
                _State = ios_base::failbit;
            } else {
                char* _Ep;
                int _Errno;
                const long _Ans = _CSTD _Stolx(_Ac, &_Ep, _Parse_result._Base, &_Errno); // convert
                if (_Ep == _Ac || _Errno != 0 // N4950 [facet.num.get.virtuals]/3
                    || _Parse_result._Bad_grouping) { // N4950 [facet.num.get.virtuals]/4
                    _Val   = true;
                    _State = ios_base::failbit;
                } else {
                    _Val = _Ans != 0;
                    if (_Ans != 0 && _Ans != 1) {
                        _State = ios_base::failbit;
                    }
                }
            }
        }

        if (_First == _Last) {
            _State |= ios_base::eofbit;
        }

        return _First;
    }

    virtual _InIt __CLR_OR_THIS_CALL do_get(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State,
        unsigned short& _Val) const { // get unsigned short from [_First, _Last) into _Val
        _Adl_verify_range(_First, _Last);
        char _Ac[_Max_int_dig];
        const auto _Parse_result =
            _Parse_int_with_locale(_Ac, _First, _Last, _Iosbase.flags(), _Iosbase.getloc()); // gather field
        if (_Parse_result._Base < 0) { // ditto "fails to convert the entire field"
            _State = ios_base::failbit;
            _Val   = 0;
        } else {
            const bool _Minus   = _Ac[0] == '-';
            const char* _Digits = _Ac;
            // C11 7.22.1.4/5: the sequence of characters starting with the first digit
            // is interpreted as an integer constant according to the rules of 6.4.4.1
            if (_Minus) { // skip over minus to start with the first digit
                ++_Digits;
            }

            char* _Ep;
            int _Errno;
            const unsigned long _Tmp = _CSTD _Stoulx(_Digits, &_Ep, _Parse_result._Base, &_Errno); // convert
            _Val                     = static_cast<unsigned short>(_Tmp);
            if (_Ep == _Digits || _Errno != 0 || _Tmp > USHRT_MAX) { // N4950 [facet.num.get.virtuals]/3
                _State = ios_base::failbit;
                _Val   = USHRT_MAX;
            } else if (_Minus) { // C11 7.22.1.4/5:  If the subject sequence begins with a minus sign,
                                 // the value resulting from the conversion is negated (in the return type).
                _Val = static_cast<unsigned short>(0 - _Val);
            }

            if (_Parse_result._Bad_grouping) { // N4950 [facet.num.get.virtuals]/4
                _State = ios_base::failbit;
            }
        }

        if (_First == _Last) {
            _State |= ios_base::eofbit;
        }

        return _First;
    }

    virtual _InIt __CLR_OR_THIS_CALL do_get(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State,
        unsigned int& _Val) const { // get unsigned int from [_First, _Last) into _Val
        static_assert(sizeof(unsigned int) == sizeof(unsigned long),
            "Bad overflow assumptions due to sizeof(unsigned int) != sizeof(unsigned long)");
        unsigned long _Tmp;
        _First = num_get::do_get(_First, _Last, _Iosbase, _State, _Tmp); // avoid virtual call for perf
        _Val   = _Tmp;
        return _First;
    }

    virtual _InIt __CLR_OR_THIS_CALL do_get(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State,
        long& _Val) const { // get long from [_First, _Last) into _Val
        _Adl_verify_range(_First, _Last);
        char _Ac[_Max_int_dig];
        const auto _Parse_result =
            _Parse_int_with_locale(_Ac, _First, _Last, _Iosbase.flags(), _Iosbase.getloc()); // gather field
        if (_Parse_result._Base < 0) { // ditto "fails to convert the entire field"
            _State = ios_base::failbit;
            _Val   = 0;
        } else {
            char* _Ep;
            int _Errno;
            _Val = _CSTD _Stolx(_Ac, &_Ep, _Parse_result._Base, &_Errno); // convert
            if (_Ep == _Ac || _Errno != 0 // N4950 [facet.num.get.virtuals]/3
                || _Parse_result._Bad_grouping) { // N4950 [facet.num.get.virtuals]/4
                _State = ios_base::failbit;
            }
        }

        if (_First == _Last) {
            _State |= ios_base::eofbit;
        }

        return _First;
    }

    virtual _InIt __CLR_OR_THIS_CALL do_get(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State,
        unsigned long& _Val) const { // get unsigned long from [_First, _Last) into _Val
        _Adl_verify_range(_First, _Last);
        char _Ac[_Max_int_dig];
        const auto _Parse_result =
            _Parse_int_with_locale(_Ac, _First, _Last, _Iosbase.flags(), _Iosbase.getloc()); // gather field
        if (_Parse_result._Base < 0) { // ditto "fails to convert the entire field"
            _State = ios_base::failbit;
            _Val   = 0;
        } else {
            char* _Ep;
            int _Errno;
            _Val = _CSTD _Stoulx(_Ac, &_Ep, _Parse_result._Base, &_Errno); // convert
            if (_Ep == _Ac || _Errno != 0 // N4950 [facet.num.get.virtuals]/3
                || _Parse_result._Bad_grouping) { // N4950 [facet.num.get.virtuals]/4
                _State = ios_base::failbit;
            }
        }

        if (_First == _Last) {
            _State |= ios_base::eofbit;
        }

        return _First;
    }

    virtual _InIt __CLR_OR_THIS_CALL do_get(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State,
        long long& _Val) const { // get long long from [_First, _Last) into _Val
        _Adl_verify_range(_First, _Last);
        char _Ac[_Max_int_dig];
        const auto _Parse_result =
            _Parse_int_with_locale(_Ac, _First, _Last, _Iosbase.flags(), _Iosbase.getloc()); // gather field
        if (_Parse_result._Base < 0) { // ditto "fails to convert the entire field"
            _State = ios_base::failbit;
            _Val   = 0;
        } else {
            char* _Ep;
            int _Errno;
            _Val = _CSTD _Stollx(_Ac, &_Ep, _Parse_result._Base, &_Errno); // convert
            if (_Ep == _Ac || _Errno != 0 // N4950 [facet.num.get.virtuals]/3
                || _Parse_result._Bad_grouping) { // N4950 [facet.num.get.virtuals]/4
                _State = ios_base::failbit;
            }
        }

        if (_First == _Last) {
            _State |= ios_base::eofbit;
        }

        return _First;
    }

    virtual _InIt __CLR_OR_THIS_CALL do_get(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State,
        unsigned long long& _Val) const { // get unsigned long long from [_First, _Last) into _Val
        _Adl_verify_range(_First, _Last);
        char _Ac[_Max_int_dig];
        const auto _Parse_result =
            _Parse_int_with_locale(_Ac, _First, _Last, _Iosbase.flags(), _Iosbase.getloc()); // gather field
        if (_Parse_result._Base < 0) { // ditto "fails to convert the entire field"
            _State = ios_base::failbit;
            _Val   = 0;
        } else {
            int _Errno;
            char* _Ep;
            _Val = _CSTD _Stoullx(_Ac, &_Ep, _Parse_result._Base, &_Errno); // convert
            if (_Ep == _Ac || _Errno != 0 // N4950 [facet.num.get.virtuals]/3
                || _Parse_result._Bad_grouping) { // N4950 [facet.num.get.virtuals]/4
                _State = ios_base::failbit;
            }
        }

        if (_First == _Last) {
            _State |= ios_base::eofbit;
        }

        return _First;
    }

#define _MAX_SIG_DIG_V2 768
#define _MAX_EXP_DIG    8 // for parsing floating-point numbers
// Size of char buffer used by num_get::do_get() for float/double/long double
#define _FLOATING_BUFFER_SIZE (_MAX_EXP_DIG + _MAX_SIG_DIG_V2 + 16)

    virtual _InIt __CLR_OR_THIS_CALL do_get(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State,
        float& _Val) const { // get float from [_First, _Last) into _Val
        _Adl_verify_range(_First, _Last);
        char _Ac[_FLOATING_BUFFER_SIZE];
        const auto _Parse_result =
            _Parse_fp_with_locale(_Ac, _MAX_SIG_DIG_V2, _First, _Last, _Iosbase.getloc()); // gather field
        if (_Parse_result._Base == 0) { // ditto "fails to convert the entire field"
            _State = ios_base::failbit;
            _Val   = 0.0f;
        } else {
            int _Errno;
            char* _Ep;
            _Val = _STD _Stofx_v3(_Ac, &_Ep, &_Errno); // convert
            if (_Ep == _Ac || _Errno != 0 // N4950 [facet.num.get.virtuals]/3
                || _Parse_result._Bad_grouping) { // N4950 [facet.num.get.virtuals]/4
                _State = ios_base::failbit;
            }
        }

        if (_First == _Last) {
            _State |= ios_base::eofbit;
        }

        return _First;
    }

    virtual _InIt __CLR_OR_THIS_CALL do_get(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State,
        double& _Val) const { // get double from [_First, _Last) into _Val
        _Adl_verify_range(_First, _Last);
        char _Ac[_FLOATING_BUFFER_SIZE];
        const auto _Parse_result =
            _Parse_fp_with_locale(_Ac, _MAX_SIG_DIG_V2, _First, _Last, _Iosbase.getloc()); // gather field
        if (_Parse_result._Base == 0) { // ditto "fails to convert the entire field"
            _State = ios_base::failbit;
            _Val   = 0.0;
        } else {
            int _Errno;
            char* _Ep;
            _Val = _STD _Stodx_v3(_Ac, &_Ep, &_Errno); // convert
            if (_Ep == _Ac || _Errno != 0 // N4950 [facet.num.get.virtuals]/3
                || _Parse_result._Bad_grouping) { // N4950 [facet.num.get.virtuals]/4
                _State = ios_base::failbit;
            }
        }

        if (_First == _Last) {
            _State |= ios_base::eofbit;
        }

        return _First;
    }
#undef _FLOATING_BUFFER_SIZE
#undef _MAX_EXP_DIG

    virtual _InIt __CLR_OR_THIS_CALL do_get(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State,
        long double& _Val) const { // get long double from [_First, _Last) into _Val
        // Assumes sizeof(double) == sizeof(long double).
        // For 80-bit long double (which is not supported by MSVC in general), this will compile
        // but will not attempt to handle the increased precision at runtime.
        double _Result;
        _First = num_get::do_get(_First, _Last, _Iosbase, _State, _Result); // avoid virtual call for perf
        _Val   = _Result;
        return _First;
    }

    virtual _InIt __CLR_OR_THIS_CALL do_get(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State,
        void*& _Val) const { // get void pointer from [_First, _Last) into _Val
        _Adl_verify_range(_First, _Last);
        char _Ac[_Max_int_dig];
        const auto _Parse_result =
            _Parse_int_with_locale(_Ac, _First, _Last, ios_base::hex, _Iosbase.getloc()); // gather field
        if (_Parse_result._Base < 0) { // ditto "fails to convert the entire field"
            _State = ios_base::failbit;
            _Val   = nullptr;
        } else {
            int _Errno;
            char* _Ep;
#ifdef _WIN64
            _Val = reinterpret_cast<void*>(_CSTD _Stoullx(_Ac, &_Ep, _Parse_result._Base, &_Errno));
#else // ^^^ defined(_WIN64) / !defined(_WIN64) vvv
            _Val = reinterpret_cast<void*>(_CSTD _Stoulx(_Ac, &_Ep, _Parse_result._Base, &_Errno));
#endif // ^^^ !defined(_WIN64) ^^^
            if (_Ep == _Ac || _Errno != 0) { // N4950 [facet.num.get.virtuals]/3
                _State = ios_base::failbit;
                _Val   = nullptr;
            }

            if (_Parse_result._Bad_grouping) { // N4950 [facet.num.get.virtuals]/4
                _State = ios_base::failbit;
            }
        }

        if (_First == _Last) {
            _State |= ios_base::eofbit;
        }

        return _First;
    }

private:
    template <int = 0> // TRANSITION, ABI
    static _Num_get_parse_result _Parse_int_with_locale(
        char* const _Ac, _InIt& _First, _InIt& _Last, ios_base::fmtflags _Basefield, const locale& _Loc) {
        // get integer field from [_First, _Last) into _Ac
        const auto& _Punct_fac  = _STD use_facet<numpunct<_Elem>>(_Loc);
        const string _Grouping  = _Punct_fac.grouping();
        const _Elem _Kseparator = _Grouping.empty() ? _Elem{} : _Punct_fac.thousands_sep();

        constexpr int _Numget_signoff = 22;
        constexpr int _Numget_xoff    = 24;
        static constexpr char _Src[]  = "0123456789ABCDEFabcdef-+Xx";
        _Elem _Atoms[sizeof(_Src)];
        const ctype<_Elem>& _Ctype_fac = _STD use_facet<ctype<_Elem>>(_Loc);
        _Ctype_fac.widen(_STD begin(_Src), _STD end(_Src), _Atoms);

        bool _Bad_grouping = false;

        // skip leading separators before the sign
        if (_Kseparator != _Elem{}) {
            while (_First != _Last && *_First == _Kseparator) {
                ++_First;
                _Bad_grouping = true;
            }
        }

        char* _Ptr = _Ac;

        if (_First != _Last) {
            if (*_First == _Atoms[_Numget_signoff + 1]) { // gather plus sign
                *_Ptr++ = '+';
                ++_First;
            } else if (*_First == _Atoms[_Numget_signoff]) { // gather minus sign
                *_Ptr++ = '-';
                ++_First;
            }
        }

        // skip leading separators before digits
        if (_Kseparator != _Elem{}) {
            while (_First != _Last && *_First == _Kseparator) {
                ++_First;
                _Bad_grouping = true;
            }
        }

        _Basefield &= ios_base::basefield;

        int8_t _Base;
        if (_Basefield == ios_base::oct) {
            _Base = 8;
        } else if (_Basefield == ios_base::hex) {
            _Base = 16;
        } else if (_Basefield == ios_base::_Fmtzero) {
            _Base = 0;
        } else {
            _Base = 10;
        }

        bool _Seendigit = false; // seen a digit in input
        bool _Nonzero   = false; // seen a nonzero digit in input

        if (_First != _Last && *_First == _Atoms[0]) { // leading zero, look for 0x, 0X
            _Seendigit = true;
            ++_First;
            if (_First != _Last && (*_First == _Atoms[_Numget_xoff + 1] || *_First == _Atoms[_Numget_xoff])
                && (_Base == 0 || _Base == 16)) {
                _Base      = 16;
                _Seendigit = false;
                ++_First;
            } else if (_Base == 0) {
                _Base = 8;
            }
        }

        const auto _Dlen = static_cast<size_t>(_Base == 0 || _Base == 10 ? 10 : _Base == 8 ? 8 : 16 + 6);
        string _Groups(1, static_cast<char>(_Seendigit)); // Groups are detected in the reversed order of _Groups.
        size_t _Groups_arr_idx = 0;

        for (char* const _Pe = &_Ac[_Max_int_dig - 1]; _First != _Last; ++_First) { // look for digits and separators
            size_t _Idx = _STD _Find_elem(_Atoms, *_First);
            if (_Idx < _Dlen) { // got a digit, characterize it and add to group size
                *_Ptr = _Src[_Idx];
                if ((_Nonzero || *_Ptr != '0') && _Ptr < _Pe) {
                    ++_Ptr;
                    _Nonzero = true;
                }

                _Seendigit = true;
                if (_Groups[_Groups_arr_idx] != CHAR_MAX) {
                    ++_Groups[_Groups_arr_idx];
                }
            } else if (_Kseparator == _Elem{} || *_First != _Kseparator) {
                break; // not a group separator, done
            } else if (_Groups[_Groups_arr_idx] == '\0') {
                _Bad_grouping = true; // adjacent separators, fail
            } else { // add a new group to _Groups string
                _Groups.push_back('\0');
                ++_Groups_arr_idx;
            }
        }

        if (_Groups_arr_idx != 0) {
            if (_Groups[_Groups_arr_idx] > '\0') {
                ++_Groups_arr_idx; // add trailing group to group count
            } else {
                _Bad_grouping = true; // trailing separator, fail
            }
        }

        // skip trailing separators
        if (_Kseparator != _Elem{}) {
            while (_First != _Last && *_First == _Kseparator) {
                ++_First;
                _Bad_grouping = true;
            }
        }

        const char* _Grouping_iter      = _Grouping.data();
        const char* const _Grouping_end = _Grouping_iter + _Grouping.size();
        for (char _Current_grouping_count = '\0'; _Seendigit && !_Bad_grouping && _Groups_arr_idx > 0;) {
            if (_Grouping_iter != _Grouping_end) { // keep the last value when _Grouping is exhausted
                _Current_grouping_count = *_Grouping_iter; // if _Grouping is empty, '\0' is used
                ++_Grouping_iter;
            }

            --_Groups_arr_idx;
            if ((_Current_grouping_count > '\0' && _Current_grouping_count != CHAR_MAX)
                && ((_Groups_arr_idx > 0 && _Groups[_Groups_arr_idx] != _Current_grouping_count)
                    || (_Groups_arr_idx == 0 && _Groups[_Groups_arr_idx] > _Current_grouping_count))) {
                _Bad_grouping = true; // bad group size, fail
            }
            // group size okay, advance to next test
        }

        if (!_Seendigit) {
            return {static_cast<int8_t>(~_Base), false};
        }

        if (!_Nonzero) {
            *_Ptr++ = '0'; // zero field, replace stripped zero(s)
        }

        *_Ptr = '\0';
        return {_Base, _Bad_grouping};
    }

    template <int = 0> // TRANSITION, ABI
    static _Num_get_parse_result _Parse_fp_with_locale(
        char* const _Ac, const int _Max_sig_dig, _InIt& _First, _InIt& _Last, const locale& _Loc) {
        // get floating-point field from [_First, _Last) into _Ac
        char* _Ptr = _Ac;

        constexpr size_t _Offset_dec_digit_end = 10;
        constexpr size_t _Offset_hex_digit_end = 22;
        constexpr size_t _Offset_neg_sign      = 22;
        constexpr size_t _Offset_pos_sign      = 23;
        constexpr size_t _Offset_upper_x       = 24;
        constexpr size_t _Offset_lower_x       = 25;
        constexpr size_t _Offset_upper_p       = 26;
        constexpr size_t _Offset_lower_p       = 27;
        constexpr size_t _Offset_upper_e       = 14;
        constexpr size_t _Offset_lower_e       = 20;
        static constexpr char _Src[]           = "0123456789ABCDEFabcdef-+XxPp";
        _Elem _Atoms[sizeof(_Src)];
        const auto& _Ctype_fac = _STD use_facet<ctype<_Elem>>(_Loc);
        _Ctype_fac.widen(_STD begin(_Src), _STD end(_Src), _Atoms);

        const _Elem _Positive_sign = _Atoms[_Offset_pos_sign];
        const _Elem _Negative_sign = _Atoms[_Offset_neg_sign];
        const _Elem _Zero_wc       = _Atoms[0];

        const auto& _Punct_fac  = _STD use_facet<numpunct<_Elem>>(_Loc);
        const string _Grouping  = _Punct_fac.grouping();
        const _Elem _Kseparator = _Grouping.empty() ? _Elem{} : _Punct_fac.thousands_sep();

        bool _Bad_grouping = false;

        // skip leading separators before the sign
        if (!_Grouping.empty()) {
            while (_First != _Last && *_First == _Kseparator) {
                ++_First;
                _Bad_grouping = true;
            }
        }

        if (_First != _Last) {
            if (*_First == _Positive_sign) { // gather plus sign
                *_Ptr++ = '+';
                ++_First;
            } else if (*_First == _Negative_sign) { // gather minus sign
                *_Ptr++ = '-';
                ++_First;
            }
        }

        *_Ptr++ = '0'; // backstop carries from sticky bit

        bool _Parse_hex                = false;
        bool _Seendigit                = false; // seen a digit in input
        char _Initial_dec_leading_zero = '\0';
        if (_First != _Last && *_First == _Zero_wc) {
            ++_First;
            if (_First == _Last) { // "0" only
                *_Ptr = '\0';
                return {10, _Bad_grouping};
            }

            if (*_First == _Atoms[_Offset_lower_x] || *_First == _Atoms[_Offset_upper_x]) { // 0x or 0X
                _Parse_hex = true;
                ++_First; // discard 0x or 0X for further parsing
                *_Ptr++ = 'x';
            } else {
                _Seendigit = true;
                ++_Initial_dec_leading_zero;
            }
        }

        bool _Has_unaccumulated_digits = false;
        int _Significant               = 0; // number of significant digits
        ptrdiff_t _Power_of_rep_base   = 0; // power of 10 or 16

        const size_t _Offset_digit_end = _Parse_hex ? _Offset_hex_digit_end : _Offset_dec_digit_end;
        if (_Grouping.empty()) {
            for (size_t _Idx; _First != _Last && (_Idx = _STD _Find_elem(_Atoms, *_First)) < _Offset_digit_end;
                _Seendigit = true, (void) ++_First) {
                if (_Significant >= _Max_sig_dig) {
                    ++_Power_of_rep_base; // just scale by 10 or 16
                    if (_Idx > 0) {
                        _Has_unaccumulated_digits = true;
                    }
                } else if (_Idx != 0 || _Significant != 0) { // save a significant digit
                    *_Ptr++ = _Src[_Idx];
                    ++_Significant;
                }
            }
        } else {
            // skip leading separators before digits
            while (_First != _Last && *_First == _Kseparator) {
                ++_First;
                _Bad_grouping = true;
            }

            string _Groups(1, _Initial_dec_leading_zero); // Groups are detected in the reversed order of _Groups.
            size_t _Groups_arr_idx = 0;

            for (; _First != _Last; ++_First) {
                const size_t _Idx = _STD _Find_elem(_Atoms, *_First);
                if (_Idx < _Offset_digit_end) { // got a digit, add to group size
                    _Seendigit = true;
                    if (_Significant >= _Max_sig_dig) {
                        ++_Power_of_rep_base; // just scale by 10 or 16
                        if (_Idx > 0) {
                            _Has_unaccumulated_digits = true;
                        }
                    } else if (_Idx != 0 || _Significant != 0) { // save a significant digit
                        *_Ptr++ = _Src[_Idx];
                        ++_Significant;
                    }

                    if (_Groups[_Groups_arr_idx] != CHAR_MAX) {
                        ++_Groups[_Groups_arr_idx];
                    }
                } else if (*_First != _Kseparator) {
                    break; // not a group separator, done
                } else if (_Groups[_Groups_arr_idx] == '\0') {
                    _Bad_grouping = true; // adjacent separators, fail
                } else { // add a new group to _Groups string
                    _Groups.push_back('\0');
                    ++_Groups_arr_idx;
                }
            }

            if (_Groups_arr_idx != 0) {
                if (_Groups[_Groups_arr_idx] > '\0') {
                    ++_Groups_arr_idx; // add trailing group to group count
                } else {
                    _Bad_grouping = true; // trailing separator, fail
                }
            }

            // skip trailing separators
            while (_First != _Last && *_First == _Kseparator) {
                ++_First;
                _Bad_grouping = true;
            }

            const char* _Grouping_iter      = _Grouping.data();
            const char* const _Grouping_end = _Grouping_iter + _Grouping.size();
            char _Current_grouping_count    = '\0';
            while (!_Bad_grouping && _Groups_arr_idx > 0) {
                if (_Grouping_iter != _Grouping_end) { // keep the last value when _Grouping is exhausted
                    _Current_grouping_count = *_Grouping_iter; // assign the variable at least once
                    ++_Grouping_iter;
                }

                --_Groups_arr_idx;
                if ((_Current_grouping_count > '\0' && _Current_grouping_count != CHAR_MAX)
                    && ((_Groups_arr_idx > 0 && _Groups[_Groups_arr_idx] != _Current_grouping_count)
                        || (_Groups_arr_idx == 0 && _Groups[_Groups_arr_idx] > _Current_grouping_count))) {
                    _Bad_grouping = true; // bad group size, fail
                }
                // group size okay, advance to next test
            }
        }

        if (_Parse_hex && _Seendigit && _Significant == 0) {
            // the condition is true when all of the digits after the 'x' and before the decimal point are zero
            *_Ptr++ = '0'; // save at least one leading digit for hex
        }

        const char _Decimal_point = (_CSTD localeconv())->decimal_point[0];
        if (_First != _Last && *_First == _Punct_fac.decimal_point()) { // add .
            *_Ptr++ = _Decimal_point;
            ++_First;
        }

        if (_Significant == 0) { // 0000. so far
            for (; _First != _Last && *_First == _Zero_wc; _Seendigit = true, (void) ++_First) {
                --_Power_of_rep_base; // count leading fraction zeros without storing digits into buffer
            }
        }

        for (size_t _Idx; _First != _Last && (_Idx = _STD _Find_elem(_Atoms, *_First)) < _Offset_digit_end;
            _Seendigit = true, (void) ++_First) {
            if (_Significant < _Max_sig_dig) { // save a significant fraction digit
                *_Ptr++ = _Src[_Idx];
                ++_Significant;
            } else if (_Idx > 0) {
                _Has_unaccumulated_digits = true; // just update _Has_unaccumulated_digits
            }
        }

        if (_Has_unaccumulated_digits) { // increment last digit in memory of those lost
            char& _Last_got_digit = _Ptr[-1] == _Decimal_point ? _Ptr[-2] : _Ptr[-1];
            if (_Last_got_digit == '0' || _Last_got_digit == (_Parse_hex ? '8' : '5')) {
                ++_Last_got_digit;
            }
        }

        const _Elem _Lower_exp_wc = _Atoms[_Parse_hex ? _Offset_lower_p : _Offset_lower_e]; // 'e' for dec, 'p' for hex
        const _Elem _Upper_exp_wc = _Atoms[_Parse_hex ? _Offset_upper_p : _Offset_upper_e]; // 'E' for dec, 'P' for hex

        bool _Exponent_part_negative = false;
        ptrdiff_t _Exponent_part     = 0;
        if (_Seendigit && _First != _Last
            && (*_First == _Lower_exp_wc || *_First == _Upper_exp_wc)) { // collect exponent
            ++_First;
            _Seendigit   = false;
            _Significant = 0;

            if (_First != _Last) {
                if (*_First == _Positive_sign) { // gather plus sign
                    ++_First;
                } else if (*_First == _Negative_sign) { // gather minus sign
                    _Exponent_part_negative = true;
                    ++_First;
                }
            }

            for (; _First != _Last && *_First == _Zero_wc; ++_First) { // strip leading zeros
                _Seendigit = true;
            }

            for (size_t _Idx; _First != _Last && (_Idx = _STD _Find_elem(_Atoms, *_First)) < _Offset_dec_digit_end;
                _Seendigit = true, (void) ++_First) {
                if (_Exponent_part < PTRDIFF_MAX / 10
                    || (_Exponent_part == PTRDIFF_MAX / 10
                        && static_cast<ptrdiff_t>(_Idx) <= PTRDIFF_MAX % 10)) { // save a significant exponent digit
                    _Exponent_part = _Exponent_part * 10 + static_cast<ptrdiff_t>(_Idx);
                } else {
                    _Exponent_part = PTRDIFF_MAX; // saturated
                }
            }

            if (_Exponent_part_negative) {
                _Exponent_part = -_Exponent_part;
            }
        }

        if (!_Seendigit) {
            return {0, false};
        }

        constexpr int _Dec_exp_abs_bound = 1100; // slightly greater than 324 + 768
        constexpr int _Hex_exp_abs_bound = 4200; // slightly greater than 1074 + 768 * 4

        const ptrdiff_t _Exp_abs_bound     = _Parse_hex ? _Hex_exp_abs_bound : _Dec_exp_abs_bound;
        const ptrdiff_t _Exp_rep_abs_bound = _Parse_hex ? _Hex_exp_abs_bound / 4 : _Dec_exp_abs_bound;

        // basically _Exponent_part = _STD clamp(-_Exp_abs_bound,
        //     _Exponent_part + _Parse_hex ? _Power_of_rep_base * 4 : _Power_of_rep_base, _Exp_abs_bound)
        // but need to defend overflowing
        for (ptrdiff_t _Power_of_rep_adjusted = _Power_of_rep_base;;) {
            if (_Exponent_part >= 0 && _Power_of_rep_adjusted >= 0
                && (_Exponent_part >= _Exp_abs_bound || _Power_of_rep_adjusted >= _Exp_rep_abs_bound)) {
                _Exponent_part = _Exp_abs_bound;
                break;
            } else if (_Exponent_part <= 0 && _Power_of_rep_adjusted <= 0
                       && (_Exponent_part <= -_Exp_abs_bound || _Power_of_rep_adjusted <= -_Exp_rep_abs_bound)) {
                _Exponent_part = -_Exp_abs_bound;
                break;
            } else if (_STD abs(_Exponent_part) <= _Exp_abs_bound
                       && _STD abs(_Power_of_rep_adjusted) <= _Exp_rep_abs_bound) {
                // _Exponent_part and _Power_of_rep_base are of different signedness, both of which are small enough
                _Exponent_part += _Parse_hex ? _Power_of_rep_adjusted * 4 : _Power_of_rep_adjusted;
                if (_Exponent_part > _Exp_abs_bound) {
                    _Exponent_part = _Exp_abs_bound;
                } else if (_Exponent_part < -_Exp_abs_bound) {
                    _Exponent_part = -_Exp_abs_bound;
                }
                break;
            } else {
                // only enters once:
                // _Exponent_part and _Power_of_rep_base are of different signedness, but at least one is large
                const ptrdiff_t _Exponent_part_preadjustment_round_up =
                    _Parse_hex ? (_STD abs(_Exponent_part) - 1) / 4 + 1 : _STD abs(_Exponent_part);
                const ptrdiff_t _Exp_rep_adjustment =
                    (_STD min)(_Exponent_part_preadjustment_round_up, _STD abs(_Power_of_rep_base));

                if (_Exponent_part >= 0) {
                    _Exponent_part -= _Parse_hex ? _Exp_rep_adjustment * 4 : _Exp_rep_adjustment;
                    _Power_of_rep_adjusted += _Exp_rep_adjustment;
                } else {
                    _Exponent_part += _Parse_hex ? _Exp_rep_adjustment * 4 : _Exp_rep_adjustment;
                    _Power_of_rep_adjusted -= _Exp_rep_adjustment;
                }
            }
        }

        if (_Exponent_part != 0) {
            *_Ptr++ = _Parse_hex ? 'p' : 'e';
            if (_Exponent_part < 0) {
                *_Ptr++ = '-';
            }

            char* const _Rev_begin = _Ptr;
            for (ptrdiff_t _Exponent_part_abs = _STD abs(_Exponent_part); _Exponent_part_abs != 0;
                _Exponent_part_abs /= 10) {
                *_Ptr++ = static_cast<char>('0' + _Exponent_part_abs % 10);
            }
            _STD reverse(_Rev_begin, _Ptr);
        }

        *_Ptr = '\0';
        return {static_cast<int8_t>(_Parse_hex ? 16 : 10), _Bad_grouping};
    }

    // TRANSITION, ABI, unused now, tracked by VSO-591516.
    int __CLRCALL_OR_CDECL _Getifld(
        char* _Ac, _InIt& _First, _InIt& _Last, ios_base::fmtflags _Basefield, const locale& _Loc) const {
        // get integer field from [_First, _Last) into _Ac
        static constexpr char _Src[] = "0123456789ABCDEFabcdef-+Xx"; // TRANSITION, ABI, was implicitly dllexported
        const char* volatile _Ptr    = _Src;
        (void) _Ptr;

        const auto _Parse_result = _Parse_int_with_locale(_Ac, _First, _Last, _Basefield, _Loc);
        if (_Parse_result._Base < 0 || _Parse_result._Bad_grouping) { // TRANSITION, ABI, old behavior
            *_Ac = '\0';
        }
        return _Parse_result._Base < 0 ? ~_Parse_result._Base : _Parse_result._Base;
    }

#define _MAX_SIG_DIG_V1 36 // TRANSITION, ABI
// TRANSITION, ABI: Sentinel value used by num_get::do_get()
// to enable correct "V2" behavior in _Getffld() and _Getffldx()
#define _ENABLE_V2_BEHAVIOR 1000000000

    // TRANSITION, ABI, unused now
    int __CLRCALL_OR_CDECL _Getffld(char* _Ac, _InIt& _First, _InIt& _Last, ios_base& _Iosbase, int* _Phexexp) const {
        // get floating-point field from [_First, _Last) into _Ac
        static constexpr char _Src[] = "0123456789-+Ee"; // TRANSITION, ABI, was implicitly dllexported
        const char* volatile _Ptr    = &_Src[0];
        (void) _Ptr;
        const int _Max_sig_dig   = (*_Phexexp == _ENABLE_V2_BEHAVIOR ? _MAX_SIG_DIG_V2 : _MAX_SIG_DIG_V1);
        const auto _Parse_result = _Parse_fp_with_locale(_Ac, _Max_sig_dig, _First, _Last, _Iosbase.getloc());
        if (_Parse_result._Base == 0 || _Parse_result._Bad_grouping) { // TRANSITION, ABI, old behavior
            *_Ac = '\0';
        }

        if (_Parse_result._Base == 16) {
            *_Phexexp = 0; // power of 16 multiplier, unnecessary now
        }
        return 0; // power of 10 multiplier, unnecessary now
    }

    // TRANSITION, ABI, unused now
    int __CLRCALL_OR_CDECL _Getffldx(char* _Ac, _InIt& _First, _InIt& _Last, ios_base& _Iosbase, int* _Phexexp) const {
        // get floating-point field from [_First, _Last) into _Ac
        static constexpr char _Src[] = "0123456789ABCDEFabcdef-+XxPp"; // TRANSITION, ABI, was implicitly dllexported
        const char* volatile _Ptr    = &_Src[0];
        (void) _Ptr;
        const int _Max_sig_dig   = (*_Phexexp == _ENABLE_V2_BEHAVIOR ? _MAX_SIG_DIG_V2 : _MAX_SIG_DIG_V1);
        const auto _Parse_result = _Parse_fp_with_locale(_Ac, _Max_sig_dig, _First, _Last, _Iosbase.getloc());
        if (_Parse_result._Base == 0 || _Parse_result._Bad_grouping) { // TRANSITION, ABI, old behavior
            *_Ac = '\0';
        }

        if (_Parse_result._Base == 16) {
            *_Phexexp = 0; // power of 16 multiplier, unnecessary now
        }
        return 0; // power of 10 multiplier, unnecessary now
    }

#undef _ENABLE_V2_BEHAVIOR
#undef _MAX_SIG_DIG_V1
#undef _MAX_SIG_DIG_V2
};

#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdllimport-static-field-def"
#endif // defined(__clang__)

template <class _Elem, class _InIt>
__PURE_APPDOMAIN_GLOBAL locale::id num_get<_Elem, _InIt>::id;

#ifdef __clang__
#pragma clang diagnostic pop
#endif // defined(__clang__)

template <class _Ty>
int _Float_put_desired_precision(const streamsize _Precision, const ios_base::fmtflags _Float_flags) {
    // return the effective precision determined by N4950 [facet.num.put.virtuals]/2.1 and printf's rules
    const bool _Is_hex = _Float_flags == (ios_base::fixed | ios_base::scientific);
    if (_Is_hex) {
        // return the number of hexits needed (after the radix point) to represent the floating-point value exactly
        if constexpr (is_same_v<_Ty, double>) {
            return ((DBL_MANT_DIG - 1) + 3) / 4;
        } else if constexpr (is_same_v<_Ty, long double>) {
            return ((LDBL_MANT_DIG - 1) + 3) / 4;
        } else {
            _STL_INTERNAL_STATIC_ASSERT(false); // unexpected type; shouldn't be float
        }
    }

    if (_Precision > 0) {
        return static_cast<int>(_Precision);
    } else if (_Precision == 0) {
        const bool _Is_default_float = _Float_flags == 0;
        if (_Is_default_float) {
            return 1;
        } else {
            return 0;
        }
    } else {
        constexpr int _Default_precision = 6;
        return _Default_precision;
    }
}

_EXPORT_STD extern "C++" template <class _Elem, class _OutIt = ostreambuf_iterator<_Elem, char_traits<_Elem>>>
class num_put : public locale::facet { // facet for converting encoded numbers to text
public:
    static_assert(!_ENFORCE_FACET_SPECIALIZATIONS || _Is_any_of_v<_Elem, char, wchar_t>, _FACET_SPECIALIZATION_MESSAGE);

    static size_t __CLRCALL_OR_CDECL _Getcat(const locale::facet** _Ppf = nullptr, const locale* _Ploc = nullptr) {
        // return locale category mask and construct standard facet
        if (_Ppf && !*_Ppf) {
            *_Ppf = new num_put<_Elem, _OutIt>(_Locinfo(_Ploc->_C_str()));
        }

        return _X_NUMERIC;
    }

    __PURE_APPDOMAIN_GLOBAL static locale::id id; // unique facet id

protected:
    __CLR_OR_THIS_CALL ~num_put() noexcept override {}

    void __CLR_OR_THIS_CALL _Init(const _Locinfo&) {} // initialize from _Locinfo object

public:
    explicit __CLR_OR_THIS_CALL num_put(size_t _Refs = 0) : locale::facet(_Refs) { // construct from current locale
        _BEGIN_LOCINFO(_Lobj)
        _Init(_Lobj);
        _END_LOCINFO()
    }

    __CLR_OR_THIS_CALL num_put(const _Locinfo& _Lobj, size_t _Refs = 0) : locale::facet(_Refs) {
        _Init(_Lobj);
    }

    using char_type = _Elem;
    using iter_type = _OutIt;

    _OutIt __CLR_OR_THIS_CALL put(
        _OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, bool _Val) const { // put formatted bool to _Dest
        return do_put(_Dest, _Iosbase, _Fill, _Val);
    }

    _OutIt __CLR_OR_THIS_CALL put(
        _OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, long _Val) const { // put formatted long to _Dest
        return do_put(_Dest, _Iosbase, _Fill, _Val);
    }

    _OutIt __CLR_OR_THIS_CALL put(_OutIt _Dest, ios_base& _Iosbase, _Elem _Fill,
        unsigned long _Val) const { // put formatted unsigned long to _Dest
        return do_put(_Dest, _Iosbase, _Fill, _Val);
    }

    _OutIt __CLR_OR_THIS_CALL put(
        _OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, long long _Val) const { // put formatted long long to _Dest
        return do_put(_Dest, _Iosbase, _Fill, _Val);
    }

    _OutIt __CLR_OR_THIS_CALL put(_OutIt _Dest, ios_base& _Iosbase, _Elem _Fill,
        unsigned long long _Val) const { // put formatted unsigned long long to _Dest
        return do_put(_Dest, _Iosbase, _Fill, _Val);
    }

    _OutIt __CLR_OR_THIS_CALL put(
        _OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, double _Val) const { // put formatted double to _Dest
        return do_put(_Dest, _Iosbase, _Fill, _Val);
    }

    _OutIt __CLR_OR_THIS_CALL put(
        _OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, long double _Val) const { // put formatted long double to _Dest
        return do_put(_Dest, _Iosbase, _Fill, _Val);
    }

    _OutIt __CLR_OR_THIS_CALL put(
        _OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, const void* _Val) const { // put formatted void pointer to _Dest
        return do_put(_Dest, _Iosbase, _Fill, _Val);
    }

protected:
    virtual _OutIt __CLR_OR_THIS_CALL do_put(
        _OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, bool _Val) const { // put formatted bool to _Dest
        if (!(_Iosbase.flags() & ios_base::boolalpha)) {
            return do_put(_Dest, _Iosbase, _Fill, static_cast<long>(_Val));
        } else { // put "false" or "true"
            const auto& _Punct_fac = _STD use_facet<numpunct<_Elem>>(_Iosbase.getloc());
            basic_string<_Elem> _Str;
            if (_Val) {
                _Str.assign(_Punct_fac.truename());
            } else {
                _Str.assign(_Punct_fac.falsename());
            }

            size_t _Fillcount;
            if (_Iosbase.width() <= 0 || static_cast<size_t>(_Iosbase.width()) <= _Str.size()) {
                _Fillcount = 0;
            } else {
                _Fillcount = static_cast<size_t>(_Iosbase.width()) - _Str.size();
            }

            if ((_Iosbase.flags() & ios_base::adjustfield) != ios_base::left) { // put leading fill
                _Dest      = _Rep(_Dest, _Fill, _Fillcount);
                _Fillcount = 0;
            }
            _Dest = _Put(_Dest, _Str.c_str(), _Str.size()); // put field
            _Iosbase.width(0);
            return _Rep(_Dest, _Fill, _Fillcount); // put trailing fill
        }
    }

#pragma warning(push)
#pragma warning(disable : 4774) // format string expected in argument N is not a string literal (/Wall)
    virtual _OutIt __CLR_OR_THIS_CALL do_put(
        _OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, long _Val) const { // put formatted long to _Dest
        char _Buf[2 * _Max_int_dig];
        char _Fmt[6];

        return _Iput(_Dest, _Iosbase, _Fill, _Buf,
            static_cast<size_t>(_CSTD sprintf_s(_Buf, sizeof(_Buf), _Ifmt(_Fmt, "ld", _Iosbase.flags()), _Val)));
    }

    virtual _OutIt __CLR_OR_THIS_CALL do_put(_OutIt _Dest, ios_base& _Iosbase, _Elem _Fill,
        unsigned long _Val) const { // put formatted unsigned long to _Dest
        char _Buf[2 * _Max_int_dig];
        char _Fmt[6];

        return _Iput(_Dest, _Iosbase, _Fill, _Buf,
            static_cast<size_t>(_CSTD sprintf_s(_Buf, sizeof(_Buf), _Ifmt(_Fmt, "lu", _Iosbase.flags()), _Val)));
    }

    virtual _OutIt __CLR_OR_THIS_CALL do_put(
        _OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, long long _Val) const { // put formatted long long to _Dest
        char _Buf[2 * _Max_int_dig];
        char _Fmt[8];

        return _Iput(_Dest, _Iosbase, _Fill, _Buf,
            static_cast<size_t>(_CSTD sprintf_s(_Buf, sizeof(_Buf), _Ifmt(_Fmt, "Ld", _Iosbase.flags()), _Val)));
    }

    virtual _OutIt __CLR_OR_THIS_CALL do_put(_OutIt _Dest, ios_base& _Iosbase, _Elem _Fill,
        unsigned long long _Val) const { // put formatted unsigned long long to _Dest
        char _Buf[2 * _Max_int_dig];
        char _Fmt[8];

        return _Iput(_Dest, _Iosbase, _Fill, _Buf,
            static_cast<size_t>(_CSTD sprintf_s(_Buf, sizeof(_Buf), _Ifmt(_Fmt, "Lu", _Iosbase.flags()), _Val)));
    }

    virtual _OutIt __CLR_OR_THIS_CALL do_put(
        _OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, double _Val) const { // put formatted double to _Dest
        string _Buf;
        char _Fmt[8];
        const auto _Float_flags     = _Iosbase.flags() & ios_base::floatfield;
        const bool _Is_fixed        = _Float_flags == ios_base::fixed;
        const bool _Is_hex          = _Float_flags == (ios_base::fixed | ios_base::scientific);
        const streamsize _Precision = _Is_hex ? -1 : _Iosbase.precision(); // precision setting
        const int _Desired_precision =
            _Float_put_desired_precision<double>(_Precision, _Float_flags); // desired precision
        size_t _Bufsize = static_cast<size_t>(_Desired_precision);
        if (_Is_fixed && 1e10 < _CSTD fabs(_Val)) { // f or F format
            int _Ptwo;
            (void) _CSTD frexp(_Val, &_Ptwo);
            _Bufsize += _CSTD abs(_Ptwo) * 30103L / 100000L;
        }

        _Buf.resize(_Bufsize + 50); // add fudge factor
        const bool _Is_finite      = (_STD isfinite)(_Val);
        const auto _Adjusted_flags = // TRANSITION, DevCom-10519861
            _Is_finite ? _Iosbase.flags() : _Iosbase.flags() & ~ios_base::showpoint;
        const auto _Ngen = static_cast<size_t>(_CSTD sprintf_s(
            &_Buf[0], _Buf.size(), _Ffmt(_Fmt, 0, _Adjusted_flags), static_cast<int>(_Precision), _Val));

        return _Fput_v3(_Dest, _Iosbase, _Fill, _Buf.c_str(), _Ngen, _Is_finite);
    }

    virtual _OutIt __CLR_OR_THIS_CALL do_put(
        _OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, long double _Val) const { // put formatted long double to _Dest
        string _Buf;
        char _Fmt[8];
        const auto _Float_flags     = _Iosbase.flags() & ios_base::floatfield;
        const bool _Is_fixed        = _Float_flags == ios_base::fixed;
        const bool _Is_hex          = _Float_flags == (ios_base::fixed | ios_base::scientific);
        const streamsize _Precision = _Is_hex ? -1 : _Iosbase.precision(); // precision setting
        const int _Desired_precision =
            _Float_put_desired_precision<long double>(_Precision, _Float_flags); // desired precision
        size_t _Bufsize = static_cast<size_t>(_Desired_precision);
        if (_Is_fixed && 1e10 < _CSTD fabsl(_Val)) { // f or F format
            int _Ptwo;
            (void) _CSTD frexpl(_Val, &_Ptwo);
            _Bufsize += _CSTD abs(_Ptwo) * 30103L / 100000L;
        }

        _Buf.resize(_Bufsize + 50); // add fudge factor
        const bool _Is_finite      = (_STD isfinite)(_Val);
        const auto _Adjusted_flags = // TRANSITION, DevCom-10519861
            _Is_finite ? _Iosbase.flags() : _Iosbase.flags() & ~ios_base::showpoint;
        const auto _Ngen = static_cast<size_t>(_CSTD sprintf_s(
            &_Buf[0], _Buf.size(), _Ffmt(_Fmt, 'L', _Adjusted_flags), static_cast<int>(_Precision), _Val));

        return _Fput_v3(_Dest, _Iosbase, _Fill, _Buf.c_str(), _Ngen, _Is_finite);
    }
#pragma warning(pop)

    virtual _OutIt __CLR_OR_THIS_CALL do_put(
        _OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, const void* _Val) const { // put formatted void pointer to _Dest
        char _Buf[2 * _Max_int_dig];

        return _Iput(
            _Dest, _Iosbase, _Fill, _Buf, static_cast<size_t>(_CSTD sprintf_s(_Buf, sizeof(_Buf), "%p", _Val)));
    }

private:
    char* __CLRCALL_OR_CDECL _Ffmt(
        char* _Fmt, char _Spec, ios_base::fmtflags _Flags) const { // generate sprintf format for floating-point
        char* _Ptr = _Fmt;
        *_Ptr++    = '%';

        if (_Flags & ios_base::showpos) {
            *_Ptr++ = '+';
        }

        if (_Flags & ios_base::showpoint) {
            *_Ptr++ = '#';
        }

        *_Ptr++ = '.';
        *_Ptr++ = '*'; // for precision argument
        if (_Spec != '\0') {
            *_Ptr++ = _Spec; // 'L' qualifier for long double only
        }

        char _Ch; // specifier
        ios_base::fmtflags _Ffl = _Flags & ios_base::floatfield;
        if (_Flags & ios_base::uppercase) {
            if (_Ffl == ios_base::fixed) {
                _Ch = 'F';
            } else if (_Ffl == (ios_base::scientific | ios_base::fixed)) {
                _Ch = 'A';
            } else if (_Ffl == ios_base::scientific) {
                _Ch = 'E';
            } else {
                _Ch = 'G';
            }
        } else {
            if (_Ffl == ios_base::fixed) {
                _Ch = 'f';
            } else if (_Ffl == (ios_base::scientific | ios_base::fixed)) {
                _Ch = 'a';
            } else if (_Ffl == ios_base::scientific) {
                _Ch = 'e';
            } else {
                _Ch = 'g';
            }
        }
        *_Ptr++ = _Ch;

        *_Ptr = '\0';
        return _Fmt;
    }

    _OutIt __CLRCALL_OR_CDECL _Fput(_OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, const char* _Buf,
        size_t _Count) const { // TRANSITION, ABI: preserved for binary compatibility
        return _Fput_v3(_Dest, _Iosbase, _Fill, _Buf, _Count, true);
    }

    template <int = 0> // TRANSITION, ABI
    _OutIt _Fput_v3(_OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, const char* _Buf, size_t _Count,
        bool _Is_finite_val) const { // put formatted floating-point to _Dest
        auto _Prefix = static_cast<size_t>(0 < _Count && (*_Buf == '+' || *_Buf == '-'));
        const char* _Exps;
        if ((_Iosbase.flags() & ios_base::floatfield) != (ios_base::scientific | ios_base::fixed)) {
            _Exps = "eE";
        } else { // correct for hexadecimal floating-point
            _Exps = "pP";
            if (_Prefix + 2 <= _Count && _Buf[_Prefix] == '0'
                && (_Buf[_Prefix + 1] == 'x' || _Buf[_Prefix + 1] == 'X')) {
                _Prefix += 2;
            }
        }
        const size_t _Eoff = _CSTD strcspn(&_Buf[0], _Exps); // find exponent
        char _Dp[2]        = {"."};
        _Dp[0]             = (_CSTD localeconv())->decimal_point[0];
        const size_t _Poff = _CSTD strcspn(&_Buf[0], &_Dp[0]); // find decimal point

        const ctype<_Elem>& _Ctype_fac = _STD use_facet<ctype<_Elem>>(_Iosbase.getloc());
        basic_string<_Elem> _Groupstring(_Count, _Elem(0)); // reserve space
        _Ctype_fac.widen(_Buf, _Buf + _Count, &_Groupstring[0]);

        const auto& _Punct_fac  = _STD use_facet<numpunct<_Elem>>(_Iosbase.getloc());
        const string _Grouping  = _Punct_fac.grouping();
        const _Elem _Kseparator = _Punct_fac.thousands_sep();

        if (_Poff != _Count) {
            _Groupstring[_Poff] = _Punct_fac.decimal_point();
        }

        if (_Is_finite_val) {
            size_t _Off     = _Poff == _Count ? _Eoff : _Poff;
            const char* _Pg = &_Grouping[0];
            while (*_Pg != CHAR_MAX && '\0' < *_Pg && static_cast<size_t>(*_Pg) < _Off - _Prefix) {
                // add thousands separator
                _Groupstring.insert(_Off -= *_Pg, 1, _Kseparator);
                if ('\0' < _Pg[1]) {
                    ++_Pg; // not last group, advance
                }
            }
        }

        _Count = _Groupstring.size();

        size_t _Fillcount;
        if (_Iosbase.width() <= 0 || static_cast<size_t>(_Iosbase.width()) <= _Count) {
            _Fillcount = 0;
        } else {
            _Fillcount = static_cast<size_t>(_Iosbase.width()) - _Count;
        }

        ios_base::fmtflags _Adjustfield = _Iosbase.flags() & ios_base::adjustfield;
        if (_Adjustfield != ios_base::left && _Adjustfield != ios_base::internal) { // put leading fill
            _Dest      = _Rep(_Dest, _Fill, _Fillcount);
            _Fillcount = 0;
            _Dest      = _Put(_Dest, &_Groupstring[0], _Prefix);
        } else if (_Adjustfield == ios_base::internal) { // put internal fill
            _Dest      = _Put(_Dest, &_Groupstring[0], _Prefix);
            _Dest      = _Rep(_Dest, _Fill, _Fillcount);
            _Fillcount = 0;
        } else {
            _Dest = _Put(_Dest, &_Groupstring[0], _Prefix);
        }

        _Dest = _Put(_Dest, &_Groupstring[_Prefix], _Count - _Prefix);
        _Iosbase.width(0);
        return _Rep(_Dest, _Fill, _Fillcount); // put trailing fill
    }

    char* __CLRCALL_OR_CDECL _Ifmt(
        char* _Fmt, const char* _Spec, ios_base::fmtflags _Flags) const { // generate sprintf format for integer
        char* _Ptr = _Fmt;
        *_Ptr++    = '%';

        if (_Flags & ios_base::showpos) {
            *_Ptr++ = '+';
        }

        if (_Flags & ios_base::showbase) {
            *_Ptr++ = '#';
        }

        if (_Spec[0] != 'L') {
            *_Ptr++ = _Spec[0]; // qualifier
        } else { // change L to I64
            *_Ptr++ = 'I';
            *_Ptr++ = '6';
            *_Ptr++ = '4';
        }

        ios_base::fmtflags _Basefield = _Flags & ios_base::basefield;
        *_Ptr++                       = _Basefield == ios_base::oct  ? 'o'
                                      : _Basefield != ios_base::hex  ? _Spec[1] // 'd' or 'u'
                                      : _Flags & ios_base::uppercase ? 'X'
                                                                     : 'x';
        *_Ptr                         = '\0';
        return _Fmt;
    }

    _OutIt __CLRCALL_OR_CDECL _Iput(_OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, char* _Buf,
        size_t _Count) const { // put formatted integer to _Dest
        auto _Prefix = static_cast<size_t>(0 < _Count && (*_Buf == '+' || *_Buf == '-'));
        if ((_Iosbase.flags() & ios_base::basefield) == ios_base::hex && _Prefix + 2 <= _Count && _Buf[_Prefix] == '0'
            && (_Buf[_Prefix + 1] == 'x' || _Buf[_Prefix + 1] == 'X')) {
            _Prefix += 2;
        }

        const ctype<_Elem>& _Ctype_fac = _STD use_facet<ctype<_Elem>>(_Iosbase.getloc());
        basic_string<_Elem> _Groupstring(_Count, _Elem(0)); // reserve space
        _Ctype_fac.widen(_Buf, _Buf + _Count, &_Groupstring[0]);

        const auto& _Punct_fac = _STD use_facet<numpunct<_Elem>>(_Iosbase.getloc());
        const string _Grouping = _Punct_fac.grouping();
        const char* _Pg        = &_Grouping[0];
        if (*_Pg != CHAR_MAX && '\0' < *_Pg) { // grouping specified, add thousands separators
            const _Elem _Kseparator = _Punct_fac.thousands_sep();
            while (*_Pg != CHAR_MAX && '\0' < *_Pg && static_cast<size_t>(*_Pg) < _Count - _Prefix) {
                // insert thousands separator
                _Count -= *_Pg;
                _Groupstring.insert(_Count, 1, _Kseparator);
                if ('\0' < _Pg[1]) {
                    ++_Pg; // not last group, advance
                }
            }
        }

        _Count = _Groupstring.size();

        size_t _Fillcount;
        if (_Iosbase.width() <= 0 || static_cast<size_t>(_Iosbase.width()) <= _Count) {
            _Fillcount = 0;
        } else {
            _Fillcount = static_cast<size_t>(_Iosbase.width()) - _Count;
        }

        ios_base::fmtflags _Adjustfield = _Iosbase.flags() & ios_base::adjustfield;
        if (_Adjustfield != ios_base::left && _Adjustfield != ios_base::internal) { // put leading fill
            _Dest      = _Rep(_Dest, _Fill, _Fillcount);
            _Fillcount = 0;
            _Dest      = _Put(_Dest, &_Groupstring[0], _Prefix);
        } else if (_Adjustfield == ios_base::internal) { // put internal fill
            _Dest      = _Put(_Dest, &_Groupstring[0], _Prefix);
            _Dest      = _Rep(_Dest, _Fill, _Fillcount);
            _Fillcount = 0;
        } else {
            _Dest = _Put(_Dest, &_Groupstring[0], _Prefix);
        }

        _Dest = _Put(_Dest, &_Groupstring[_Prefix], _Count - _Prefix);
        _Iosbase.width(0);
        return _Rep(_Dest, _Fill, _Fillcount); // put trailing fill
    }

    _OutIt __CLRCALL_OR_CDECL _Put(
        _OutIt _Dest, const _Elem* _Ptr, size_t _Count) const { // put [_Ptr, _Ptr + _Count) to _Dest
        for (; 0 < _Count; --_Count, (void) ++_Dest, ++_Ptr) {
            *_Dest = *_Ptr;
        }

        return _Dest;
    }

    _OutIt __CLRCALL_OR_CDECL _Rep(_OutIt _Dest, _Elem _Ch, size_t _Count) const { // put _Count * _Ch to _Dest
        for (; 0 < _Count; --_Count, (void) ++_Dest) {
            *_Dest = _Ch;
        }

        return _Dest;
    }
};

#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdllimport-static-field-def"
#endif // defined(__clang__)

template <class _Elem, class _OutIt>
__PURE_APPDOMAIN_GLOBAL locale::id num_put<_Elem, _OutIt>::id;

#if defined(_DLL_CPPLIB)

#if !defined(_CRTBLD) || defined(__FORCE_INSTANCE)
template __PURE_APPDOMAIN_GLOBAL locale::id numpunct<char>::id;
template class _CRTIMP2_PURE_IMPORT num_get<char, istreambuf_iterator<char, char_traits<char>>>;
template class _CRTIMP2_PURE_IMPORT num_put<char, ostreambuf_iterator<char, char_traits<char>>>;

template __PURE_APPDOMAIN_GLOBAL locale::id numpunct<wchar_t>::id;
template class _CRTIMP2_PURE_IMPORT num_get<wchar_t, istreambuf_iterator<wchar_t, char_traits<wchar_t>>>;
template class _CRTIMP2_PURE_IMPORT num_put<wchar_t, ostreambuf_iterator<wchar_t, char_traits<wchar_t>>>;
#endif // !defined(_CRTBLD) || defined(__FORCE_INSTANCE)

#ifdef __FORCE_INSTANCE
template __PURE_APPDOMAIN_GLOBAL locale::id numpunct<unsigned short>::id;
template class _CRTIMP2_PURE_IMPORT
    num_get<unsigned short, istreambuf_iterator<unsigned short, char_traits<unsigned short>>>;
template class _CRTIMP2_PURE_IMPORT
    num_put<unsigned short, ostreambuf_iterator<unsigned short, char_traits<unsigned short>>>;
#endif // defined(__FORCE_INSTANCE)
#endif // defined(_DLL_CPPLIB)

#ifdef __clang__
#pragma clang diagnostic pop
#endif // defined(__clang__)
_STD_END
#pragma pop_macro("new")
_STL_RESTORE_CLANG_WARNINGS
#pragma warning(pop)
#pragma pack(pop)
#endif // _STL_COMPILER_PREPROCESSOR
#endif // _XLOCNUM_
