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