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