master
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
36// money_base
37
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// moneypunct
49
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_CHARACTERS
100extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS moneypunct<wchar_t, false>;
101extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS moneypunct<wchar_t, true>;
102# endif
103
104// moneypunct_byname
105
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_CHARACTERS
158template <>
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# endif
165
166// money_get
167
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_CHARACTERS
226extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS __money_get<wchar_t>;
227# endif
228
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_type
239 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_type
244 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_type
254 do_get(iter_type __b, iter_type __e, bool __intl, ios_base& __iob, ios_base::iostate& __err, long double& __v) const;
255 virtual iter_type
256 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 else
292 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 == success
300template <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 they
330 // 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 required
370 __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 default
375 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 at
386 // 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 the
393 // beginning of __sym, which will prevent a
394 // 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 } else
424 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, ++__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, ++__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_CHARACTERS
540extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS money_get<wchar_t>;
541# endif
542
543// money_put
544
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 it
662 char_type* __t = __me;
663 // find beginning of digits
664 if (__neg)
665 ++__db;
666 // find end of digits
667 const char_type* __d;
668 for (__d = __db; __d < __de; ++__d)
669 if (!__ct.is(ctype_base::digit, *__d))
670 break;
671 // print fractional part
672 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 part
682 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 it
702 std::reverse(__t, __me);
703 } break;
704 }
705 }
706 // print rest of sign, if any
707 if (__sn.size() > 1)
708 __me = std::copy(__sn.begin() + 1, __sn.end(), __me);
709 // set alignment
710 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_CHARACTERS
718extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS __money_put<wchar_t>;
719# endif
720
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_type
731 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_type
736 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_type
747 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 char
757 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 storage
766 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 info
777 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 formatting
790 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) + 1
795 : __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 // format
803 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 info
814 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 formatting
826 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()) > __fd
831 ? (__digits.size() - static_cast<size_t>(__fd)) * 2 + __sn.size() + __sym.size() + static_cast<size_t>(__fd) +
832 1
833 : __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 // format
841 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_CHARACTERS
864extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS money_put<wchar_t>;
865# endif
866
867_LIBCPP_END_NAMESPACE_STD
868
869_LIBCPP_POP_MACROS
870
871#endif // _LIBCPP_HAS_LOCALIZATION
872
873#endif // _LIBCPP___LOCALE_DIR_MONEY_H