зеркало из https://github.com/microsoft/STL.git
1679 строки
69 KiB
C++
1679 строки
69 KiB
C++
// 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_
|