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