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