874 lines · c
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef _LIBCPP___LOCALE_DIR_MONEY_H10#define _LIBCPP___LOCALE_DIR_MONEY_H11 12#include <__algorithm/copy.h>13#include <__algorithm/equal.h>14#include <__algorithm/find.h>15#include <__algorithm/reverse.h>16#include <__config>17#include <__locale>18#include <__locale_dir/check_grouping.h>19#include <__locale_dir/get_c_locale.h>20#include <__locale_dir/pad_and_output.h>21#include <__memory/unique_ptr.h>22#include <ios>23#include <string>24 25#if _LIBCPP_HAS_LOCALIZATION26 27# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)28# pragma GCC system_header29# endif30 31_LIBCPP_PUSH_MACROS32# include <__undef_macros>33 34_LIBCPP_BEGIN_NAMESPACE_STD35 36// money_base37 38class _LIBCPP_EXPORTED_FROM_ABI money_base {39public:40 enum part { none, space, symbol, sign, value };41 struct pattern {42 char field[4];43 };44 45 _LIBCPP_HIDE_FROM_ABI money_base() {}46};47 48// moneypunct49 50template <class _CharT, bool _International = false>51class moneypunct : public locale::facet, public money_base {52public:53 typedef _CharT char_type;54 typedef basic_string<char_type> string_type;55 56 _LIBCPP_HIDE_FROM_ABI explicit moneypunct(size_t __refs = 0) : locale::facet(__refs) {}57 58 _LIBCPP_HIDE_FROM_ABI char_type decimal_point() const { return do_decimal_point(); }59 _LIBCPP_HIDE_FROM_ABI char_type thousands_sep() const { return do_thousands_sep(); }60 _LIBCPP_HIDE_FROM_ABI string grouping() const { return do_grouping(); }61 _LIBCPP_HIDE_FROM_ABI string_type curr_symbol() const { return do_curr_symbol(); }62 _LIBCPP_HIDE_FROM_ABI string_type positive_sign() const { return do_positive_sign(); }63 _LIBCPP_HIDE_FROM_ABI string_type negative_sign() const { return do_negative_sign(); }64 _LIBCPP_HIDE_FROM_ABI int frac_digits() const { return do_frac_digits(); }65 _LIBCPP_HIDE_FROM_ABI pattern pos_format() const { return do_pos_format(); }66 _LIBCPP_HIDE_FROM_ABI pattern neg_format() const { return do_neg_format(); }67 68 static locale::id id;69 static const bool intl = _International;70 71protected:72 _LIBCPP_HIDE_FROM_ABI_VIRTUAL ~moneypunct() override {}73 74 virtual char_type do_decimal_point() const { return numeric_limits<char_type>::max(); }75 virtual char_type do_thousands_sep() const { return numeric_limits<char_type>::max(); }76 virtual string do_grouping() const { return string(); }77 virtual string_type do_curr_symbol() const { return string_type(); }78 virtual string_type do_positive_sign() const { return string_type(); }79 virtual string_type do_negative_sign() const { return string_type(1, '-'); }80 virtual int do_frac_digits() const { return 0; }81 virtual pattern do_pos_format() const {82 pattern __p = {{symbol, sign, none, value}};83 return __p;84 }85 virtual pattern do_neg_format() const {86 pattern __p = {{symbol, sign, none, value}};87 return __p;88 }89};90 91template <class _CharT, bool _International>92locale::id moneypunct<_CharT, _International>::id;93 94template <class _CharT, bool _International>95const bool moneypunct<_CharT, _International>::intl;96 97extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS moneypunct<char, false>;98extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS moneypunct<char, true>;99# if _LIBCPP_HAS_WIDE_CHARACTERS100extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS moneypunct<wchar_t, false>;101extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS moneypunct<wchar_t, true>;102# endif103 104// moneypunct_byname105 106template <class _CharT, bool _International = false>107class moneypunct_byname : public moneypunct<_CharT, _International> {108public:109 typedef money_base::pattern pattern;110 typedef _CharT char_type;111 typedef basic_string<char_type> string_type;112 113 _LIBCPP_HIDE_FROM_ABI explicit moneypunct_byname(const char* __nm, size_t __refs = 0)114 : moneypunct<_CharT, _International>(__refs) {115 init(__nm);116 }117 118 _LIBCPP_HIDE_FROM_ABI explicit moneypunct_byname(const string& __nm, size_t __refs = 0)119 : moneypunct<_CharT, _International>(__refs) {120 init(__nm.c_str());121 }122 123protected:124 _LIBCPP_HIDE_FROM_ABI_VIRTUAL ~moneypunct_byname() override {}125 126 char_type do_decimal_point() const override { return __decimal_point_; }127 char_type do_thousands_sep() const override { return __thousands_sep_; }128 string do_grouping() const override { return __grouping_; }129 string_type do_curr_symbol() const override { return __curr_symbol_; }130 string_type do_positive_sign() const override { return __positive_sign_; }131 string_type do_negative_sign() const override { return __negative_sign_; }132 int do_frac_digits() const override { return __frac_digits_; }133 pattern do_pos_format() const override { return __pos_format_; }134 pattern do_neg_format() const override { return __neg_format_; }135 136private:137 char_type __decimal_point_;138 char_type __thousands_sep_;139 string __grouping_;140 string_type __curr_symbol_;141 string_type __positive_sign_;142 string_type __negative_sign_;143 int __frac_digits_;144 pattern __pos_format_;145 pattern __neg_format_;146 147 void init(const char*);148};149 150template <>151_LIBCPP_EXPORTED_FROM_ABI void moneypunct_byname<char, false>::init(const char*);152template <>153_LIBCPP_EXPORTED_FROM_ABI void moneypunct_byname<char, true>::init(const char*);154extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS moneypunct_byname<char, false>;155extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS moneypunct_byname<char, true>;156 157# if _LIBCPP_HAS_WIDE_CHARACTERS158template <>159_LIBCPP_EXPORTED_FROM_ABI void moneypunct_byname<wchar_t, false>::init(const char*);160template <>161_LIBCPP_EXPORTED_FROM_ABI void moneypunct_byname<wchar_t, true>::init(const char*);162extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS moneypunct_byname<wchar_t, false>;163extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS moneypunct_byname<wchar_t, true>;164# endif165 166// money_get167 168template <class _CharT>169class __money_get {170protected:171 typedef _CharT char_type;172 typedef basic_string<char_type> string_type;173 174 _LIBCPP_HIDE_FROM_ABI __money_get() {}175 176 static void __gather_info(177 bool __intl,178 const locale& __loc,179 money_base::pattern& __pat,180 char_type& __dp,181 char_type& __ts,182 string& __grp,183 string_type& __sym,184 string_type& __psn,185 string_type& __nsn,186 int& __fd);187};188 189template <class _CharT>190void __money_get<_CharT>::__gather_info(191 bool __intl,192 const locale& __loc,193 money_base::pattern& __pat,194 char_type& __dp,195 char_type& __ts,196 string& __grp,197 string_type& __sym,198 string_type& __psn,199 string_type& __nsn,200 int& __fd) {201 if (__intl) {202 const moneypunct<char_type, true>& __mp = std::use_facet<moneypunct<char_type, true> >(__loc);203 __pat = __mp.neg_format();204 __nsn = __mp.negative_sign();205 __psn = __mp.positive_sign();206 __dp = __mp.decimal_point();207 __ts = __mp.thousands_sep();208 __grp = __mp.grouping();209 __sym = __mp.curr_symbol();210 __fd = __mp.frac_digits();211 } else {212 const moneypunct<char_type, false>& __mp = std::use_facet<moneypunct<char_type, false> >(__loc);213 __pat = __mp.neg_format();214 __nsn = __mp.negative_sign();215 __psn = __mp.positive_sign();216 __dp = __mp.decimal_point();217 __ts = __mp.thousands_sep();218 __grp = __mp.grouping();219 __sym = __mp.curr_symbol();220 __fd = __mp.frac_digits();221 }222}223 224extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS __money_get<char>;225# if _LIBCPP_HAS_WIDE_CHARACTERS226extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS __money_get<wchar_t>;227# endif228 229template <class _CharT, class _InputIterator = istreambuf_iterator<_CharT> >230class money_get : public locale::facet, private __money_get<_CharT> {231public:232 typedef _CharT char_type;233 typedef _InputIterator iter_type;234 typedef basic_string<char_type> string_type;235 236 _LIBCPP_HIDE_FROM_ABI explicit money_get(size_t __refs = 0) : locale::facet(__refs) {}237 238 _LIBCPP_HIDE_FROM_ABI iter_type239 get(iter_type __b, iter_type __e, bool __intl, ios_base& __iob, ios_base::iostate& __err, long double& __v) const {240 return do_get(__b, __e, __intl, __iob, __err, __v);241 }242 243 _LIBCPP_HIDE_FROM_ABI iter_type244 get(iter_type __b, iter_type __e, bool __intl, ios_base& __iob, ios_base::iostate& __err, string_type& __v) const {245 return do_get(__b, __e, __intl, __iob, __err, __v);246 }247 248 static locale::id id;249 250protected:251 _LIBCPP_HIDE_FROM_ABI_VIRTUAL ~money_get() override {}252 253 virtual iter_type254 do_get(iter_type __b, iter_type __e, bool __intl, ios_base& __iob, ios_base::iostate& __err, long double& __v) const;255 virtual iter_type256 do_get(iter_type __b, iter_type __e, bool __intl, ios_base& __iob, ios_base::iostate& __err, string_type& __v) const;257 258private:259 static bool __do_get(260 iter_type& __b,261 iter_type __e,262 bool __intl,263 const locale& __loc,264 ios_base::fmtflags __flags,265 ios_base::iostate& __err,266 bool& __neg,267 const ctype<char_type>& __ct,268 unique_ptr<char_type, void (*)(void*)>& __wb,269 char_type*& __wn,270 char_type* __we);271};272 273template <class _CharT, class _InputIterator>274locale::id money_get<_CharT, _InputIterator>::id;275 276_LIBCPP_EXPORTED_FROM_ABI void __do_nothing(void*);277 278template <class _Tp>279_LIBCPP_HIDE_FROM_ABI void __double_or_nothing(unique_ptr<_Tp, void (*)(void*)>& __b, _Tp*& __n, _Tp*& __e) {280 bool __owns = __b.get_deleter() != __do_nothing;281 size_t __cur_cap = static_cast<size_t>(__e - __b.get()) * sizeof(_Tp);282 size_t __new_cap = __cur_cap < numeric_limits<size_t>::max() / 2 ? 2 * __cur_cap : numeric_limits<size_t>::max();283 if (__new_cap == 0)284 __new_cap = sizeof(_Tp);285 size_t __n_off = static_cast<size_t>(__n - __b.get());286 _Tp* __t = (_Tp*)std::realloc(__owns ? __b.get() : 0, __new_cap);287 if (__t == 0)288 std::__throw_bad_alloc();289 if (__owns)290 __b.release();291 else292 std::memcpy(__t, __b.get(), __cur_cap);293 __b = unique_ptr<_Tp, void (*)(void*)>(__t, free);294 __new_cap /= sizeof(_Tp);295 __n = __b.get() + __n_off;296 __e = __b.get() + __new_cap;297}298 299// true == success300template <class _CharT, class _InputIterator>301bool money_get<_CharT, _InputIterator>::__do_get(302 iter_type& __b,303 iter_type __e,304 bool __intl,305 const locale& __loc,306 ios_base::fmtflags __flags,307 ios_base::iostate& __err,308 bool& __neg,309 const ctype<char_type>& __ct,310 unique_ptr<char_type, void (*)(void*)>& __wb,311 char_type*& __wn,312 char_type* __we) {313 if (__b == __e) {314 __err |= ios_base::failbit;315 return false;316 }317 const unsigned __bz = 100;318 unsigned __gbuf[__bz];319 unique_ptr<unsigned, void (*)(void*)> __gb(__gbuf, __do_nothing);320 unsigned* __gn = __gb.get();321 unsigned* __ge = __gn + __bz;322 money_base::pattern __pat;323 char_type __dp;324 char_type __ts;325 string __grp;326 string_type __sym;327 string_type __psn;328 string_type __nsn;329 // Capture the spaces read into money_base::{space,none} so they330 // can be compared to initial spaces in __sym.331 string_type __spaces;332 int __fd;333 __money_get<_CharT>::__gather_info(__intl, __loc, __pat, __dp, __ts, __grp, __sym, __psn, __nsn, __fd);334 const string_type* __trailing_sign = 0;335 __wn = __wb.get();336 for (unsigned __p = 0; __p < 4 && __b != __e; ++__p) {337 switch (__pat.field[__p]) {338 case money_base::space:339 if (__p != 3) {340 if (__ct.is(ctype_base::space, *__b))341 __spaces.push_back(*__b++);342 else {343 __err |= ios_base::failbit;344 return false;345 }346 }347 [[__fallthrough__]];348 case money_base::none:349 if (__p != 3) {350 while (__b != __e && __ct.is(ctype_base::space, *__b))351 __spaces.push_back(*__b++);352 }353 break;354 case money_base::sign:355 if (__psn.size() > 0 && *__b == __psn[0]) {356 ++__b;357 __neg = false;358 if (__psn.size() > 1)359 __trailing_sign = std::addressof(__psn);360 break;361 }362 if (__nsn.size() > 0 && *__b == __nsn[0]) {363 ++__b;364 __neg = true;365 if (__nsn.size() > 1)366 __trailing_sign = std::addressof(__nsn);367 break;368 }369 if (__psn.size() > 0 && __nsn.size() > 0) { // sign is required370 __err |= ios_base::failbit;371 return false;372 }373 if (__psn.size() == 0 && __nsn.size() == 0)374 // locale has no way of specifying a sign. Use the initial value of __neg as a default375 break;376 __neg = (__nsn.size() == 0);377 break;378 case money_base::symbol: {379 bool __more_needed =380 __trailing_sign || (__p < 2) || (__p == 2 && __pat.field[3] != static_cast<char>(money_base::none));381 bool __sb = (__flags & ios_base::showbase) != 0;382 if (__sb || __more_needed) {383 typename string_type::const_iterator __sym_space_end = __sym.begin();384 if (__p > 0 && (__pat.field[__p - 1] == money_base::none || __pat.field[__p - 1] == money_base::space)) {385 // Match spaces we've already read against spaces at386 // the beginning of __sym.387 while (__sym_space_end != __sym.end() && __ct.is(ctype_base::space, *__sym_space_end))388 ++__sym_space_end;389 const size_t __num_spaces = __sym_space_end - __sym.begin();390 if (__num_spaces > __spaces.size() ||391 !std::equal(__spaces.end() - __num_spaces, __spaces.end(), __sym.begin())) {392 // No match. Put __sym_space_end back at the393 // beginning of __sym, which will prevent a394 // match in the next loop.395 __sym_space_end = __sym.begin();396 }397 }398 typename string_type::const_iterator __sym_curr_char = __sym_space_end;399 while (__sym_curr_char != __sym.end() && __b != __e && *__b == *__sym_curr_char) {400 ++__b;401 ++__sym_curr_char;402 }403 if (__sb && __sym_curr_char != __sym.end()) {404 __err |= ios_base::failbit;405 return false;406 }407 }408 } break;409 case money_base::value: {410 unsigned __ng = 0;411 for (; __b != __e; ++__b) {412 char_type __c = *__b;413 if (__ct.is(ctype_base::digit, __c)) {414 if (__wn == __we)415 std::__double_or_nothing(__wb, __wn, __we);416 *__wn++ = __c;417 ++__ng;418 } else if (__grp.size() > 0 && __ng > 0 && __c == __ts) {419 if (__gn == __ge)420 std::__double_or_nothing(__gb, __gn, __ge);421 *__gn++ = __ng;422 __ng = 0;423 } else424 break;425 }426 if (__gb.get() != __gn && __ng > 0) {427 if (__gn == __ge)428 std::__double_or_nothing(__gb, __gn, __ge);429 *__gn++ = __ng;430 }431 if (__fd > 0) {432 if (__b == __e || *__b != __dp) {433 __err |= ios_base::failbit;434 return false;435 }436 for (++__b; __fd > 0; --__fd, (void)++__b) {437 if (__b == __e || !__ct.is(ctype_base::digit, *__b)) {438 __err |= ios_base::failbit;439 return false;440 }441 if (__wn == __we)442 std::__double_or_nothing(__wb, __wn, __we);443 *__wn++ = *__b;444 }445 }446 if (__wn == __wb.get()) {447 __err |= ios_base::failbit;448 return false;449 }450 } break;451 }452 }453 if (__trailing_sign) {454 for (unsigned __i = 1; __i < __trailing_sign->size(); ++__i, (void)++__b) {455 if (__b == __e || *__b != (*__trailing_sign)[__i]) {456 __err |= ios_base::failbit;457 return false;458 }459 }460 }461 if (__gb.get() != __gn) {462 ios_base::iostate __et = ios_base::goodbit;463 __check_grouping(__grp, __gb.get(), __gn, __et);464 if (__et) {465 __err |= ios_base::failbit;466 return false;467 }468 }469 return true;470}471 472template <class _CharT, class _InputIterator>473_InputIterator money_get<_CharT, _InputIterator>::do_get(474 iter_type __b, iter_type __e, bool __intl, ios_base& __iob, ios_base::iostate& __err, long double& __v) const {475 const int __bz = 100;476 char_type __wbuf[__bz];477 unique_ptr<char_type, void (*)(void*)> __wb(__wbuf, __do_nothing);478 char_type* __wn;479 char_type* __we = __wbuf + __bz;480 locale __loc = __iob.getloc();481 const ctype<char_type>& __ct = std::use_facet<ctype<char_type> >(__loc);482 bool __neg = false;483 if (__do_get(__b, __e, __intl, __loc, __iob.flags(), __err, __neg, __ct, __wb, __wn, __we)) {484 const char __src[] = "0123456789";485 char_type __atoms[sizeof(__src) - 1];486 __ct.widen(__src, __src + (sizeof(__src) - 1), __atoms);487 char __nbuf[__bz];488 char* __nc = __nbuf;489 const char* __nc_in = __nc;490 unique_ptr<char, void (*)(void*)> __h(nullptr, free);491 if (__wn - __wb.get() > __bz - 2) {492 __h.reset((char*)malloc(static_cast<size_t>(__wn - __wb.get() + 2)));493 if (__h.get() == nullptr)494 std::__throw_bad_alloc();495 __nc = __h.get();496 __nc_in = __nc;497 }498 if (__neg)499 *__nc++ = '-';500 for (const char_type* __w = __wb.get(); __w < __wn; ++__w, ++__nc)501 *__nc = __src[std::find(__atoms, std::end(__atoms), *__w) - __atoms];502 *__nc = char();503 if (sscanf(__nc_in, "%Lf", &__v) != 1)504 std::__throw_runtime_error("money_get error");505 }506 if (__b == __e)507 __err |= ios_base::eofbit;508 return __b;509}510 511template <class _CharT, class _InputIterator>512_InputIterator money_get<_CharT, _InputIterator>::do_get(513 iter_type __b, iter_type __e, bool __intl, ios_base& __iob, ios_base::iostate& __err, string_type& __v) const {514 const int __bz = 100;515 char_type __wbuf[__bz];516 unique_ptr<char_type, void (*)(void*)> __wb(__wbuf, __do_nothing);517 char_type* __wn;518 char_type* __we = __wbuf + __bz;519 locale __loc = __iob.getloc();520 const ctype<char_type>& __ct = std::use_facet<ctype<char_type> >(__loc);521 bool __neg = false;522 if (__do_get(__b, __e, __intl, __loc, __iob.flags(), __err, __neg, __ct, __wb, __wn, __we)) {523 __v.clear();524 if (__neg)525 __v.push_back(__ct.widen('-'));526 char_type __z = __ct.widen('0');527 char_type* __w;528 for (__w = __wb.get(); __w < __wn - 1; ++__w)529 if (*__w != __z)530 break;531 __v.append(__w, __wn);532 }533 if (__b == __e)534 __err |= ios_base::eofbit;535 return __b;536}537 538extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS money_get<char>;539# if _LIBCPP_HAS_WIDE_CHARACTERS540extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS money_get<wchar_t>;541# endif542 543// money_put544 545template <class _CharT>546class __money_put {547protected:548 typedef _CharT char_type;549 typedef basic_string<char_type> string_type;550 551 _LIBCPP_HIDE_FROM_ABI __money_put() {}552 553 static void __gather_info(554 bool __intl,555 bool __neg,556 const locale& __loc,557 money_base::pattern& __pat,558 char_type& __dp,559 char_type& __ts,560 string& __grp,561 string_type& __sym,562 string_type& __sn,563 int& __fd);564 static void __format(565 char_type* __mb,566 char_type*& __mi,567 char_type*& __me,568 ios_base::fmtflags __flags,569 const char_type* __db,570 const char_type* __de,571 const ctype<char_type>& __ct,572 bool __neg,573 const money_base::pattern& __pat,574 char_type __dp,575 char_type __ts,576 const string& __grp,577 const string_type& __sym,578 const string_type& __sn,579 int __fd);580};581 582template <class _CharT>583void __money_put<_CharT>::__gather_info(584 bool __intl,585 bool __neg,586 const locale& __loc,587 money_base::pattern& __pat,588 char_type& __dp,589 char_type& __ts,590 string& __grp,591 string_type& __sym,592 string_type& __sn,593 int& __fd) {594 if (__intl) {595 const moneypunct<char_type, true>& __mp = std::use_facet<moneypunct<char_type, true> >(__loc);596 if (__neg) {597 __pat = __mp.neg_format();598 __sn = __mp.negative_sign();599 } else {600 __pat = __mp.pos_format();601 __sn = __mp.positive_sign();602 }603 __dp = __mp.decimal_point();604 __ts = __mp.thousands_sep();605 __grp = __mp.grouping();606 __sym = __mp.curr_symbol();607 __fd = __mp.frac_digits();608 } else {609 const moneypunct<char_type, false>& __mp = std::use_facet<moneypunct<char_type, false> >(__loc);610 if (__neg) {611 __pat = __mp.neg_format();612 __sn = __mp.negative_sign();613 } else {614 __pat = __mp.pos_format();615 __sn = __mp.positive_sign();616 }617 __dp = __mp.decimal_point();618 __ts = __mp.thousands_sep();619 __grp = __mp.grouping();620 __sym = __mp.curr_symbol();621 __fd = __mp.frac_digits();622 }623}624 625template <class _CharT>626void __money_put<_CharT>::__format(627 char_type* __mb,628 char_type*& __mi,629 char_type*& __me,630 ios_base::fmtflags __flags,631 const char_type* __db,632 const char_type* __de,633 const ctype<char_type>& __ct,634 bool __neg,635 const money_base::pattern& __pat,636 char_type __dp,637 char_type __ts,638 const string& __grp,639 const string_type& __sym,640 const string_type& __sn,641 int __fd) {642 __me = __mb;643 for (char __p : __pat.field) {644 switch (__p) {645 case money_base::none:646 __mi = __me;647 break;648 case money_base::space:649 __mi = __me;650 *__me++ = __ct.widen(' ');651 break;652 case money_base::sign:653 if (!__sn.empty())654 *__me++ = __sn[0];655 break;656 case money_base::symbol:657 if (!__sym.empty() && (__flags & ios_base::showbase))658 __me = std::copy(__sym.begin(), __sym.end(), __me);659 break;660 case money_base::value: {661 // remember start of value so we can reverse it662 char_type* __t = __me;663 // find beginning of digits664 if (__neg)665 ++__db;666 // find end of digits667 const char_type* __d;668 for (__d = __db; __d < __de; ++__d)669 if (!__ct.is(ctype_base::digit, *__d))670 break;671 // print fractional part672 if (__fd > 0) {673 int __f;674 for (__f = __fd; __d > __db && __f > 0; --__f)675 *__me++ = *--__d;676 char_type __z = __f > 0 ? __ct.widen('0') : char_type();677 for (; __f > 0; --__f)678 *__me++ = __z;679 *__me++ = __dp;680 }681 // print units part682 if (__d == __db) {683 *__me++ = __ct.widen('0');684 } else {685 unsigned __ng = 0;686 unsigned __ig = 0;687 unsigned __gl = __grp.empty() ? numeric_limits<unsigned>::max() : static_cast<unsigned>(__grp[__ig]);688 while (__d != __db) {689 if (__ng == __gl) {690 *__me++ = __ts;691 __ng = 0;692 if (++__ig < __grp.size())693 __gl = __grp[__ig] == numeric_limits<char>::max()694 ? numeric_limits<unsigned>::max()695 : static_cast<unsigned>(__grp[__ig]);696 }697 *__me++ = *--__d;698 ++__ng;699 }700 }701 // reverse it702 std::reverse(__t, __me);703 } break;704 }705 }706 // print rest of sign, if any707 if (__sn.size() > 1)708 __me = std::copy(__sn.begin() + 1, __sn.end(), __me);709 // set alignment710 if ((__flags & ios_base::adjustfield) == ios_base::left)711 __mi = __me;712 else if ((__flags & ios_base::adjustfield) != ios_base::internal)713 __mi = __mb;714}715 716extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS __money_put<char>;717# if _LIBCPP_HAS_WIDE_CHARACTERS718extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS __money_put<wchar_t>;719# endif720 721template <class _CharT, class _OutputIterator = ostreambuf_iterator<_CharT> >722class money_put : public locale::facet, private __money_put<_CharT> {723public:724 typedef _CharT char_type;725 typedef _OutputIterator iter_type;726 typedef basic_string<char_type> string_type;727 728 _LIBCPP_HIDE_FROM_ABI explicit money_put(size_t __refs = 0) : locale::facet(__refs) {}729 730 _LIBCPP_HIDE_FROM_ABI iter_type731 put(iter_type __s, bool __intl, ios_base& __iob, char_type __fl, long double __units) const {732 return do_put(__s, __intl, __iob, __fl, __units);733 }734 735 _LIBCPP_HIDE_FROM_ABI iter_type736 put(iter_type __s, bool __intl, ios_base& __iob, char_type __fl, const string_type& __digits) const {737 return do_put(__s, __intl, __iob, __fl, __digits);738 }739 740 static locale::id id;741 742protected:743 _LIBCPP_HIDE_FROM_ABI_VIRTUAL ~money_put() override {}744 745 virtual iter_type do_put(iter_type __s, bool __intl, ios_base& __iob, char_type __fl, long double __units) const;746 virtual iter_type747 do_put(iter_type __s, bool __intl, ios_base& __iob, char_type __fl, const string_type& __digits) const;748};749 750template <class _CharT, class _OutputIterator>751locale::id money_put<_CharT, _OutputIterator>::id;752 753template <class _CharT, class _OutputIterator>754_OutputIterator money_put<_CharT, _OutputIterator>::do_put(755 iter_type __s, bool __intl, ios_base& __iob, char_type __fl, long double __units) const {756 // convert to char757 const size_t __bs = 100;758 char __buf[__bs];759 char* __bb = __buf;760 char_type __digits[__bs];761 char_type* __db = __digits;762 int __n = snprintf(__bb, __bs, "%.0Lf", __units);763 unique_ptr<char, void (*)(void*)> __hn(nullptr, free);764 unique_ptr<char_type, void (*)(void*)> __hd(0, free);765 // secure memory for digit storage766 if (static_cast<size_t>(__n) > __bs - 1) {767 __n = __locale::__asprintf(&__bb, _LIBCPP_GET_C_LOCALE, "%.0Lf", __units);768 if (__n == -1)769 std::__throw_bad_alloc();770 __hn.reset(__bb);771 __hd.reset((char_type*)malloc(static_cast<size_t>(__n) * sizeof(char_type)));772 if (__hd == nullptr)773 std::__throw_bad_alloc();774 __db = __hd.get();775 }776 // gather info777 locale __loc = __iob.getloc();778 const ctype<char_type>& __ct = std::use_facet<ctype<char_type> >(__loc);779 __ct.widen(__bb, __bb + __n, __db);780 bool __neg = __n > 0 && __bb[0] == '-';781 money_base::pattern __pat;782 char_type __dp;783 char_type __ts;784 string __grp;785 string_type __sym;786 string_type __sn;787 int __fd;788 this->__gather_info(__intl, __neg, __loc, __pat, __dp, __ts, __grp, __sym, __sn, __fd);789 // secure memory for formatting790 char_type __mbuf[__bs];791 char_type* __mb = __mbuf;792 unique_ptr<char_type, void (*)(void*)> __hw(0, free);793 size_t __exn = __n > __fd ? (static_cast<size_t>(__n) - static_cast<size_t>(__fd)) * 2 + __sn.size() + __sym.size() +794 static_cast<size_t>(__fd) + 1795 : __sn.size() + __sym.size() + static_cast<size_t>(__fd) + 2;796 if (__exn > __bs) {797 __hw.reset((char_type*)malloc(__exn * sizeof(char_type)));798 __mb = __hw.get();799 if (__mb == 0)800 std::__throw_bad_alloc();801 }802 // format803 char_type* __mi;804 char_type* __me;805 this->__format(806 __mb, __mi, __me, __iob.flags(), __db, __db + __n, __ct, __neg, __pat, __dp, __ts, __grp, __sym, __sn, __fd);807 return std::__pad_and_output(__s, __mb, __mi, __me, __iob, __fl);808}809 810template <class _CharT, class _OutputIterator>811_OutputIterator money_put<_CharT, _OutputIterator>::do_put(812 iter_type __s, bool __intl, ios_base& __iob, char_type __fl, const string_type& __digits) const {813 // gather info814 locale __loc = __iob.getloc();815 const ctype<char_type>& __ct = std::use_facet<ctype<char_type> >(__loc);816 bool __neg = __digits.size() > 0 && __digits[0] == __ct.widen('-');817 money_base::pattern __pat;818 char_type __dp;819 char_type __ts;820 string __grp;821 string_type __sym;822 string_type __sn;823 int __fd;824 this->__gather_info(__intl, __neg, __loc, __pat, __dp, __ts, __grp, __sym, __sn, __fd);825 // secure memory for formatting826 char_type __mbuf[100];827 char_type* __mb = __mbuf;828 unique_ptr<char_type, void (*)(void*)> __h(0, free);829 size_t __exn =830 static_cast<int>(__digits.size()) > __fd831 ? (__digits.size() - static_cast<size_t>(__fd)) * 2 + __sn.size() + __sym.size() + static_cast<size_t>(__fd) +832 1833 : __sn.size() + __sym.size() + static_cast<size_t>(__fd) + 2;834 if (__exn > 100) {835 __h.reset((char_type*)malloc(__exn * sizeof(char_type)));836 __mb = __h.get();837 if (__mb == 0)838 std::__throw_bad_alloc();839 }840 // format841 char_type* __mi;842 char_type* __me;843 this->__format(844 __mb,845 __mi,846 __me,847 __iob.flags(),848 __digits.data(),849 __digits.data() + __digits.size(),850 __ct,851 __neg,852 __pat,853 __dp,854 __ts,855 __grp,856 __sym,857 __sn,858 __fd);859 return std::__pad_and_output(__s, __mb, __mi, __me, __iob, __fl);860}861 862extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS money_put<char>;863# if _LIBCPP_HAS_WIDE_CHARACTERS864extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS money_put<wchar_t>;865# endif866 867_LIBCPP_END_NAMESPACE_STD868 869_LIBCPP_POP_MACROS870 871#endif // _LIBCPP_HAS_LOCALIZATION872 873#endif // _LIBCPP___LOCALE_DIR_MONEY_H874