STL/stl/inc/xlocmon

922 строки
36 KiB
C++

// xlocmon internal header
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#ifndef _XLOCMON_
#define _XLOCMON_
#include <yvals_core.h>
#if _STL_COMPILER_PREPROCESSOR
#include <iterator>
#include <xlocnum>
#pragma pack(push, _CRT_PACKING)
#pragma warning(push, _STL_WARNING_LEVEL)
#pragma warning(disable : _STL_DISABLED_WARNINGS)
_STL_DISABLE_CLANG_WARNINGS
#pragma push_macro("new")
#undef new
_STD_BEGIN
_EXPORT_STD struct money_base // ultimate base class for moneypunct
: locale::facet // TRANSITION, ABI, shouldn't be derived from locale::facet
{
enum { // constants for different format codes
symbol = '$',
sign = '+',
space = ' ',
value = 'v',
none = 'x'
};
using part = int;
struct pattern { // four-part formats for monetary text
char field[4];
};
money_base(size_t _Refs = 0) noexcept // strengthened
: locale::facet(_Refs) {}
};
template <class _Elem>
class _Mpunct : public money_base { // common base class for moneypunct<_Elem, false/true>
public:
friend _Tidy_guard<_Mpunct>;
using char_type = _Elem;
using string_type = basic_string<_Elem, char_traits<_Elem>, allocator<_Elem>>;
_Elem decimal_point() const {
return do_decimal_point();
}
_Elem thousands_sep() const {
return do_thousands_sep();
}
string grouping() const {
return do_grouping();
}
string_type curr_symbol() const {
return do_curr_symbol();
}
string_type positive_sign() const {
return do_positive_sign();
}
string_type negative_sign() const {
return do_negative_sign();
}
int frac_digits() const {
return do_frac_digits();
}
pattern pos_format() const {
return do_pos_format();
}
pattern neg_format() const {
return do_neg_format();
}
explicit _Mpunct(size_t _Refs, bool _Intl)
: money_base(_Refs), _International(_Intl) { // construct from current locale
_BEGIN_LOCINFO(_Lobj)
_Init(_Lobj);
_END_LOCINFO()
}
_Mpunct(const _Locinfo& _Lobj, size_t _Refs, bool _Intl, bool _Isdef = false)
: money_base(_Refs), _International(_Intl) {
_Init(_Lobj, _Isdef);
}
protected:
_Mpunct(const char* _Locname, size_t _Refs, bool _Intl, bool _Isdef = false)
: money_base(_Refs), _International(_Intl) {
_BEGIN_LOCINFO(_Lobj(_Locname))
_Init(_Lobj, _Isdef);
_END_LOCINFO()
}
__CLR_OR_THIS_CALL ~_Mpunct() noexcept override {
_Tidy();
}
template <class _Elem2>
void _Getvals(_Elem2, const lconv* _Ptr) { // get values
_Currencysign = _Maklocstr(
_International ? _Ptr->int_curr_symbol : _Ptr->currency_symbol, static_cast<_Elem2*>(nullptr), _Cvt);
_Plussign = _Maklocstr(4 < static_cast<unsigned int>(_Ptr->p_sign_posn) ? "" : _Ptr->positive_sign,
static_cast<_Elem2*>(nullptr), _Cvt);
_Minussign = _Maklocstr(4 < static_cast<unsigned int>(_Ptr->n_sign_posn) ? "-" : _Ptr->negative_sign,
static_cast<_Elem2*>(nullptr), _Cvt);
_Decimalpoint = _Maklocchr(_Ptr->mon_decimal_point[0], static_cast<_Elem2*>(nullptr), _Cvt);
_Kseparator = _Maklocchr(_Ptr->mon_thousands_sep[0], static_cast<_Elem2*>(nullptr), _Cvt);
}
void _Getvals(wchar_t, const lconv* _Ptr) { // get values
_Currencysign = reinterpret_cast<const _Elem*>(
_Maklocwcs(_International ? _Ptr->_W_int_curr_symbol : _Ptr->_W_currency_symbol));
_Plussign = reinterpret_cast<const _Elem*>(
_Maklocwcs(4 < static_cast<unsigned int>(_Ptr->p_sign_posn) ? L"" : _Ptr->_W_positive_sign));
_Minussign = reinterpret_cast<const _Elem*>(
_Maklocwcs(4 < static_cast<unsigned int>(_Ptr->n_sign_posn) ? L"-" : _Ptr->_W_negative_sign));
_Decimalpoint = static_cast<_Elem>(_Ptr->_W_mon_decimal_point[0]);
_Kseparator = static_cast<_Elem>(_Ptr->_W_mon_thousands_sep[0]);
}
void _Init(const _Locinfo& _Lobj, bool _Isdef = false) { // initialize from _Lobj
_Cvt = _Lobj._Getcvt();
const lconv* _Ptr = _Lobj._Getlconv();
_Grouping = nullptr;
_Currencysign = nullptr;
_Plussign = nullptr;
_Minussign = nullptr;
_Tidy_guard<_Mpunct> _Guard{this};
_Grouping = _Maklocstr(_Ptr->mon_grouping, static_cast<char*>(nullptr), _Cvt);
_Getvals(_Elem{}, _Ptr);
_Guard._Target = nullptr;
_Fracdigits = _International ? _Ptr->int_frac_digits : _Ptr->frac_digits;
if (_Fracdigits < 0 || CHAR_MAX <= _Fracdigits) {
_Fracdigits = 0;
}
_Makpat(_Plusformat, static_cast<unsigned int>(_Ptr->p_sep_by_space),
static_cast<unsigned int>(_Ptr->p_cs_precedes), static_cast<unsigned int>(_Ptr->p_sign_posn));
_Makpat(_Minusformat, static_cast<unsigned int>(_Ptr->n_sep_by_space),
static_cast<unsigned int>(_Ptr->n_cs_precedes), static_cast<unsigned int>(_Ptr->n_sign_posn));
if (_Isdef) { // apply defaults for required facets
_CSTD memcpy(&_Plusformat, "$+xv", 4);
_CSTD memcpy(&_Minusformat, "$+xv", 4);
}
}
virtual _Elem __CLR_OR_THIS_CALL do_decimal_point() const {
return _Decimalpoint;
}
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_curr_symbol() const {
return string_type{_Currencysign};
}
virtual string_type __CLR_OR_THIS_CALL do_positive_sign() const {
return string_type{_Plussign};
}
virtual string_type __CLR_OR_THIS_CALL do_negative_sign() const {
return string_type{_Minussign};
}
virtual int __CLR_OR_THIS_CALL do_frac_digits() const {
return _Fracdigits;
}
virtual pattern __CLR_OR_THIS_CALL do_pos_format() const {
return _Plusformat;
}
virtual pattern __CLR_OR_THIS_CALL do_neg_format() const {
return _Minusformat;
}
private:
void _Makpat(pattern& _Pattern, unsigned int _Sepbyspace, unsigned int _Symbolprecedes,
unsigned int _Signposition) { // make format pattern from locale information
const char* _Ptr;
if (_International || 2 < _Sepbyspace || 1 < _Symbolprecedes || 4 < _Signposition) {
// international or bad parameters
_Ptr = "$+xv";
} else {
// clang-format off
_Ptr =
"+v$x" "+v$x" "v$+x" "v+$x" "v$+x"
"+$vx" "+$vx" "$v+x" "+$vx" "$+vx"
"+v $" "+v $" "v $+" "v +$" "v $+"
"+$ v" "+$ v" "$ v+" "+$ v" "$+ v"
"+xv$" "+ v$" "v$ +" "v+ $" "v$ +"
"+x$v" "+ $v" "$v +" "+ $v" "$ +v";
// clang-format on
_Ptr += _Signposition * 4 // pick even/odd column
+ _Symbolprecedes * 20 // pick even/odd row
+ _Sepbyspace * 40; // pick first/second/third group
}
_CSTD memcpy(_Pattern.field, _Ptr, sizeof(_Pattern.field));
}
void _Tidy() noexcept { // free all storage
_CSTD free(const_cast<char*>(_Grouping));
_CSTD free(const_cast<_Elem*>(_Currencysign));
_CSTD free(const_cast<_Elem*>(_Plussign));
_CSTD free(const_cast<_Elem*>(_Minussign));
}
const char* _Grouping; // grouping string, "" for "C" locale
_Elem _Decimalpoint; // decimal point, '\0' for "C" locale
_Elem _Kseparator; // thousands separator, '\0' for "C" locale
const _Elem* _Currencysign; // currency symbol, "" for "C" locale
const _Elem* _Plussign; // plus sign, "" for "C" locale
const _Elem* _Minussign; // minus sign, "-" for "C" locale
int _Fracdigits; // number of fraction digits, 0 for "C" locale
pattern _Plusformat; // positive format, "$+vx" for "C" locale
pattern _Minusformat; // negative format, "$+vx" for "C" locale
bool _International; // true if international format
_Locinfo::_Cvtvec _Cvt; // conversion information
};
_EXPORT_STD template <class _Elem, bool _Intl = false>
class moneypunct : public _Mpunct<_Elem> { // facet for defining monetary punctuation text
public:
static_assert(!_ENFORCE_FACET_SPECIALIZATIONS || _Is_any_of_v<_Elem, char, wchar_t>, _FACET_SPECIALIZATION_MESSAGE);
_PGLOBAL _CRTIMP2_PURE_IMPORT static const bool intl; // true if international
__PURE_APPDOMAIN_GLOBAL _CRTIMP2_PURE_IMPORT static locale::id id; // unique facet id
explicit moneypunct(size_t _Refs = 0) : _Mpunct<_Elem>(_Refs, _Intl) {} // construct from current locale
moneypunct(const _Locinfo& _Lobj, size_t _Refs = 0, bool _Isdef = false)
: _Mpunct<_Elem>(_Lobj, _Refs, _Intl, _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 moneypunct<_Elem, _Intl>(_Locinfo(_Ploc->_C_str()), 0, true);
}
return _X_MONETARY;
}
protected:
moneypunct(const char* _Locname, size_t _Refs = 0) : _Mpunct<_Elem>(_Locname, _Refs, _Intl) {}
__CLR_OR_THIS_CALL ~moneypunct() noexcept override {}
};
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdllimport-static-field-def"
#endif // defined(__clang__)
template <class _Elem, bool _Intl>
_PGLOBAL const bool moneypunct<_Elem, _Intl>::intl = _Intl;
template <class _Elem, bool _Intl>
__PURE_APPDOMAIN_GLOBAL locale::id moneypunct<_Elem, _Intl>::id;
#ifdef __clang__
#pragma clang diagnostic pop
#endif // defined(__clang__)
_EXPORT_STD template <class _Elem, bool _Intl = false>
class moneypunct_byname : public moneypunct<_Elem, _Intl> { // moneypunct for named locale
public:
static_assert(!_ENFORCE_FACET_SPECIALIZATIONS || _Is_any_of_v<_Elem, char, wchar_t>, _FACET_SPECIALIZATION_MESSAGE);
explicit moneypunct_byname(const char* _Locname, size_t _Refs = 0)
: moneypunct<_Elem, _Intl>(_Locname, _Refs) {} // construct for named locale
explicit moneypunct_byname(const string& _Str, size_t _Refs = 0)
: moneypunct<_Elem, _Intl>(_Str.c_str(), _Refs) {} // construct for named locale
protected:
__CLR_OR_THIS_CALL ~moneypunct_byname() noexcept override {}
};
_EXPORT_STD template <class _Elem, class _InIt = istreambuf_iterator<_Elem, char_traits<_Elem>>>
class money_get : public locale::facet { // facet for converting text to encoded monetary amounts
private:
using _Mypunct0 = moneypunct<_Elem, false>;
using _Mypunct1 = moneypunct<_Elem, true>;
public:
static_assert(!_ENFORCE_FACET_SPECIALIZATIONS || _Is_any_of_v<_Elem, char, wchar_t>, _FACET_SPECIALIZATION_MESSAGE);
using char_type = _Elem;
using iter_type = _InIt;
using string_type = basic_string<_Elem, char_traits<_Elem>, allocator<_Elem>>;
_InIt get(_InIt _First, _InIt _Last, bool _Intl, ios_base& _Iosbase, ios_base::iostate& _State,
long double& _Val) const { // get long double from [_First, _Last) into _Val
return do_get(_First, _Last, _Intl, _Iosbase, _State, _Val);
}
_InIt get(_InIt _First, _InIt _Last, bool _Intl, ios_base& _Iosbase, ios_base::iostate& _State,
string_type& _Val) const { // get string_type from [_First, _Last) into _Val
return do_get(_First, _Last, _Intl, _Iosbase, _State, _Val);
}
__PURE_APPDOMAIN_GLOBAL _CRTIMP2_PURE_IMPORT static locale::id id; // unique facet id
explicit money_get(size_t _Refs = 0) : locale::facet(_Refs) { // construct from current locale
_BEGIN_LOCINFO(_Lobj)
_Init(_Lobj);
_END_LOCINFO()
}
money_get(const _Locinfo& _Lobj, size_t _Refs = 0) : locale::facet(_Refs) {
_Init(_Lobj);
}
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 money_get<_Elem, _InIt>(_Locinfo(_Ploc->_C_str()));
}
return _X_MONETARY;
}
protected:
__CLR_OR_THIS_CALL ~money_get() noexcept override {}
void _Init(const _Locinfo&) {} // initialize from _Locinfo object
virtual _InIt __CLR_OR_THIS_CALL do_get(_InIt _First, _InIt _Last, bool _Intl, ios_base& _Iosbase,
ios_base::iostate& _State,
long double& _Val) const { // get long double from [_First, _Last) into _Val
_Elem _Atoms[sizeof("0123456789-")];
string _Str = _Getmfld(_First, _Last, _Intl, _Iosbase, _Atoms);
if (_First == _Last) {
_State |= ios_base::eofbit;
}
if (_Str.empty()) {
_State |= ios_base::failbit; // _Getmfld failed
} else { // convert to long double
const char* _Eb = _Str.c_str();
char* _Ep;
int _Errno = 0;
const long double _Ans = _Stodx_v3(_Eb, &_Ep, &_Errno); // convert and "widen" double to long double
if (_Ep == _Eb || _Errno != 0) {
_State |= ios_base::failbit;
} else {
_Val = _Ans; // deliver value
}
}
return _First;
}
virtual _InIt __CLR_OR_THIS_CALL do_get(_InIt _First, _InIt _Last, bool _Intl, ios_base& _Iosbase,
ios_base::iostate& _State,
string_type& _Val) const { // get string_type from [_First, _Last) into _Val
_Elem _Atoms[sizeof("0123456789-")];
string _Str = _Getmfld(_First, _Last, _Intl, _Iosbase, _Atoms);
size_t _Len = _Str.size();
if (_First == _Last) {
_State |= ios_base::eofbit;
}
if (_Len == 0) {
_State |= ios_base::failbit; // _Getmfld failed
} else { // deliver value
size_t _Idx = 0;
_Val.resize(_Len);
if (_Str[0] == '-') {
_Val[_Idx++] = _Atoms[10];
}
for (; _Idx < _Len; ++_Idx) {
_Val[_Idx] = _Atoms[_Str[_Idx] - '0']; // map digits
}
}
return _First;
}
private:
string _Getmfld(_InIt& _First, _InIt& _Last, bool _Intl, ios_base& _Iosbase,
_Elem (&_Atoms)[12]) const { // get monetary field from [_First, _Last) into string_type
_Adl_verify_range(_First, _Last);
const _Mpunct<_Elem>* _Ppunct_fac;
if (_Intl) {
_Ppunct_fac = _STD addressof(_STD use_facet<_Mypunct1>(_Iosbase.getloc())); // international
} else {
_Ppunct_fac = _STD addressof(_STD use_facet<_Mypunct0>(_Iosbase.getloc())); // local
}
bool _Bad = false;
bool _Neg = false;
string_type _Sign;
const money_base::pattern _Pattern = _Ppunct_fac->neg_format();
string _Val;
size_t _Idx;
static constexpr char _Src[] = "0123456789-";
const ctype<_Elem>& _Ctype_fac = _STD use_facet<ctype<_Elem>>(_Iosbase.getloc());
_Ctype_fac.widen(_STD begin(_Src), _STD end(_Src), _Atoms);
for (size_t _Off = 0; !_Bad && _Off < 4; ++_Off) {
switch (_Pattern.field[_Off]) { // parse a format component
case money_base::symbol:
{ // parse currency symbol
string_type _Symbol = _Ppunct_fac->curr_symbol();
typename string_type::const_iterator _Source;
if ((!(_Iosbase.flags() & ios_base::showbase) && _First != _Last && *_First != *_Symbol.c_str())
|| (_Off == 3 && _Sign.size() <= 1
&& (_First == _Last || *_First != *_Symbol.c_str()))) { // showbase ==> mandatory symbol
// or
// currency symbol optional at end
_Symbol.erase();
}
_Source = _Symbol.begin();
while (_First != _Last && _Source != _Symbol.end() && *_First == *_Source) {
// still matching currency symbol
++_Source;
++_First;
}
if (_Source != _Symbol.end()) {
_Bad = true; // currency symbol match failed
}
break;
}
case money_base::sign: // parse sign
if (_First != _Last) {
if (0 < _Ppunct_fac->positive_sign().size()
&& _Ppunct_fac->positive_sign()[0] == *_First) { // match positive sign
++_First;
_Sign = _Ppunct_fac->positive_sign();
} else if (0 < _Ppunct_fac->negative_sign().size()
&& _Ppunct_fac->negative_sign()[0] == *_First) { // match negative sign
++_First;
_Sign = _Ppunct_fac->negative_sign();
_Neg = true;
} else if (0 != _Ppunct_fac->positive_sign().size() && 0 == _Ppunct_fac->negative_sign().size()) {
_Neg = true;
}
}
break; // sign match can't fail
case money_base::value:
{ // parse value field
int _Fracdigseen = 0;
int _Fracdigits = _Ppunct_fac->frac_digits();
const string _Grouping = _Ppunct_fac->grouping();
const _Elem _Kseparator = _Grouping.empty() ? _Elem{} : _Ppunct_fac->thousands_sep();
if (_Kseparator == _Elem{} || CHAR_MAX <= static_cast<unsigned char>(*_Grouping.c_str())) {
for (; _First != _Last && (_Idx = _Find_elem(_Atoms, *_First)) < 10; ++_First) {
_Val += _Src[_Idx]; // no grouping, just gather digits
}
} else { // grouping specified, gather digits and group sizes
string _Groups;
_Groups.push_back('\0');
size_t _Group = 0;
for (; _First != _Last; ++_First) {
if ((_Idx = _Find_elem(_Atoms, *_First)) < 10) { // got a digit, add to group size
_Val += _Src[_Idx];
if (_Groups[_Group] != CHAR_MAX) {
++_Groups[_Group];
}
} else if (_Groups[_Group] == '\0' || *_First != _Kseparator) {
break; // not a group separator, done
} else { // add a new group to _Groups string
_Groups.push_back('\0');
++_Group;
}
}
if (_Group != 0) { // thousands separators seen
if ('\0' < _Groups[_Group]) {
++_Group; // add trailing group to group count
} else {
_Bad = true; // trailing separator, fail
}
}
for (const char* _Pg = _Grouping.c_str(); !_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 (_Bad) {
break; // bad grouping, give up
}
}
const _Elem _Point = _Ppunct_fac->decimal_point();
if (_First != _Last && _Point != _Elem{}
&& *_First == _Point) { // seen decimal point, gather fraction digits
while (++_First != _Last && _Fracdigseen < _Fracdigits
&& (_Idx = _Find_elem(_Atoms, *_First)) < 10) {
_Val += _Src[_Idx];
++_Fracdigseen;
}
if (_Fracdigseen < _Fracdigits) {
_Bad = true; // short fraction
}
}
if (_Val.empty()) {
_Bad = true; // fail if no elements parsed
} else {
for (; _Fracdigseen < _Fracdigits; ++_Fracdigseen) {
_Val += '0'; // pad out fraction with zeros
}
}
break;
}
case money_base::space:
case money_base::none:
{ // parse optional space
if (_Off == 3) {
break; // ignore space at end
}
bool _Seen = false;
for (; _First != _Last && _Ctype_fac.is(ctype_base::space, *_First); ++_First) {
_Seen = true; // skip any space
}
if (_Pattern.field[_Off] == money_base::space && !_Seen) {
_Bad = true; // fail if no space seen
}
} // parse optional space
} // switch
}
if (!_Bad && 1 < _Sign.size()) { // match rest of sign string
auto _Source = _Sign.begin();
while (++_Source != _Sign.end() && _First != _Last && *_First == *_Source) {
++_First;
}
if (_Source != _Sign.end()) {
_Bad = true; // rest of sign doesn't match, fail
}
}
if (_Bad) {
_Val.erase(); // bad input, return empty string
} else if (_Neg) {
_Val.insert(0, 1, '-'); // minus sign
}
return _Val;
}
};
#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 money_get<_Elem, _InIt>::id;
#ifdef __clang__
#pragma clang diagnostic pop
#endif // defined(__clang__)
_EXPORT_STD template <class _Elem, class _OutIt = ostreambuf_iterator<_Elem, char_traits<_Elem>>>
class money_put : public locale::facet { // facet for converting encoded monetary amounts to text
private:
using _Mypunct0 = moneypunct<_Elem, false>;
using _Mypunct1 = moneypunct<_Elem, true>;
public:
static_assert(!_ENFORCE_FACET_SPECIALIZATIONS || _Is_any_of_v<_Elem, char, wchar_t>, _FACET_SPECIALIZATION_MESSAGE);
using char_type = _Elem;
using iter_type = _OutIt;
using string_type = basic_string<_Elem, char_traits<_Elem>, allocator<_Elem>>;
_OutIt put(_OutIt _Dest, bool _Intl, ios_base& _Iosbase, _Elem _Fill,
long double _Val) const { // put long double to _Dest
return do_put(_Dest, _Intl, _Iosbase, _Fill, _Val);
}
_OutIt put(_OutIt _Dest, bool _Intl, ios_base& _Iosbase, _Elem _Fill,
const string_type& _Val) const { // put string_type to _Dest
return do_put(_Dest, _Intl, _Iosbase, _Fill, _Val);
}
__PURE_APPDOMAIN_GLOBAL _CRTIMP2_PURE_IMPORT static locale::id id; // unique facet id
explicit money_put(size_t _Refs = 0) : locale::facet(_Refs) { // construct from current locale
_BEGIN_LOCINFO(_Lobj)
_Init(_Lobj);
_END_LOCINFO()
}
money_put(const _Locinfo& _Lobj, size_t _Refs = 0) : locale::facet(_Refs) {
_Init(_Lobj);
}
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 money_put<_Elem, _OutIt>(_Locinfo(_Ploc->_C_str()));
}
return _X_MONETARY;
}
protected:
__CLR_OR_THIS_CALL ~money_put() noexcept override {}
void _Init(const _Locinfo&) {} // initialize from _Locinfo object
virtual _OutIt __CLR_OR_THIS_CALL do_put(_OutIt _Dest, bool _Intl, ios_base& _Iosbase, _Elem _Fill,
long double _Val) const { // put long double to _Dest
bool _Negative = false;
if (_Val < 0) {
_Negative = true;
_Val = -_Val;
}
size_t _Exp;
for (_Exp = 0; 1e35 <= _Val && _Exp < 5000; _Exp += 10) {
_Val /= 1e10; // drop 10 zeros before decimal point
}
char _Buf[40];
// convert to chars:
const int _Count = _CSTD sprintf_s(_Buf, sizeof(_Buf), "%.0Lf", _Val);
if (_Count < 0) {
return _Dest; // bad conversion, give up
}
const ctype<_Elem>& _Ctype_fac = _STD use_facet<ctype<_Elem>>(_Iosbase.getloc());
const _Elem _Elem0 = _Ctype_fac.widen('0');
string_type _Val2(static_cast<size_t>(_Count), _Elem{});
_Ctype_fac.widen(_Buf, _Buf + _Count, &_Val2[0]);
_Val2.append(_Exp, _Elem0); // scale by trailing zeros
return _Putmfld(_Dest, _Intl, _Iosbase, _Fill, _Negative, _Val2, _Elem0);
}
virtual _OutIt __CLR_OR_THIS_CALL do_put(_OutIt _Dest, bool _Intl, ios_base& _Iosbase, _Elem _Fill,
const string_type& _Val) const { // put string_type to _Dest
static constexpr char _Src[] = "0123456789-";
_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);
bool _Negative = false;
size_t _Idx0 = 0;
if (!_Val.empty() && _Val[0] == _Atoms[10]) { // strip off '-'
_Negative = true;
++_Idx0;
}
size_t _Size = _Val.size();
size_t _Idx = _Idx0;
for (; _Idx < _Size && _Find_elem(_Atoms, _Val[_Idx]) < 10; ++_Idx) { // count digits
}
string_type _Val2(&_Val[_Idx0], _Idx - _Idx0);
if (_Val2.empty()) { // replace empty digit string with '0'
_Val2.push_back(_Atoms[0]);
}
return _Putmfld(_Dest, _Intl, _Iosbase, _Fill, _Negative, _Val2, _Atoms[0]);
}
private:
_OutIt _Putmfld(
_OutIt _Dest, bool _Intl, ios_base& _Iosbase, _Elem _Fill, bool _Neg, string_type _Val, _Elem _Elem0) const {
// put string_type with just digits to _Dest
const _Mpunct<_Elem>* _Ppunct_fac;
if (_Intl) {
_Ppunct_fac = _STD addressof(_STD use_facet<_Mypunct1>(_Iosbase.getloc())); // international
} else {
_Ppunct_fac = _STD addressof(_STD use_facet<_Mypunct0>(_Iosbase.getloc())); // local
}
const string _Grouping = _Ppunct_fac->grouping();
int _Ifracdigits = _Ppunct_fac->frac_digits();
const auto _Fracdigits = static_cast<unsigned int>(_Ifracdigits < 0 ? -_Ifracdigits : _Ifracdigits);
if (_Val.size() <= _Fracdigits) {
_Val.insert(0, _Fracdigits - _Val.size() + 1, _Elem0);
} else if (*_Grouping.c_str() != CHAR_MAX && '\0' < *_Grouping.c_str()) {
// grouping specified, add thousands separators
const _Elem _Kseparator = _Ppunct_fac->thousands_sep();
const char* _Pg = _Grouping.c_str();
size_t _Off = _Val.size() - _Fracdigits; // start of fraction
while (*_Pg != CHAR_MAX && '\0' < *_Pg && static_cast<size_t>(*_Pg) < _Off) {
// add a thousands separator, right to left
_Val.insert(_Off -= *_Pg, 1, _Kseparator);
if ('\0' < _Pg[1]) {
++_Pg; // not last group, advance
}
}
}
money_base::pattern _Pattern;
string_type _Sign;
if (_Neg) { // negative value, choose appropriate format and sign
_Pattern = _Ppunct_fac->neg_format();
_Sign = _Ppunct_fac->negative_sign();
} else { // positive value, choose appropriate format and sign
_Pattern = _Ppunct_fac->pos_format();
_Sign = _Ppunct_fac->positive_sign();
}
string_type _Symbol;
if (_Iosbase.flags() & ios_base::showbase) {
_Symbol = _Ppunct_fac->curr_symbol(); // showbase ==> show $
}
bool _Intern = false;
size_t _Fillcount;
size_t _Off;
for (_Fillcount = 0, _Off = 0; _Off < 4; ++_Off) {
switch (_Pattern.field[_Off]) { // accumulate total length in _Fillcount
case money_base::symbol: // count currency symbol size
_Fillcount += _Symbol.size();
break;
case money_base::sign: // count sign size
_Fillcount += _Sign.size();
break;
case money_base::value: // count value field size
_Fillcount += _Val.size() + (0 < _Fracdigits ? 1 : 0)
+ (_Val.size() <= _Fracdigits ? _Fracdigits - _Val.size() + 1 : 0);
break;
case money_base::space: // count space size
++_Fillcount; // at least one space
_FALLTHROUGH;
case money_base::none: // count space size
if (_Off != 3) {
_Intern = true; // optional internal fill
}
break;
}
}
if (_Iosbase.width() <= 0 || static_cast<size_t>(_Iosbase.width()) <= _Fillcount) {
_Fillcount = 0;
} else {
_Fillcount = static_cast<size_t>(_Iosbase.width()) - _Fillcount;
}
ios_base::fmtflags _Afl = _Iosbase.flags() & ios_base::adjustfield;
if (_Afl != ios_base::left && (_Afl != ios_base::internal || !_Intern)) { // put leading fill
_Dest = _Rep(_Dest, _Fill, _Fillcount);
_Fillcount = 0;
}
for (_Off = 0; _Off < 4; ++_Off) {
switch (_Pattern.field[_Off]) { // put components as specified by _Pattern
case money_base::symbol: // put currency symbol
_Dest = _Put(_Dest, _Symbol.begin(), _Symbol.size());
break;
case money_base::sign: // put sign
if (0 < _Sign.size()) {
_Dest = _Put(_Dest, _Sign.begin(), 1);
}
break;
case money_base::value: // put value field
if (_Fracdigits == 0) {
_Dest = _Put(_Dest, _Val.begin(), _Val.size()); // no fraction part
} else if (_Val.size() <= _Fracdigits) { // put leading zero, all fraction digits
*_Dest++ = _Elem0;
*_Dest++ = _Ppunct_fac->decimal_point();
_Dest = _Rep(_Dest, _Elem0, _Fracdigits - _Val.size()); // insert zeros
_Dest = _Put(_Dest, _Val.begin(), _Val.size());
} else { // put both integer and fraction parts
_Dest = _Put(_Dest, _Val.begin(), _Val.size() - _Fracdigits); // put integer part
*_Dest++ = _Ppunct_fac->decimal_point();
_Dest =
_Put(_Dest, _Val.end() - static_cast<ptrdiff_t>(_Fracdigits), _Fracdigits); // put fraction part
}
break;
case money_base::space: // put any internal fill
_Dest = _Rep(_Dest, _Fill, 1);
_FALLTHROUGH;
case money_base::none: // put any internal fill
if (_Afl == ios_base::internal) { // put internal fill
_Dest = _Rep(_Dest, _Fill, _Fillcount);
_Fillcount = 0;
}
}
}
if (1 < _Sign.size()) {
_Dest = _Put(_Dest, _Sign.begin() + 1, _Sign.size() - 1); // put remainder of sign
}
_Iosbase.width(0);
return _Rep(_Dest, _Fill, _Fillcount); // put trailing fill
}
static _OutIt _Put(_OutIt _Dest, typename string_type::const_iterator _Source, size_t _Count) {
// put [_Source, _Source + _Count) to _Dest
for (; 0 < _Count; --_Count, (void) ++_Dest, ++_Source) {
*_Dest = *_Source;
}
return _Dest;
}
static _OutIt _Rep(_OutIt _Dest, _Elem _Ch, size_t _Count) { // 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 money_put<_Elem, _OutIt>::id;
#if defined(_DLL_CPPLIB)
#if !defined(_CRTBLD) || defined(__FORCE_INSTANCE)
template _PGLOBAL const bool moneypunct<char, true>::intl;
template _PGLOBAL const bool moneypunct<char, false>::intl;
template __PURE_APPDOMAIN_GLOBAL locale::id moneypunct<char, true>::id;
template __PURE_APPDOMAIN_GLOBAL locale::id moneypunct<char, false>::id;
template __PURE_APPDOMAIN_GLOBAL locale::id money_get<char, istreambuf_iterator<char, char_traits<char>>>::id;
template __PURE_APPDOMAIN_GLOBAL locale::id money_put<char, ostreambuf_iterator<char, char_traits<char>>>::id;
template _PGLOBAL const bool moneypunct<wchar_t, true>::intl;
template _PGLOBAL const bool moneypunct<wchar_t, false>::intl;
template __PURE_APPDOMAIN_GLOBAL locale::id moneypunct<wchar_t, true>::id;
template __PURE_APPDOMAIN_GLOBAL locale::id moneypunct<wchar_t, false>::id;
template __PURE_APPDOMAIN_GLOBAL locale::id money_get<wchar_t, istreambuf_iterator<wchar_t, char_traits<wchar_t>>>::id;
template __PURE_APPDOMAIN_GLOBAL locale::id money_put<wchar_t, ostreambuf_iterator<wchar_t, char_traits<wchar_t>>>::id;
#endif // !defined(_CRTBLD) || defined(__FORCE_INSTANCE)
#ifdef __FORCE_INSTANCE
template _PGLOBAL const bool moneypunct<unsigned short, true>::intl;
template _PGLOBAL const bool moneypunct<unsigned short, false>::intl;
template __PURE_APPDOMAIN_GLOBAL locale::id moneypunct<unsigned short, true>::id;
template __PURE_APPDOMAIN_GLOBAL locale::id moneypunct<unsigned short, false>::id;
template __PURE_APPDOMAIN_GLOBAL locale::id
money_get<unsigned short, istreambuf_iterator<unsigned short, char_traits<unsigned short>>>::id;
template __PURE_APPDOMAIN_GLOBAL locale::id
money_put<unsigned short, ostreambuf_iterator<unsigned short, char_traits<unsigned short>>>::id;
#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 // _XLOCMON_