cxx11-shim_facets.cc revision 1.3
1// Locale support -*- C++ -*-
2
3// Copyright (C) 2014-2017 Free Software Foundation, Inc.
4//
5// This file is part of the GNU ISO C++ Library.  This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23// <http://www.gnu.org/licenses/>.
24
25//
26// ISO C++ 14882: 22.1  Locales
27//
28
29// This file defines classes that behave like the standard predefined locale
30// facets (collate, money_get etc.) except that they forward all virtual
31// functions to another facet which uses a different std::string ABI,
32// converting between string types as needed.
33// When a user replaces one of the relevant facets the corresponding shim in
34// this file is used so that the replacement facet can be used (via the shim)
35// in code that uses the other std::string ABI from the replacing code.
36
37#ifndef _GLIBCXX_USE_CXX11_ABI
38# define _GLIBCXX_USE_CXX11_ABI 1
39#endif
40#include <locale>
41
42#if ! _GLIBCXX_USE_DUAL_ABI
43# error This file should not be compiled for this configuration.
44#endif
45
46namespace std _GLIBCXX_VISIBILITY(default)
47{
48  // Base class of facet shims, holds a reference to the underlying facet
49  // that the shim forwards to.
50  class locale::facet::__shim
51  {
52  public:
53    const facet* _M_get() const { return _M_facet; }
54
55    __shim(const __shim&) = delete;
56    __shim& operator=(const __shim&) = delete;
57
58  protected:
59    explicit
60    __shim(const facet* __f) : _M_facet(__f) { __f->_M_add_reference(); }
61
62    ~__shim() { _M_facet->_M_remove_reference(); }
63
64  private:
65    const facet* _M_facet;
66  };
67
68namespace __facet_shims
69{
70_GLIBCXX_BEGIN_NAMESPACE_VERSION
71
72  namespace // unnamed
73  {
74    template<typename C>
75      void __destroy_string(void* p)
76      {
77	static_cast<std::basic_string<C>*>(p)->~basic_string();
78      }
79  } // namespace
80
81  // Manages a buffer of uninitialized memory that can store a std::string
82  // or std::wstring, using either ABI, and convert to the other ABI.
83  class __any_string
84  {
85    struct __attribute__((may_alias)) __str_rep
86    {
87      union {
88	const void* _M_p;
89	char* _M_pc;
90#ifdef _GLIBCXX_USE_WCHAR_T
91	wchar_t* _M_pwc;
92#endif
93      };
94      size_t _M_len;
95      char _M_unused[16];
96
97      operator const char*() const { return _M_pc; }
98#ifdef _GLIBCXX_USE_WCHAR_T
99      operator const wchar_t*() const { return _M_pwc; }
100#endif
101    };
102    union {
103      __str_rep _M_str;
104      char _M_bytes[sizeof(__str_rep)];
105    };
106    using __dtor_func = void(*)(void*);
107    __dtor_func _M_dtor = nullptr;
108
109#if _GLIBCXX_USE_CXX11_ABI
110    // SSO strings overlay the entire __str_rep structure.
111    static_assert(sizeof(std::string) == sizeof(__str_rep),
112		  "std::string changed size!");
113#else
114    // COW strings overlay just the pointer, the length is stored manually.
115    static_assert(sizeof(std::string) == sizeof(__str_rep::_M_p),
116		  "std::string changed size!");
117#endif
118# ifdef _GLIBCXX_USE_WCHAR_T
119    static_assert(sizeof(std::wstring) == sizeof(std::string),
120		  "std::wstring and std::string are different sizes!");
121# endif
122
123  public:
124    __any_string() = default;
125    ~__any_string() { if (_M_dtor) _M_dtor(_M_bytes); }
126
127    __any_string(const __any_string&) = delete;
128    __any_string& operator=(const __any_string&) = delete;
129
130    // Store a string (and its length if needed) in the buffer and
131    // set _M_dtor to the function that runs the right destructor.
132    template<typename C>
133      __any_string&
134      operator=(const basic_string<C>& s)
135      {
136	if (_M_dtor)
137	  _M_dtor(_M_bytes);
138	::new(_M_bytes) basic_string<C>(s);
139#if ! _GLIBCXX_USE_CXX11_ABI
140	_M_str._M_len = s.length();
141#endif
142	_M_dtor = __destroy_string<C>;
143	return *this;
144      }
145
146    // Create a new string with a copy of the characters in the stored string.
147    // The returned object will match the caller's string ABI, even when the
148    // stored string doesn't.
149    template<typename C>
150      _GLIBCXX_DEFAULT_ABI_TAG
151      operator basic_string<C>() const
152      {
153	if (!_M_dtor)
154	  __throw_logic_error("uninitialized __any_string");
155	return basic_string<C>(static_cast<const C*>(_M_str), _M_str._M_len);
156      }
157  };
158
159  // This file is compiled twice, with and without this macro defined.
160  // Define tag types to distinguish between the two cases and to allow
161  // overloading on the tag.
162  using current_abi = __bool_constant<_GLIBCXX_USE_CXX11_ABI>;
163  using other_abi = __bool_constant<!_GLIBCXX_USE_CXX11_ABI>;
164
165  using facet = locale::facet;
166
167  // Declare the functions that shims defined in this file will call to
168  // perform work in the context of the other ABI.
169  // These will be defined when this file is recompiled for the other ABI
170  // (at which point what is now "current_abi" will become "other_abi").
171
172  template<typename C>
173    void
174    __numpunct_fill_cache(other_abi, const facet*, __numpunct_cache<C>*);
175
176  template<typename C>
177    int
178    __collate_compare(other_abi, const facet*, const C*, const C*,
179		      const C*, const C*);
180
181  template<typename C>
182    void
183    __collate_transform(other_abi, const facet*, __any_string&,
184			const C*, const C*);
185
186  template<typename C>
187    time_base::dateorder
188    __time_get_dateorder(other_abi, const facet* f);
189
190  template<typename C>
191    istreambuf_iterator<C>
192    __time_get(other_abi, const facet* f,
193	       istreambuf_iterator<C> beg, istreambuf_iterator<C> end,
194	       ios_base& io, ios_base::iostate& err, tm* t, char which);
195
196  template<typename C, bool Intl>
197    void
198    __moneypunct_fill_cache(other_abi, const facet*,
199			    __moneypunct_cache<C, Intl>*);
200
201  template<typename C>
202    istreambuf_iterator<C>
203    __money_get(other_abi, const facet*,
204		istreambuf_iterator<C>, istreambuf_iterator<C>,
205		bool, ios_base&, ios_base::iostate&,
206		long double*, __any_string*);
207
208  template<typename C>
209    ostreambuf_iterator<C>
210    __money_put(other_abi, const facet*, ostreambuf_iterator<C>, bool,
211		ios_base&, C, long double, const __any_string*);
212
213  template<typename C>
214    messages_base::catalog
215    __messages_open(other_abi, const facet*, const char*, size_t,
216		    const locale&);
217
218  template<typename C>
219    void
220    __messages_get(other_abi, const facet*, __any_string&,
221		   messages_base::catalog, int, int, const C*, size_t);
222
223  template<typename C>
224    void
225    __messages_close(other_abi, const facet*, messages_base::catalog);
226
227  namespace // unnamed
228  {
229    struct __shim_accessor : facet
230    {
231      using facet::__shim;  // Redeclare protected member as public.
232    };
233    using __shim = __shim_accessor::__shim;
234
235    template<typename _CharT>
236      struct numpunct_shim : std::numpunct<_CharT>, __shim
237      {
238	typedef typename numpunct<_CharT>::__cache_type __cache_type;
239
240	// f must point to a type derived from numpunct<C>[abi:other]
241	numpunct_shim(const facet* f, __cache_type* c = new __cache_type)
242	: std::numpunct<_CharT>(c), __shim(f), _M_cache(c)
243	{
244	  __numpunct_fill_cache(other_abi{}, f, c);
245	}
246
247	~numpunct_shim()
248	{
249	  // Stop GNU locale's ~numpunct() from freeing the cached string.
250	  _M_cache->_M_grouping_size = 0;
251	}
252
253	// No need to override any virtual functions, the base definitions
254	// will return the cached data.
255
256	__cache_type* _M_cache;
257      };
258
259    template<typename _CharT>
260      struct collate_shim : std::collate<_CharT>, __shim
261      {
262	typedef basic_string<_CharT>	string_type;
263
264	// f must point to a type derived from collate<C>[abi:other]
265	collate_shim(const facet* f) : __shim(f) { }
266
267	virtual int
268	do_compare(const _CharT* lo1, const _CharT* hi1,
269		   const _CharT* lo2, const _CharT* hi2) const
270	{
271	  return __collate_compare(other_abi{}, _M_get(),
272				   lo1, hi1, lo2, hi2);
273	}
274
275	virtual string_type
276	do_transform(const _CharT* lo, const _CharT* hi) const
277	{
278	  __any_string st;
279	  __collate_transform(other_abi{}, _M_get(), st, lo, hi);
280	  return st;
281	}
282      };
283
284    template<typename _CharT>
285      struct time_get_shim : std::time_get<_CharT>, __shim
286      {
287	typedef typename std::time_get<_CharT>::iter_type iter_type;
288	typedef typename std::time_get<_CharT>::char_type char_type;
289
290	// f must point to a type derived from time_get<C>[abi:other]
291	time_get_shim(const facet* f) : __shim(f) { }
292
293	virtual time_base::dateorder
294	do_date_order() const
295	{ return __time_get_dateorder<_CharT>(other_abi{}, _M_get()); }
296
297	virtual iter_type
298	do_get_time(iter_type beg, iter_type end, ios_base& io,
299		    ios_base::iostate& err, tm* t) const
300	{
301	  return __time_get(other_abi{}, _M_get(), beg, end, io, err, t,
302			    't');
303	}
304
305	virtual iter_type
306	do_get_date(iter_type beg, iter_type end, ios_base& io,
307		    ios_base::iostate& err, tm* t) const
308	{
309	  return __time_get(other_abi{}, _M_get(), beg, end, io, err, t,
310			    'd');
311	}
312
313	virtual iter_type
314	do_get_weekday(iter_type beg, iter_type end, ios_base& io,
315		       ios_base::iostate& err, tm* t) const
316	{
317	  return __time_get(other_abi{}, _M_get(), beg, end, io, err, t,
318			    'w');
319	}
320
321	virtual iter_type
322	do_get_monthname(iter_type beg, iter_type end, ios_base& io,
323			 ios_base::iostate& err, tm* t) const
324	{
325	  return __time_get(other_abi{}, _M_get(), beg, end, io, err, t,
326			    'm');
327	}
328
329	virtual iter_type
330	do_get_year(iter_type beg, iter_type end, ios_base& io,
331		    ios_base::iostate& err, tm* t) const
332	{
333	  return __time_get(other_abi{}, _M_get(), beg, end, io, err, t,
334			    'y');
335	}
336      };
337
338    template<typename _CharT, bool _Intl>
339      struct moneypunct_shim : std::moneypunct<_CharT, _Intl>, __shim
340      {
341	typedef typename moneypunct<_CharT, _Intl>::__cache_type __cache_type;
342
343	// f must point to a type derived from moneypunct<C>[abi:other]
344	moneypunct_shim(const facet* f, __cache_type* c = new __cache_type)
345	: std::moneypunct<_CharT, _Intl>(c), __shim(f), _M_cache(c)
346	{
347	  __moneypunct_fill_cache(other_abi{}, f, c);
348	}
349
350	~moneypunct_shim()
351	{
352	  // Stop GNU locale's ~moneypunct() from freeing the cached strings.
353	  _M_cache->_M_grouping_size = 0;
354	  _M_cache->_M_curr_symbol_size = 0;
355	  _M_cache->_M_positive_sign_size = 0;
356	  _M_cache->_M_negative_sign_size = 0;
357	}
358
359	// No need to override any virtual functions, the base definitions
360	// will return the cached data.
361
362	__cache_type* _M_cache;
363      };
364
365    template<typename _CharT>
366      struct money_get_shim : std::money_get<_CharT>, __shim
367      {
368	typedef typename std::money_get<_CharT>::iter_type iter_type;
369	typedef typename std::money_get<_CharT>::char_type char_type;
370	typedef typename std::money_get<_CharT>::string_type string_type;
371
372	// f must point to a type derived from money_get<C>[abi:other]
373	money_get_shim(const facet* f) : __shim(f) { }
374
375	virtual iter_type
376	do_get(iter_type s, iter_type end, bool intl, ios_base& io,
377	       ios_base::iostate& err, long double& units) const
378	{
379	  ios_base::iostate err2 = ios_base::goodbit;
380	  long double units2;
381	  s = __money_get(other_abi{}, _M_get(), s, end, intl, io, err2,
382			  &units2, nullptr);
383	  if (err2 == ios_base::goodbit)
384	    units = units2;
385	  else
386	    err = err2;
387	  return s;
388	}
389
390	virtual iter_type
391	do_get(iter_type s, iter_type end, bool intl, ios_base& io,
392	       ios_base::iostate& err, string_type& digits) const
393	{
394	  __any_string st;
395	  ios_base::iostate err2 = ios_base::goodbit;
396	  s = __money_get(other_abi{}, _M_get(), s, end, intl, io, err2,
397			  nullptr, &st);
398	  if (err2 == ios_base::goodbit)
399	    digits = st;
400	  else
401	    err = err2;
402	  return s;
403	}
404      };
405
406    template<typename _CharT>
407      struct money_put_shim : std::money_put<_CharT>, __shim
408      {
409	typedef typename std::money_put<_CharT>::iter_type iter_type;
410	typedef typename std::money_put<_CharT>::char_type char_type;
411	typedef typename std::money_put<_CharT>::string_type string_type;
412
413	// f must point to a type derived from money_put<C>[abi:other]
414	money_put_shim(const facet* f) : __shim(f) { }
415
416	virtual iter_type
417	do_put(iter_type s, bool intl, ios_base& io,
418	       char_type fill, long double units) const
419	{
420	  return __money_put(other_abi{}, _M_get(), s, intl, io, fill, units,
421			     nullptr);
422	}
423
424	virtual iter_type
425	do_put(iter_type s, bool intl, ios_base& io,
426	       char_type fill, const string_type& digits) const
427	{
428	  __any_string st;
429	  st = digits;
430	  return __money_put(other_abi{}, _M_get(), s, intl, io, fill, 0.L,
431			     &st);
432	}
433      };
434
435    template<typename _CharT>
436      struct messages_shim : std::messages<_CharT>, __shim
437      {
438	typedef messages_base::catalog  catalog;
439	typedef basic_string<_CharT>	string_type;
440
441	// f must point to a type derived from messages<C>[abi:other]
442	messages_shim(const facet* f) : __shim(f) { }
443
444	virtual catalog
445	do_open(const basic_string<char>& s, const locale& l) const
446	{
447	  return __messages_open<_CharT>(other_abi{}, _M_get(),
448					 s.c_str(), s.size(), l);
449	}
450
451	virtual string_type
452	do_get(catalog c, int set, int msgid, const string_type& dfault) const
453	{
454	  __any_string st;
455	  __messages_get(other_abi{}, _M_get(), st, c, set, msgid,
456			 dfault.c_str(), dfault.size());
457	  return st;
458	}
459
460	virtual void
461	do_close(catalog c) const
462	{
463	  __messages_close<_CharT>(other_abi{}, _M_get(), c);
464	}
465      };
466
467    template class numpunct_shim<char>;
468    template class collate_shim<char>;
469    template class moneypunct_shim<char, true>;
470    template class moneypunct_shim<char, false>;
471    template class money_get_shim<char>;
472    template class money_put_shim<char>;
473    template class messages_shim<char>;
474#ifdef _GLIBCXX_USE_WCHAR_T
475    template class numpunct_shim<wchar_t>;
476    template class collate_shim<wchar_t>;
477    template class moneypunct_shim<wchar_t, true>;
478    template class moneypunct_shim<wchar_t, false>;
479    template class money_get_shim<wchar_t>;
480    template class money_put_shim<wchar_t>;
481    template class messages_shim<wchar_t>;
482#endif
483
484    template<typename C>
485      inline size_t
486      __copy(const C*& dest, const basic_string<C>& s)
487      {
488	auto len = s.length();
489	C* p = new C[len+1];
490	s.copy(p, len);
491	p[len] = '\0';
492	dest = p;
493	return len;
494      }
495
496  } // namespace
497
498  // Now define and instantiate the functions that will be called by the
499  // shim facets defined when this file is recompiled for the other ABI.
500
501  // Cache the values returned by the numpunct facet f.
502  // Sets c->_M_allocated so that the __numpunct_cache destructor will
503  // delete[] the strings allocated by this function.
504  template<typename C>
505    void
506    __numpunct_fill_cache(current_abi, const facet* f, __numpunct_cache<C>* c)
507    {
508      auto* m = static_cast<const numpunct<C>*>(f);
509
510      c->_M_decimal_point = m->decimal_point();
511      c->_M_thousands_sep = m->thousands_sep();
512
513      c->_M_grouping = nullptr;
514      c->_M_truename = nullptr;
515      c->_M_falsename = nullptr;
516      // set _M_allocated so that if any allocation fails the previously
517      // allocated strings will be deleted in ~__numpunct_cache()
518      c->_M_allocated = true;
519
520      c->_M_grouping_size = __copy(c->_M_grouping, m->grouping());
521      c->_M_truename_size = __copy(c->_M_truename, m->truename());
522      c->_M_falsename_size = __copy(c->_M_falsename, m->falsename());
523    }
524
525  template void
526  __numpunct_fill_cache(current_abi, const facet*, __numpunct_cache<char>*);
527
528#ifdef _GLIBCXX_USE_WCHAR_T
529  template void
530  __numpunct_fill_cache(current_abi, const facet*, __numpunct_cache<wchar_t>*);
531#endif
532
533  template<typename C>
534    int
535    __collate_compare(current_abi, const facet* f, const C* lo1, const C* hi1,
536		      const C* lo2, const C* hi2)
537    {
538      return static_cast<const collate<C>*>(f)->compare(lo1, hi1, lo2, hi2);
539    }
540
541  template int
542  __collate_compare(current_abi, const facet*, const char*, const char*,
543		    const char*, const char*);
544
545#ifdef _GLIBCXX_USE_WCHAR_T
546  template int
547  __collate_compare(current_abi, const facet*, const wchar_t*, const wchar_t*,
548		    const wchar_t*, const wchar_t*);
549#endif
550
551  template<typename C>
552    void
553    __collate_transform(current_abi, const facet* f, __any_string& st,
554			const C* __lo, const C* __hi)
555    {
556      auto* c = static_cast<const collate<C>*>(f);
557      st = c->transform(__lo, __hi);
558    }
559
560  template void
561  __collate_transform(current_abi, const facet*, __any_string&,
562		      const char*, const char*);
563
564#ifdef _GLIBCXX_USE_WCHAR_T
565  template void
566  __collate_transform(current_abi, const facet*, __any_string&,
567		      const wchar_t*, const wchar_t*);
568#endif
569
570  // Cache the values returned by the moneypunct facet, f.
571  // Sets c->_M_allocated so that the __moneypunct_cache destructor will
572  // delete[] the strings allocated by this function.
573  template<typename C, bool Intl>
574    void
575    __moneypunct_fill_cache(current_abi, const facet* f,
576			    __moneypunct_cache<C, Intl>* c)
577    {
578      auto* m = static_cast<const moneypunct<C, Intl>*>(f);
579
580      c->_M_decimal_point = m->decimal_point();
581      c->_M_thousands_sep = m->thousands_sep();
582      c->_M_frac_digits = m->frac_digits();
583
584      c->_M_grouping = nullptr;
585      c->_M_curr_symbol = nullptr;
586      c->_M_positive_sign = nullptr;
587      c->_M_negative_sign = nullptr;
588      // Set _M_allocated so that if any allocation fails the previously
589      // allocated strings will be deleted in ~__moneypunct_cache().
590      c->_M_allocated = true;
591
592      c->_M_grouping_size = __copy(c->_M_grouping, m->grouping());
593      c->_M_curr_symbol_size = __copy(c->_M_curr_symbol, m->curr_symbol());
594      c->_M_positive_sign_size
595	= __copy(c->_M_positive_sign, m->positive_sign());
596      c->_M_negative_sign_size
597	= __copy(c->_M_negative_sign, m->negative_sign());
598
599      c->_M_pos_format = m->pos_format();
600      c->_M_neg_format = m->neg_format();
601    }
602
603  template void
604  __moneypunct_fill_cache(current_abi, const facet*,
605			  __moneypunct_cache<char, true>*);
606
607  template void
608  __moneypunct_fill_cache(current_abi, const facet*,
609			  __moneypunct_cache<char, false>*);
610
611#ifdef _GLIBCXX_USE_WCHAR_T
612  template void
613  __moneypunct_fill_cache(current_abi, const facet*,
614			  __moneypunct_cache<wchar_t, true>*);
615
616  template void
617  __moneypunct_fill_cache(current_abi, const facet*,
618			  __moneypunct_cache<wchar_t, false>*);
619#endif
620
621  template<typename C>
622    messages_base::catalog
623    __messages_open(current_abi, const facet* f, const char* s, size_t n,
624		    const locale& l)
625    {
626      auto* m = static_cast<const messages<C>*>(f);
627      string str(s, n);
628      return m->open(str, l);
629    }
630
631  template messages_base::catalog
632  __messages_open<char>(current_abi, const facet*, const char*, size_t,
633			const locale&);
634
635#ifdef _GLIBCXX_USE_WCHAR_T
636  template messages_base::catalog
637  __messages_open<wchar_t>(current_abi, const facet*, const char*, size_t,
638			   const locale&);
639#endif
640
641  template<typename C>
642    void
643    __messages_get(current_abi, const facet* f, __any_string& st,
644		   messages_base::catalog c, int set, int msgid,
645		   const C* s, size_t n)
646    {
647      auto* m = static_cast<const messages<C>*>(f);
648      st = m->get(c, set, msgid, basic_string<C>(s, n));
649    }
650
651  template void
652  __messages_get(current_abi, const facet*, __any_string&,
653		 messages_base::catalog, int, int, const char*, size_t);
654
655#ifdef _GLIBCXX_USE_WCHAR_T
656  template void
657  __messages_get(current_abi, const facet*, __any_string&,
658		 messages_base::catalog, int, int, const wchar_t*, size_t);
659#endif
660
661  template<typename C>
662    void
663    __messages_close(current_abi, const facet* f, messages_base::catalog c)
664    {
665      static_cast<const messages<C>*>(f)->close(c);
666    }
667
668  template void
669  __messages_close<char>(current_abi, const facet*, messages_base::catalog c);
670
671#ifdef _GLIBCXX_USE_WCHAR_T
672  template void
673  __messages_close<wchar_t>(current_abi, const facet*,
674			    messages_base::catalog c);
675#endif
676
677  template<typename C>
678    time_base::dateorder
679    __time_get_dateorder(current_abi, const facet* f)
680    { return static_cast<const time_get<C>*>(f)->date_order(); }
681
682  template time_base::dateorder
683  __time_get_dateorder<char>(current_abi, const facet*);
684
685#ifdef _GLIBCXX_USE_WCHAR_T
686  template time_base::dateorder
687  __time_get_dateorder<wchar_t>(current_abi, const facet*);
688#endif
689
690  template<typename C>
691    istreambuf_iterator<C>
692    __time_get(current_abi, const facet* f,
693	       istreambuf_iterator<C> beg, istreambuf_iterator<C> end,
694	       ios_base& io, ios_base::iostate& err, tm* t, char which)
695    {
696      auto* g = static_cast<const time_get<C>*>(f);
697      switch(which)
698      {
699      case 't':
700	return g->get_time(beg, end, io, err, t);
701      case 'd':
702	return g->get_date(beg, end, io, err, t);
703      case 'w':
704	return g->get_weekday(beg, end, io, err, t);
705      case 'm':
706	return g->get_monthname(beg, end, io, err, t);
707      case 'y':
708	return g->get_year(beg, end, io, err, t);
709      default:
710	__builtin_unreachable();
711      }
712    }
713
714  template istreambuf_iterator<char>
715  __time_get(current_abi, const facet*,
716	     istreambuf_iterator<char>, istreambuf_iterator<char>,
717	     ios_base&, ios_base::iostate&, tm*, char);
718
719#ifdef _GLIBCXX_USE_WCHAR_T
720  template istreambuf_iterator<wchar_t>
721  __time_get(current_abi, const facet*,
722	     istreambuf_iterator<wchar_t>, istreambuf_iterator<wchar_t>,
723	     ios_base&, ios_base::iostate&, tm*, char);
724#endif
725
726  template<typename C>
727    istreambuf_iterator<C>
728    __money_get(current_abi, const facet* f,
729		istreambuf_iterator<C> s, istreambuf_iterator<C> end,
730		bool intl, ios_base& str, ios_base::iostate& err,
731		long double* units, __any_string* digits)
732    {
733      auto* m = static_cast<const money_get<C>*>(f);
734      if (units)
735	return m->get(s, end, intl, str, err, *units);
736      basic_string<C> digits2;
737      s = m->get(s, end, intl, str, err, digits2);
738      if (err == ios_base::goodbit)
739	*digits = digits2;
740      return s;
741    }
742
743  template istreambuf_iterator<char>
744  __money_get(current_abi, const facet*,
745	      istreambuf_iterator<char>, istreambuf_iterator<char>,
746	      bool, ios_base&, ios_base::iostate&,
747	      long double*, __any_string*);
748
749#ifdef _GLIBCXX_USE_WCHAR_T
750  template istreambuf_iterator<wchar_t>
751  __money_get(current_abi, const facet*,
752	      istreambuf_iterator<wchar_t>, istreambuf_iterator<wchar_t>,
753	      bool, ios_base&, ios_base::iostate&,
754	      long double*, __any_string*);
755#endif
756
757  template<typename C>
758    ostreambuf_iterator<C>
759    __money_put(current_abi, const facet* f, ostreambuf_iterator<C> s,
760		bool intl, ios_base& io, C fill, long double units,
761		const __any_string* digits)
762    {
763      auto* m = static_cast<const money_put<C>*>(f);
764      if (digits)
765	return m->put(s, intl, io, fill, *digits);
766      else
767	return m->put(s, intl, io, fill, units);
768    }
769
770  template ostreambuf_iterator<char>
771  __money_put(current_abi, const facet*, ostreambuf_iterator<char>,
772		bool, ios_base&, char, long double, const __any_string*);
773
774#ifdef _GLIBCXX_USE_WCHAR_T
775  template ostreambuf_iterator<wchar_t>
776  __money_put(current_abi, const facet*, ostreambuf_iterator<wchar_t>,
777		bool, ios_base&, wchar_t, long double, const __any_string*);
778#endif
779
780_GLIBCXX_END_NAMESPACE_VERSION
781} // namespace __facet_shims
782
783_GLIBCXX_BEGIN_NAMESPACE_VERSION
784  // Create a new shim facet of type WHICH that forwards calls to F.
785  // F is the replacement facet provided by the user, WHICH is the ID of
786  // F's "other ABI twin" which we are replacing with a shim.
787  const locale::facet*
788#if _GLIBCXX_USE_CXX11_ABI
789  locale::facet::_M_sso_shim(const locale::id* which) const
790#else
791  locale::facet::_M_cow_shim(const locale::id* which) const
792#endif
793  {
794    using namespace __facet_shims;
795
796#if __cpp_rtti
797    // If this is already a shim just use its underlying facet.
798    if (auto* p = dynamic_cast<const __shim*>(this))
799      return p->_M_get();
800#endif
801
802    if (which == &numpunct<char>::id)
803      return new numpunct_shim<char>{this};
804    if (which == &std::collate<char>::id)
805      return new collate_shim<char>{this};
806    if (which == &time_get<char>::id)
807      return new time_get_shim<char>{this};
808    if (which == &money_get<char>::id)
809      return new money_get_shim<char>{this};
810    if (which == &money_put<char>::id)
811      return new money_put_shim<char>{this};
812    if (which == &moneypunct<char, true>::id)
813      return new moneypunct_shim<char, true>{this};
814    if (which == &moneypunct<char, false>::id)
815      return new moneypunct_shim<char, false>{this};
816    if (which == &std::messages<char>::id)
817      return new messages_shim<char>{this};
818#ifdef _GLIBCXX_USE_WCHAR_T
819    if (which == &numpunct<wchar_t>::id)
820      return new numpunct_shim<wchar_t>{this};
821    if (which == &std::collate<wchar_t>::id)
822      return new collate_shim<wchar_t>{this};
823    if (which == &time_get<wchar_t>::id)
824      return new time_get_shim<wchar_t>{this};
825    if (which == &money_get<wchar_t>::id)
826      return new money_get_shim<wchar_t>{this};
827    if (which == &money_put<wchar_t>::id)
828      return new money_put_shim<wchar_t>{this};
829    if (which == &moneypunct<wchar_t, true>::id)
830      return new moneypunct_shim<wchar_t, true>{this};
831    if (which == &moneypunct<wchar_t, false>::id)
832      return new moneypunct_shim<wchar_t, false>{this};
833    if (which == &std::messages<wchar_t>::id)
834      return new messages_shim<wchar_t>{this};
835#endif
836    __throw_logic_error("cannot create shim for unknown locale::facet");
837  }
838
839_GLIBCXX_END_NAMESPACE_VERSION
840} // namespace std
841