зеркало из https://github.com/microsoft/STL.git
1649 строки
65 KiB
C++
1649 строки
65 KiB
C++
// xlocnum internal header
|
|
|
|
// Copyright (c) Microsoft Corporation.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
#pragma once
|
|
#ifndef _XLOCNUM_
|
|
#define _XLOCNUM_
|
|
#include <yvals_core.h>
|
|
#if _STL_COMPILER_PREPROCESSOR
|
|
#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
|
|
|
|
// TEXT-TO-NUMERIC CONVERSION FUNCTIONS
|
|
|
|
_EXTERN_C_UNLESS_PURE
|
|
|
|
extern _CRTIMP2_PURE float __CLRCALL_PURE_OR_CDECL _Stofx(
|
|
const char*, _Out_opt_ _Deref_post_opt_valid_ char**, long, int*);
|
|
extern _CRTIMP2_PURE double __CLRCALL_PURE_OR_CDECL _Stodx(
|
|
const char*, _Out_opt_ _Deref_post_opt_valid_ char**, long, int*);
|
|
extern _CRTIMP2_PURE long double __CLRCALL_PURE_OR_CDECL _Stoldx(
|
|
const char*, _Out_opt_ _Deref_post_opt_valid_ char**, long, int*);
|
|
extern _CRTIMP2_PURE long __CLRCALL_PURE_OR_CDECL _Stolx(
|
|
const char*, _Out_opt_ _Deref_post_opt_valid_ char**, int, int*);
|
|
extern _CRTIMP2_PURE unsigned long __CLRCALL_PURE_OR_CDECL _Stoulx(
|
|
const char*, _Out_opt_ _Deref_post_opt_valid_ char**, int, int*);
|
|
extern _CRTIMP2_PURE long long __CLRCALL_PURE_OR_CDECL _Stollx(
|
|
const char*, _Out_opt_ _Deref_post_opt_valid_ char**, int, int*);
|
|
extern _CRTIMP2_PURE unsigned long long __CLRCALL_PURE_OR_CDECL _Stoullx(
|
|
const char*, _Out_opt_ _Deref_post_opt_valid_ char**, int, int*);
|
|
|
|
_END_EXTERN_C_UNLESS_PURE
|
|
|
|
_STD_BEGIN
|
|
|
|
// FUNCTION _Stodx_v2
|
|
inline double _Stodx_v2(const char* _Str, char** _Endptr, int _Pten, int* _Perr) { // 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;
|
|
|
|
if (_Pten != 0) {
|
|
_Val *= _CSTD pow(10.0, static_cast<double>(_Pten));
|
|
}
|
|
|
|
return _Val;
|
|
}
|
|
|
|
// FUNCTION _Stofx_v2
|
|
inline float _Stofx_v2(const char* _Str, char** _Endptr, int _Pten, int* _Perr) { // 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;
|
|
|
|
if (_Pten != 0) {
|
|
_Val *= _CSTD powf(10.0f, static_cast<float>(_Pten));
|
|
}
|
|
|
|
return _Val;
|
|
}
|
|
|
|
// FUNCTION TEMPLATE _Find_elem
|
|
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>(_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;
|
|
}
|
|
|
|
// CLASS TEMPLATE numpunct
|
|
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, unsigned short>,
|
|
_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:
|
|
virtual __CLR_OR_THIS_CALL ~numpunct() noexcept {
|
|
_Tidy();
|
|
}
|
|
|
|
numpunct(const char* _Locname, size_t _Refs = 0, bool _Isdef = false) : locale::facet(_Refs) {
|
|
_BEGIN_LOCINFO(_Lobj(_Locname))
|
|
_Init(_Lobj, _Isdef);
|
|
_END_LOCINFO()
|
|
}
|
|
|
|
template <class _Elem2>
|
|
void _Getvals(_Elem2, const lconv* _Ptr, _Locinfo::_Cvtvec _Cvt) { // get values
|
|
_Dp = _Maklocchr(_Ptr->decimal_point[0], static_cast<_Elem2*>(nullptr), _Cvt);
|
|
_Kseparator = _Maklocchr(_Ptr->thousands_sep[0], static_cast<_Elem2*>(nullptr), _Cvt);
|
|
}
|
|
|
|
void _Getvals(wchar_t, const lconv* _Ptr, _Locinfo::_Cvtvec) { // get values
|
|
_Dp = static_cast<_Elem>(_Ptr->_W_decimal_point[0]);
|
|
_Kseparator = static_cast<_Elem>(_Ptr->_W_thousands_sep[0]);
|
|
}
|
|
|
|
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), _Lobj._Getcvt());
|
|
_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
|
|
// _Grouping = _Maklocstr("", static_cast<char *>(nullptr), _Cvt);
|
|
_Dp = _Maklocchr('.', static_cast<_Elem*>(nullptr), _Cvt);
|
|
_Kseparator = _Maklocchr(',', static_cast<_Elem*>(nullptr), _Cvt);
|
|
} else {
|
|
_Getvals(_Elem{}, _Ptr, _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
|
|
};
|
|
|
|
// CLASS TEMPLATE numpunct_byname
|
|
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:
|
|
virtual __CLR_OR_THIS_CALL ~numpunct_byname() noexcept {}
|
|
};
|
|
|
|
// STATIC numpunct::id OBJECT
|
|
#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 // __clang__
|
|
|
|
template <class _Elem>
|
|
__PURE_APPDOMAIN_GLOBAL locale::id numpunct<_Elem>::id;
|
|
|
|
#ifdef __clang__
|
|
#pragma clang diagnostic pop
|
|
#endif // __clang__
|
|
#endif // !defined(_CRTBLD) || defined(CRTDLL2) || !defined(_DLL) || defined(_M_CEE_PURE)
|
|
|
|
// CLASS TEMPLATE num_get
|
|
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, unsigned short>,
|
|
_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:
|
|
virtual __CLR_OR_THIS_CALL ~num_get() noexcept {}
|
|
|
|
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 int _Base = _Getifld(_Ac, _First, _Last, _Iosbase.flags(), _Iosbase.getloc()); // gather field
|
|
if (_Ac[0] == '\0') { // Handle N4727 [facet.num.get.virtuals]/3.6:
|
|
// "zero, if the conversion function does not convert the entire field."
|
|
// We should still do numeric conversion with bad digit separators, instead of
|
|
// setting 0, but we can't distinguish that from _Getifld's interface, and _Getifld's
|
|
// interface can't be changed as it is an exported function.
|
|
// TRANSITION, ABI: Fixing that when ABI allows is tracked by VSO-591516.
|
|
_Val = false;
|
|
_State = ios_base::failbit;
|
|
} else {
|
|
char* _Ep;
|
|
int _Errno;
|
|
const long _Ans = _CSTD _Stolx(_Ac, &_Ep, _Base, &_Errno); // convert
|
|
if (_Ep == _Ac || _Errno != 0) {
|
|
_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 int _Base = _Getifld(_Ac, _First, _Last, _Iosbase.flags(), _Iosbase.getloc()); // gather field
|
|
if (_Ac[0] == '\0') { // ditto "fails to convert the entire field" / VSO-591516
|
|
_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, _Base, &_Errno); // convert
|
|
_Val = static_cast<unsigned short>(_Tmp);
|
|
if (_Ep == _Digits || _Errno != 0 || _Tmp > USHRT_MAX) {
|
|
_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 (_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 int _Base = _Getifld(_Ac, _First, _Last, _Iosbase.flags(), _Iosbase.getloc()); // gather field
|
|
if (_Ac[0] == '\0') { // ditto "fails to convert the entire field" / VSO-591516
|
|
_State = ios_base::failbit;
|
|
_Val = 0;
|
|
} else {
|
|
char* _Ep;
|
|
int _Errno;
|
|
_Val = _CSTD _Stolx(_Ac, &_Ep, _Base, &_Errno); // convert
|
|
if (_Ep == _Ac || _Errno != 0) {
|
|
_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 int _Base = _Getifld(_Ac, _First, _Last, _Iosbase.flags(), _Iosbase.getloc()); // gather field
|
|
if (_Ac[0] == '\0') { // ditto "fails to convert the entire field" / VSO-591516
|
|
_State = ios_base::failbit;
|
|
_Val = 0;
|
|
} else {
|
|
char* _Ep;
|
|
int _Errno;
|
|
_Val = _CSTD _Stoulx(_Ac, &_Ep, _Base, &_Errno); // convert
|
|
if (_Ep == _Ac || _Errno != 0) {
|
|
_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 int _Base = _Getifld(_Ac, _First, _Last, _Iosbase.flags(), _Iosbase.getloc());
|
|
if (_Ac[0] == '\0') { // ditto "fails to convert the entire field" / VSO-591516
|
|
_State = ios_base::failbit;
|
|
_Val = 0;
|
|
} else {
|
|
char* _Ep;
|
|
int _Errno;
|
|
_Val = _CSTD _Stollx(_Ac, &_Ep, _Base, &_Errno); // convert
|
|
if (_Ep == _Ac || _Errno != 0) {
|
|
_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 int _Base = _Getifld(_Ac, _First, _Last, _Iosbase.flags(), _Iosbase.getloc());
|
|
if (_Ac[0] == '\0') { // ditto "fails to convert the entire field" / VSO-591516
|
|
_State = ios_base::failbit;
|
|
_Val = 0;
|
|
} else {
|
|
int _Errno;
|
|
char* _Ep;
|
|
_Val = _CSTD _Stoullx(_Ac, &_Ep, _Base, &_Errno); // convert
|
|
if (_Ep == _Ac || _Errno != 0) {
|
|
_State = ios_base::failbit;
|
|
}
|
|
}
|
|
|
|
if (_First == _Last) {
|
|
_State |= ios_base::eofbit;
|
|
}
|
|
|
|
return _First;
|
|
}
|
|
|
|
// TRANSITION, ABI: Sentinel value used by num_get::do_get()
|
|
// to enable correct "V2" behavior in _Getffld() and _Getffldx()
|
|
#define _ENABLE_V2_BEHAVIOR 1000000000
|
|
|
|
// 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];
|
|
int _Hexexp = _ENABLE_V2_BEHAVIOR;
|
|
const int _Base = _Getffld(_Ac, _First, _Last, _Iosbase, &_Hexexp); // gather field
|
|
if (_Ac[0] == '\0') { // ditto "fails to convert the entire field" / VSO-591516
|
|
_State = ios_base::failbit;
|
|
_Val = 0.0f;
|
|
} else {
|
|
int _Errno;
|
|
char* _Ep;
|
|
_Val = _Stofx_v2(_Ac, &_Ep, _Base, &_Errno); // convert
|
|
if (_Ep == _Ac || _Errno != 0) {
|
|
_State = ios_base::failbit;
|
|
_Val = 0.0f;
|
|
} else if (_Hexexp != _ENABLE_V2_BEHAVIOR && _Hexexp != 0) {
|
|
_Val = _CSTD ldexpf(_Val, 4 * _Hexexp);
|
|
}
|
|
}
|
|
|
|
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];
|
|
int _Hexexp = _ENABLE_V2_BEHAVIOR;
|
|
const int _Base = _Getffld(_Ac, _First, _Last, _Iosbase, &_Hexexp); // gather field
|
|
if (_Ac[0] == '\0') { // ditto "fails to convert the entire field" / VSO-591516
|
|
_State = ios_base::failbit;
|
|
_Val = 0.0;
|
|
} else {
|
|
int _Errno;
|
|
char* _Ep;
|
|
_Val = _Stodx_v2(_Ac, &_Ep, _Base, &_Errno); // convert
|
|
if (_Ep == _Ac || _Errno != 0) {
|
|
_State = ios_base::failbit;
|
|
_Val = 0.0;
|
|
} else if (_Hexexp != _ENABLE_V2_BEHAVIOR && _Hexexp != 0) {
|
|
_Val = _CSTD ldexp(_Val, 4 * _Hexexp);
|
|
}
|
|
}
|
|
|
|
if (_First == _Last) {
|
|
_State |= ios_base::eofbit;
|
|
}
|
|
|
|
return _First;
|
|
}
|
|
#undef _FLOATING_BUFFER_SIZE
|
|
|
|
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
|
|
static_assert(sizeof(double) == sizeof(long double), "Bad assumption: sizeof(double) == sizeof(long double).");
|
|
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 int _Base = _Getifld(_Ac, _First, _Last, ios_base::hex, _Iosbase.getloc()); // gather field
|
|
if (_Ac[0] == '\0') { // ditto "fails to convert the entire field" / VSO-591516
|
|
_State = ios_base::failbit;
|
|
_Val = nullptr;
|
|
} else {
|
|
int _Errno;
|
|
char* _Ep;
|
|
#ifdef _WIN64
|
|
_Val = reinterpret_cast<void*>(_CSTD _Stoullx(_Ac, &_Ep, _Base, &_Errno));
|
|
#else // ^^^ _WIN64 ^^^ // vvv !_WIN64 vvv
|
|
_Val = reinterpret_cast<void*>(_CSTD _Stoulx(_Ac, &_Ep, _Base, &_Errno));
|
|
#endif // _WIN64
|
|
if (_Ep == _Ac || _Errno != 0) {
|
|
_State = ios_base::failbit;
|
|
_Val = nullptr;
|
|
}
|
|
}
|
|
|
|
if (_First == _Last) {
|
|
_State |= ios_base::eofbit;
|
|
}
|
|
|
|
return _First;
|
|
}
|
|
|
|
private:
|
|
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
|
|
const auto& _Punct_fac = _STD use_facet<numpunct<_Elem>>(_Loc);
|
|
const string _Grouping = _Punct_fac.grouping();
|
|
const _Elem _Kseparator = _Grouping.size() == 0 ? _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);
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
_Basefield &= ios_base::basefield;
|
|
|
|
int _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));
|
|
size_t _Group = 0;
|
|
|
|
for (char* const _Pe = &_Ac[_MAX_INT_DIG - 1]; _First != _Last; ++_First) { // look for digits and separators
|
|
size_t _Idx = _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[_Group] != CHAR_MAX) {
|
|
++_Groups[_Group];
|
|
}
|
|
} else if (_Groups[_Group] == '\0' || _Kseparator == _Elem{} || *_First != _Kseparator) {
|
|
break; // not a group separator, done
|
|
} else { // add a new group to _Groups string
|
|
_Groups.push_back('\0');
|
|
++_Group;
|
|
}
|
|
}
|
|
|
|
if (_Group != 0) {
|
|
if ('\0' < _Groups[_Group]) {
|
|
++_Group; // add trailing group to group count
|
|
} else {
|
|
_Seendigit = false; // trailing separator, fail
|
|
}
|
|
}
|
|
|
|
for (const char* _Pg = &_Grouping[0]; _Seendigit && 0 < _Group;) {
|
|
if (*_Pg == CHAR_MAX) {
|
|
break; // end of grouping constraints to check
|
|
} else if ((0 < --_Group && *_Pg != _Groups[_Group]) || (0 == _Group && *_Pg < _Groups[_Group])) {
|
|
_Seendigit = false; // bad group size, fail
|
|
} else if ('\0' < _Pg[1]) {
|
|
++_Pg; // group size okay, advance to next test
|
|
}
|
|
}
|
|
|
|
if (_Seendigit && !_Nonzero) {
|
|
*_Ptr++ = '0'; // zero field, replace stripped zero(s)
|
|
} else if (!_Seendigit) {
|
|
_Ptr = _Ac; // roll back pointer to indicate failure
|
|
}
|
|
|
|
*_Ptr = '\0';
|
|
return _Base;
|
|
}
|
|
|
|
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
|
|
if ((_Iosbase.flags() & ios_base::floatfield) == ios_base::hexfloat) {
|
|
return _Getffldx(_Ac, _First, _Last, _Iosbase, _Phexexp); // hex format
|
|
}
|
|
|
|
const auto& _Punct_fac = _STD use_facet<numpunct<_Elem>>(_Iosbase.getloc());
|
|
const string _Grouping = _Punct_fac.grouping();
|
|
char* _Ptr = _Ac;
|
|
bool _Bad = false;
|
|
bool _Sticky = false;
|
|
|
|
constexpr int _Numget_signoff = 10;
|
|
constexpr int _Numget_eoff = 12;
|
|
static constexpr char _Src[] = "0123456789-+Ee";
|
|
_Elem _Atoms[sizeof(_Src)];
|
|
const ctype<_Elem>& _Ctype_fac = _STD use_facet<ctype<_Elem>>(_Iosbase.getloc());
|
|
_Ctype_fac.widen(_STD begin(_Src), _STD end(_Src), _Atoms);
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
char* _Leading = _Ptr; // remember backstop
|
|
*_Ptr++ = '0'; // backstop carries from sticky bit
|
|
|
|
bool _Seendigit = false; // seen a digit in input
|
|
int _Significant = 0; // number of significant digits
|
|
int _Pten = 0; // power of 10 multiplier
|
|
size_t _Idx;
|
|
|
|
const int _Max_sig_dig = (*_Phexexp == _ENABLE_V2_BEHAVIOR ? _MAX_SIG_DIG_V2 : _MAX_SIG_DIG_V1);
|
|
|
|
const char* _Pg = &_Grouping[0];
|
|
if (*_Pg == CHAR_MAX || *_Pg <= '\0') {
|
|
for (; _First != _Last && (_Idx = _Find_elem(_Atoms, *_First)) < 10; _Seendigit = true, (void) ++_First) {
|
|
if (_Max_sig_dig <= _Significant) { // enough digits, scale by 10 and update _Sticky
|
|
++_Pten;
|
|
if (0 < _Idx) {
|
|
_Sticky = true;
|
|
}
|
|
} else if (_Idx != 0 || _Significant != 0) { // save a significant digit
|
|
*_Ptr++ = _Src[_Idx];
|
|
++_Significant;
|
|
}
|
|
}
|
|
} else { // grouping specified, gather digits and group sizes
|
|
const _Elem _Kseparator = _Grouping.size() == 0 ? _Elem{} : _Punct_fac.thousands_sep();
|
|
string _Groups(1, '\0');
|
|
size_t _Group = 0;
|
|
|
|
for (; _First != _Last; ++_First) {
|
|
if ((_Idx = _Find_elem(_Atoms, *_First)) < 10) { // got a digit, add to group size
|
|
_Seendigit = true;
|
|
if (_Max_sig_dig <= _Significant) { // enough digits, scale by 10 and update _Sticky
|
|
++_Pten;
|
|
if (0 < _Idx) {
|
|
_Sticky = true;
|
|
}
|
|
} else if (_Idx != 0 || _Significant != 0) { // save a significant digit
|
|
*_Ptr++ = _Src[_Idx];
|
|
++_Significant;
|
|
}
|
|
|
|
if (_Groups[_Group] != CHAR_MAX) {
|
|
++_Groups[_Group];
|
|
}
|
|
} else if (_Groups[_Group] == '\0' || _Kseparator == _Elem{} || *_First != _Kseparator) {
|
|
break; // not a group separator, done
|
|
} else { // add a new group to _Groups string
|
|
_Groups.push_back('\0');
|
|
++_Group;
|
|
}
|
|
}
|
|
|
|
if (_Group != 0) {
|
|
if ('\0' < _Groups[_Group]) {
|
|
++_Group; // add trailing group to group count
|
|
} else {
|
|
_Bad = true; // trailing separator, fail
|
|
}
|
|
}
|
|
|
|
while (!_Bad && 0 < _Group) {
|
|
if (*_Pg == CHAR_MAX) {
|
|
break; // end of grouping constraints to check
|
|
}
|
|
|
|
if ((0 < --_Group && *_Pg != _Groups[_Group]) || (0 == _Group && *_Pg < _Groups[_Group])) {
|
|
_Bad = true; // bad group size, fail
|
|
} else if ('\0' < _Pg[1]) {
|
|
++_Pg; // group size okay, advance to next test
|
|
}
|
|
}
|
|
}
|
|
|
|
if (_First != _Last && *_First == _Punct_fac.decimal_point()) { // add .
|
|
*_Ptr++ = localeconv()->decimal_point[0];
|
|
++_First;
|
|
}
|
|
|
|
if (*_Phexexp != _ENABLE_V2_BEHAVIOR && _Significant == 0) { // 0000. so far
|
|
for (; _First != _Last && *_First == _Atoms[0]; _Seendigit = true, (void) ++_First) {
|
|
--_Pten; // just count leading fraction zeros
|
|
}
|
|
|
|
if (_Pten < 0) { // put one back
|
|
*_Ptr++ = '0';
|
|
++_Pten;
|
|
}
|
|
}
|
|
|
|
for (; _First != _Last && (_Idx = _Find_elem(_Atoms, *_First)) < 10; _Seendigit = true, (void) ++_First) {
|
|
if (_Significant < _Max_sig_dig) { // save a significant fraction digit
|
|
*_Ptr++ = _Src[_Idx];
|
|
++_Significant;
|
|
} else if (0 < _Idx) {
|
|
_Sticky = true; // just update _Sticky
|
|
}
|
|
}
|
|
|
|
if (_Sticky) { // increment ls digit in memory of those lost
|
|
char* _Px = _Ptr;
|
|
while (--_Px != _Leading) { // add in carry
|
|
if (*_Px != localeconv()->decimal_point[0]) { // not decimal point
|
|
if (*_Px != '9') { // carry stops here
|
|
++*_Px;
|
|
break;
|
|
}
|
|
|
|
*_Px = '0'; // propagate carry
|
|
}
|
|
}
|
|
|
|
if (_Px == _Leading) { // change "999..." to "1000..." and scale _Pten
|
|
*_Px = '1';
|
|
++_Pten;
|
|
}
|
|
}
|
|
|
|
if (_Seendigit && _First != _Last
|
|
&& (*_First == _Atoms[_Numget_eoff + 1]
|
|
|| *_First == _Atoms[_Numget_eoff])) { // 'e' or 'E', collect exponent
|
|
*_Ptr++ = 'e';
|
|
++_First;
|
|
_Seendigit = false;
|
|
_Significant = 0;
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
for (; _First != _Last && *_First == _Atoms[0]; ++_First) { // strip leading zeros
|
|
_Seendigit = true;
|
|
}
|
|
|
|
if (_Seendigit) {
|
|
*_Ptr++ = '0'; // put one back
|
|
}
|
|
|
|
for (; _First != _Last && (_Idx = _Find_elem(_Atoms, *_First)) < 10; _Seendigit = true, (void) ++_First) {
|
|
if (_Significant < _MAX_EXP_DIG) { // save a significant exponent digit
|
|
*_Ptr++ = _Src[_Idx];
|
|
++_Significant;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (_Bad || !_Seendigit) {
|
|
_Ptr = _Ac; // roll back pointer to indicate failure
|
|
}
|
|
|
|
*_Ptr = '\0';
|
|
return _Pten;
|
|
}
|
|
|
|
int __CLRCALL_OR_CDECL _Getffldx(char* _Ac, _InIt& _First, _InIt& _Last, ios_base& _Iosbase,
|
|
int* _Phexexp) const { // get hex floating-point field from [_First, _Last) into _Ac
|
|
const auto& _Punct_fac = _STD use_facet<numpunct<_Elem>>(_Iosbase.getloc());
|
|
const string _Grouping = _Punct_fac.grouping();
|
|
|
|
constexpr int _Numget_signoff = 22;
|
|
constexpr int _Numget_xoff = 24;
|
|
constexpr int _Numget_poff = 26;
|
|
static constexpr char _Src[] = "0123456789ABCDEFabcdef-+XxPp";
|
|
_Elem _Atoms[sizeof(_Src)];
|
|
const ctype<_Elem>& _Ctype_fac = _STD use_facet<ctype<_Elem>>(_Iosbase.getloc());
|
|
_Ctype_fac.widen(_STD begin(_Src), _STD end(_Src), _Atoms);
|
|
|
|
char* _Ptr = _Ac;
|
|
bool _Bad = false;
|
|
size_t _Idx;
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
*_Ptr++ = '0';
|
|
*_Ptr++ = 'x';
|
|
|
|
bool _Seendigit = false; // seen a digit in input
|
|
int _Significant = 0; // number of significant digits
|
|
int _Phex = 0; // power of 10 multiplier
|
|
|
|
if (_First != _Last && *_First == _Atoms[0]) {
|
|
if (++_First != _Last && (*_First == _Atoms[_Numget_xoff + 1] || *_First == _Atoms[_Numget_xoff])) {
|
|
++_First; // discard any 0x or 0X
|
|
} else {
|
|
_Seendigit = true; // '0' not followed by 'x' or 'X'
|
|
}
|
|
}
|
|
|
|
const int _Max_sig_dig = (*_Phexexp == _ENABLE_V2_BEHAVIOR ? _MAX_SIG_DIG_V2 : _MAX_SIG_DIG_V1);
|
|
|
|
const char* _Pg = &_Grouping[0];
|
|
if (*_Pg == CHAR_MAX || *_Pg <= '\0') {
|
|
for (; _First != _Last && (_Idx = _Find_elem(_Atoms, *_First)) < _Numget_signoff;
|
|
_Seendigit = true, (void) ++_First) {
|
|
if (_Max_sig_dig <= _Significant) {
|
|
++_Phex; // just scale by 10
|
|
} else if (_Idx != 0 || _Significant != 0) { // save a significant digit
|
|
*_Ptr++ = _Src[_Idx];
|
|
++_Significant;
|
|
}
|
|
}
|
|
} else { // grouping specified, gather digits and group sizes
|
|
const _Elem _Kseparator = _Grouping.size() == 0 ? _Elem{} : _Punct_fac.thousands_sep();
|
|
string _Groups(1, '\0');
|
|
size_t _Group = 0;
|
|
|
|
for (; _First != _Last; ++_First) {
|
|
if ((_Idx = _Find_elem(_Atoms, *_First)) < _Numget_signoff) { // got a digit, add to group size
|
|
_Seendigit = true;
|
|
if (_Max_sig_dig <= _Significant) {
|
|
++_Phex; // just scale by 10
|
|
} else if (_Idx != 0 || _Significant != 0) { // save a significant digit
|
|
*_Ptr++ = _Src[_Idx];
|
|
++_Significant;
|
|
}
|
|
|
|
if (_Groups[_Group] != CHAR_MAX) {
|
|
++_Groups[_Group];
|
|
}
|
|
} else if (_Groups[_Group] == '\0' || _Kseparator == _Elem{} || *_First != _Kseparator) {
|
|
break; // not a group separator, done
|
|
} else { // add a new group to _Groups string
|
|
_Groups.push_back('\0');
|
|
++_Group;
|
|
}
|
|
}
|
|
|
|
if (_Group != 0) {
|
|
if ('\0' < _Groups[_Group]) {
|
|
++_Group; // add trailing group to group count
|
|
} else {
|
|
_Bad = true; // trailing separator, fail
|
|
}
|
|
}
|
|
|
|
while (!_Bad && 0 < _Group) {
|
|
if (*_Pg == CHAR_MAX) {
|
|
break; // end of grouping constraints to check
|
|
}
|
|
|
|
if ((0 < --_Group && *_Pg != _Groups[_Group]) || (0 == _Group && *_Pg < _Groups[_Group])) {
|
|
_Bad = true; // bad group size, fail
|
|
} else if ('\0' < _Pg[1]) {
|
|
++_Pg; // group size okay, advance to next test
|
|
}
|
|
}
|
|
}
|
|
|
|
if (_Seendigit && _Significant == 0) {
|
|
*_Ptr++ = '0'; // save at least one leading digit
|
|
}
|
|
|
|
if (_First != _Last && *_First == _Punct_fac.decimal_point()) { // add .
|
|
*_Ptr++ = localeconv()->decimal_point[0];
|
|
++_First;
|
|
}
|
|
|
|
if (_Significant == 0) { // 0000. so far
|
|
for (; _First != _Last && *_First == _Atoms[0]; _Seendigit = true, (void) ++_First) {
|
|
--_Phex; // just count leading fraction zeros
|
|
}
|
|
|
|
if (_Phex < 0) { // put one back
|
|
*_Ptr++ = '0';
|
|
++_Phex;
|
|
}
|
|
}
|
|
|
|
for (; _First != _Last && (_Idx = _Find_elem(_Atoms, *_First)) < _Numget_signoff;
|
|
_Seendigit = true, (void) ++_First) {
|
|
if (_Significant < _Max_sig_dig) { // save a significant fraction digit
|
|
*_Ptr++ = _Src[_Idx];
|
|
++_Significant;
|
|
}
|
|
}
|
|
|
|
if (_Seendigit && _First != _Last
|
|
&& (*_First == _Atoms[_Numget_poff + 1]
|
|
|| *_First == _Atoms[_Numget_poff])) { // 'p' or 'P', collect exponent
|
|
*_Ptr++ = 'p';
|
|
++_First;
|
|
_Seendigit = false;
|
|
_Significant = 0;
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
for (; _First != _Last && *_First == _Atoms[0]; ++_First) { // strip leading zeros
|
|
_Seendigit = true;
|
|
}
|
|
|
|
if (_Seendigit) {
|
|
*_Ptr++ = '0'; // put one back
|
|
}
|
|
|
|
for (; _First != _Last && (_Idx = _Find_elem(_Atoms, *_First)) < _Numget_signoff;
|
|
_Seendigit = true, (void) ++_First) {
|
|
if (_Significant < _MAX_EXP_DIG) { // save a significant exponent digit
|
|
*_Ptr++ = _Src[_Idx];
|
|
++_Significant;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (_Bad || !_Seendigit) {
|
|
_Ptr = _Ac; // roll back pointer to indicate failure
|
|
}
|
|
|
|
*_Ptr = '\0';
|
|
*_Phexexp = _Phex; // power of 16 multiplier
|
|
return 0; // power of 10 multiplier
|
|
}
|
|
|
|
#undef _ENABLE_V2_BEHAVIOR
|
|
};
|
|
|
|
// STATIC num_get::id OBJECT
|
|
#ifdef __clang__
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wdllimport-static-field-def"
|
|
#endif // __clang__
|
|
|
|
template <class _Elem, class _InIt>
|
|
__PURE_APPDOMAIN_GLOBAL locale::id num_get<_Elem, _InIt>::id;
|
|
|
|
#ifdef __clang__
|
|
#pragma clang diagnostic pop
|
|
#endif // __clang__
|
|
|
|
// STRUCT TEMPLATE _Hex_float_precision
|
|
template <class _Ty>
|
|
struct _Hex_float_precision;
|
|
|
|
template <>
|
|
struct _Hex_float_precision<double> {
|
|
// the number of hexits needed to represent (DBL_MANT_DIG - 1) bits after the radix point exactly
|
|
static constexpr int value = ((DBL_MANT_DIG - 1) + 3) / 4;
|
|
};
|
|
|
|
template <>
|
|
struct _Hex_float_precision<long double> {
|
|
// the number of hexits needed to represent (LDBL_MANT_DIG - 1) bits after the radix point exactly
|
|
static constexpr int value = ((LDBL_MANT_DIG - 1) + 3) / 4;
|
|
};
|
|
|
|
// FUNCTION TEMPLATE _Float_put_desired_precision
|
|
template <class _Ty>
|
|
int _Float_put_desired_precision(const streamsize _Precision, const ios_base::fmtflags _Float_flags) {
|
|
const bool _Is_hex = _Float_flags == (ios_base::fixed | ios_base::scientific);
|
|
if (_Is_hex) {
|
|
return _Hex_float_precision<_Ty>::value;
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
// CLASS TEMPLATE num_put
|
|
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, unsigned short>,
|
|
_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:
|
|
virtual __CLR_OR_THIS_CALL ~num_put() noexcept {}
|
|
|
|
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 auto _Ngen = static_cast<size_t>(_CSTD sprintf_s(
|
|
&_Buf[0], _Buf.size(), _Ffmt(_Fmt, 0, _Iosbase.flags()), static_cast<int>(_Precision), _Val));
|
|
|
|
return _Fput(_Dest, _Iosbase, _Fill, _Buf.c_str(), _Ngen);
|
|
}
|
|
|
|
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 auto _Ngen = static_cast<size_t>(_CSTD sprintf_s(
|
|
&_Buf[0], _Buf.size(), _Ffmt(_Fmt, 'L', _Iosbase.flags()), static_cast<int>(_Precision), _Val));
|
|
|
|
return _Fput(_Dest, _Iosbase, _Fill, _Buf.c_str(), _Ngen);
|
|
}
|
|
#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::hexfloat) {
|
|
_Ch = 'A'; // added with TR1
|
|
} else if (_Ffl == ios_base::scientific) {
|
|
_Ch = 'E';
|
|
} else {
|
|
_Ch = 'G';
|
|
}
|
|
} else {
|
|
if (_Ffl == ios_base::fixed) {
|
|
_Ch = 'f';
|
|
} else if (_Ffl == ios_base::hexfloat) {
|
|
_Ch = 'a'; // added with TR1
|
|
} 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 { // 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::hexfloat) {
|
|
_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();
|
|
}
|
|
|
|
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;
|
|
}
|
|
};
|
|
|
|
// STATIC num_put::id OBJECT
|
|
#ifdef __clang__
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wdllimport-static-field-def"
|
|
#endif // __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 // __FORCE_INSTANCE
|
|
#endif // defined(_DLL_CPPLIB)
|
|
|
|
#ifdef __clang__
|
|
#pragma clang diagnostic pop
|
|
#endif // __clang__
|
|
_STD_END
|
|
#pragma pop_macro("new")
|
|
_STL_RESTORE_CLANG_WARNINGS
|
|
#pragma warning(pop)
|
|
#pragma pack(pop)
|
|
#endif // _STL_COMPILER_PREPROCESSOR
|
|
#endif // _XLOCNUM_
|