xref: /freebsd/contrib/llvm-project/libcxx/include/__locale_dir/money.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 
38 class _LIBCPP_EXPORTED_FROM_ABI money_base {
39 public:
40   enum part { none, space, symbol, sign, value };
41   struct pattern {
42     char field[4];
43   };
44 
money_base()45   _LIBCPP_HIDE_FROM_ABI money_base() {}
46 };
47 
48 // moneypunct
49 
50 template <class _CharT, bool _International = false>
51 class moneypunct : public locale::facet, public money_base {
52 public:
53   typedef _CharT char_type;
54   typedef basic_string<char_type> string_type;
55 
facet(__refs)56   _LIBCPP_HIDE_FROM_ABI explicit moneypunct(size_t __refs = 0) : locale::facet(__refs) {}
57 
decimal_point()58   _LIBCPP_HIDE_FROM_ABI char_type decimal_point() const { return do_decimal_point(); }
thousands_sep()59   _LIBCPP_HIDE_FROM_ABI char_type thousands_sep() const { return do_thousands_sep(); }
grouping()60   _LIBCPP_HIDE_FROM_ABI string grouping() const { return do_grouping(); }
curr_symbol()61   _LIBCPP_HIDE_FROM_ABI string_type curr_symbol() const { return do_curr_symbol(); }
positive_sign()62   _LIBCPP_HIDE_FROM_ABI string_type positive_sign() const { return do_positive_sign(); }
negative_sign()63   _LIBCPP_HIDE_FROM_ABI string_type negative_sign() const { return do_negative_sign(); }
frac_digits()64   _LIBCPP_HIDE_FROM_ABI int frac_digits() const { return do_frac_digits(); }
pos_format()65   _LIBCPP_HIDE_FROM_ABI pattern pos_format() const { return do_pos_format(); }
neg_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 
71 protected:
~moneypunct()72   _LIBCPP_HIDE_FROM_ABI_VIRTUAL ~moneypunct() override {}
73 
do_decimal_point()74   virtual char_type do_decimal_point() const { return numeric_limits<char_type>::max(); }
do_thousands_sep()75   virtual char_type do_thousands_sep() const { return numeric_limits<char_type>::max(); }
do_grouping()76   virtual string do_grouping() const { return string(); }
do_curr_symbol()77   virtual string_type do_curr_symbol() const { return string_type(); }
do_positive_sign()78   virtual string_type do_positive_sign() const { return string_type(); }
do_negative_sign()79   virtual string_type do_negative_sign() const { return string_type(1, '-'); }
do_frac_digits()80   virtual int do_frac_digits() const { return 0; }
do_pos_format()81   virtual pattern do_pos_format() const {
82     pattern __p = {{symbol, sign, none, value}};
83     return __p;
84   }
do_neg_format()85   virtual pattern do_neg_format() const {
86     pattern __p = {{symbol, sign, none, value}};
87     return __p;
88   }
89 };
90 
91 template <class _CharT, bool _International>
92 locale::id moneypunct<_CharT, _International>::id;
93 
94 template <class _CharT, bool _International>
95 const bool moneypunct<_CharT, _International>::intl;
96 
97 extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS moneypunct<char, false>;
98 extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS moneypunct<char, true>;
99 #  if _LIBCPP_HAS_WIDE_CHARACTERS
100 extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS moneypunct<wchar_t, false>;
101 extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS moneypunct<wchar_t, true>;
102 #  endif
103 
104 // moneypunct_byname
105 
106 template <class _CharT, bool _International = false>
107 class moneypunct_byname : public moneypunct<_CharT, _International> {
108 public:
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 
123 protected:
~moneypunct_byname()124   _LIBCPP_HIDE_FROM_ABI_VIRTUAL ~moneypunct_byname() override {}
125 
do_decimal_point()126   char_type do_decimal_point() const override { return __decimal_point_; }
do_thousands_sep()127   char_type do_thousands_sep() const override { return __thousands_sep_; }
do_grouping()128   string do_grouping() const override { return __grouping_; }
do_curr_symbol()129   string_type do_curr_symbol() const override { return __curr_symbol_; }
do_positive_sign()130   string_type do_positive_sign() const override { return __positive_sign_; }
do_negative_sign()131   string_type do_negative_sign() const override { return __negative_sign_; }
do_frac_digits()132   int do_frac_digits() const override { return __frac_digits_; }
do_pos_format()133   pattern do_pos_format() const override { return __pos_format_; }
do_neg_format()134   pattern do_neg_format() const override { return __neg_format_; }
135 
136 private:
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 
150 template <>
151 _LIBCPP_EXPORTED_FROM_ABI void moneypunct_byname<char, false>::init(const char*);
152 template <>
153 _LIBCPP_EXPORTED_FROM_ABI void moneypunct_byname<char, true>::init(const char*);
154 extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS moneypunct_byname<char, false>;
155 extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS moneypunct_byname<char, true>;
156 
157 #  if _LIBCPP_HAS_WIDE_CHARACTERS
158 template <>
159 _LIBCPP_EXPORTED_FROM_ABI void moneypunct_byname<wchar_t, false>::init(const char*);
160 template <>
161 _LIBCPP_EXPORTED_FROM_ABI void moneypunct_byname<wchar_t, true>::init(const char*);
162 extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS moneypunct_byname<wchar_t, false>;
163 extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS moneypunct_byname<wchar_t, true>;
164 #  endif
165 
166 // money_get
167 
168 template <class _CharT>
169 class __money_get {
170 protected:
171   typedef _CharT char_type;
172   typedef basic_string<char_type> string_type;
173 
__money_get()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 
189 template <class _CharT>
__gather_info(bool __intl,const locale & __loc,money_base::pattern & __pat,char_type & __dp,char_type & __ts,string & __grp,string_type & __sym,string_type & __psn,string_type & __nsn,int & __fd)190 void __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 
224 extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS __money_get<char>;
225 #  if _LIBCPP_HAS_WIDE_CHARACTERS
226 extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS __money_get<wchar_t>;
227 #  endif
228 
229 template <class _CharT, class _InputIterator = istreambuf_iterator<_CharT> >
230 class money_get : public locale::facet, private __money_get<_CharT> {
231 public:
232   typedef _CharT char_type;
233   typedef _InputIterator iter_type;
234   typedef basic_string<char_type> string_type;
235 
facet(__refs)236   _LIBCPP_HIDE_FROM_ABI explicit money_get(size_t __refs = 0) : locale::facet(__refs) {}
237 
238   _LIBCPP_HIDE_FROM_ABI iter_type
get(iter_type __b,iter_type __e,bool __intl,ios_base & __iob,ios_base::iostate & __err,long double & __v)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
get(iter_type __b,iter_type __e,bool __intl,ios_base & __iob,ios_base::iostate & __err,string_type & __v)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 
250 protected:
~money_get()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 
258 private:
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 
273 template <class _CharT, class _InputIterator>
274 locale::id money_get<_CharT, _InputIterator>::id;
275 
276 _LIBCPP_EXPORTED_FROM_ABI void __do_nothing(void*);
277 
278 template <class _Tp>
__double_or_nothing(unique_ptr<_Tp,void (*)(void *)> & __b,_Tp * & __n,_Tp * & __e)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
300 template <class _CharT, class _InputIterator>
__do_get(iter_type & __b,iter_type __e,bool __intl,const locale & __loc,ios_base::fmtflags __flags,ios_base::iostate & __err,bool & __neg,const ctype<char_type> & __ct,unique_ptr<char_type,void (*)(void *)> & __wb,char_type * & __wn,char_type * __we)301 bool 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 
472 template <class _CharT, class _InputIterator>
do_get(iter_type __b,iter_type __e,bool __intl,ios_base & __iob,ios_base::iostate & __err,long double & __v)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 
511 template <class _CharT, class _InputIterator>
do_get(iter_type __b,iter_type __e,bool __intl,ios_base & __iob,ios_base::iostate & __err,string_type & __v)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 
538 extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS money_get<char>;
539 #  if _LIBCPP_HAS_WIDE_CHARACTERS
540 extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS money_get<wchar_t>;
541 #  endif
542 
543 // money_put
544 
545 template <class _CharT>
546 class __money_put {
547 protected:
548   typedef _CharT char_type;
549   typedef basic_string<char_type> string_type;
550 
__money_put()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 
582 template <class _CharT>
__gather_info(bool __intl,bool __neg,const locale & __loc,money_base::pattern & __pat,char_type & __dp,char_type & __ts,string & __grp,string_type & __sym,string_type & __sn,int & __fd)583 void __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 
625 template <class _CharT>
__format(char_type * __mb,char_type * & __mi,char_type * & __me,ios_base::fmtflags __flags,const char_type * __db,const char_type * __de,const ctype<char_type> & __ct,bool __neg,const money_base::pattern & __pat,char_type __dp,char_type __ts,const string & __grp,const string_type & __sym,const string_type & __sn,int __fd)626 void __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 
716 extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS __money_put<char>;
717 #  if _LIBCPP_HAS_WIDE_CHARACTERS
718 extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS __money_put<wchar_t>;
719 #  endif
720 
721 template <class _CharT, class _OutputIterator = ostreambuf_iterator<_CharT> >
722 class money_put : public locale::facet, private __money_put<_CharT> {
723 public:
724   typedef _CharT char_type;
725   typedef _OutputIterator iter_type;
726   typedef basic_string<char_type> string_type;
727 
facet(__refs)728   _LIBCPP_HIDE_FROM_ABI explicit money_put(size_t __refs = 0) : locale::facet(__refs) {}
729 
730   _LIBCPP_HIDE_FROM_ABI iter_type
put(iter_type __s,bool __intl,ios_base & __iob,char_type __fl,long double __units)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
put(iter_type __s,bool __intl,ios_base & __iob,char_type __fl,const string_type & __digits)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 
742 protected:
~money_put()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 
750 template <class _CharT, class _OutputIterator>
751 locale::id money_put<_CharT, _OutputIterator>::id;
752 
753 template <class _CharT, class _OutputIterator>
do_put(iter_type __s,bool __intl,ios_base & __iob,char_type __fl,long double __units)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 
810 template <class _CharT, class _OutputIterator>
do_put(iter_type __s,bool __intl,ios_base & __iob,char_type __fl,const string_type & __digits)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 
862 extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS money_put<char>;
863 #  if _LIBCPP_HAS_WIDE_CHARACTERS
864 extern 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
874