1 // Locale support -*- C++ -*-
2 
3 // Copyright (C) 2014-2018 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 
46 namespace std _GLIBCXX_VISIBILITY(default)
47 {
48 _GLIBCXX_BEGIN_NAMESPACE_VERSION
49 
50   // Base class of facet shims, holds a reference to the underlying facet
51   // that the shim forwards to.
52   class locale::facet::__shim
53   {
54   public:
55     const facet* _M_get() const { return _M_facet; }
56 
57     __shim(const __shim&) = delete;
58     __shim& operator=(const __shim&) = delete;
59 
60   protected:
61     explicit
62     __shim(const facet* __f) : _M_facet(__f) { __f->_M_add_reference(); }
63 
64     ~__shim() { _M_facet->_M_remove_reference(); }
65 
66   private:
67     const facet* _M_facet;
68   };
69 
70 namespace __facet_shims
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 } // namespace __facet_shims
781 
782   // Create a new shim facet of type WHICH that forwards calls to F.
783   // F is the replacement facet provided by the user, WHICH is the ID of
784   // F's "other ABI twin" which we are replacing with a shim.
785   const locale::facet*
786 #if _GLIBCXX_USE_CXX11_ABI
787   locale::facet::_M_sso_shim(const locale::id* which) const
788 #else
789   locale::facet::_M_cow_shim(const locale::id* which) const
790 #endif
791   {
792     using namespace __facet_shims;
793 
794 #if __cpp_rtti
795     // If this is already a shim just use its underlying facet.
796     if (auto* p = dynamic_cast<const __shim*>(this))
797       return p->_M_get();
798 #endif
799 
800     if (which == &numpunct<char>::id)
801       return new numpunct_shim<char>{this};
802     if (which == &std::collate<char>::id)
803       return new collate_shim<char>{this};
804     if (which == &time_get<char>::id)
805       return new time_get_shim<char>{this};
806     if (which == &money_get<char>::id)
807       return new money_get_shim<char>{this};
808     if (which == &money_put<char>::id)
809       return new money_put_shim<char>{this};
810     if (which == &moneypunct<char, true>::id)
811       return new moneypunct_shim<char, true>{this};
812     if (which == &moneypunct<char, false>::id)
813       return new moneypunct_shim<char, false>{this};
814     if (which == &std::messages<char>::id)
815       return new messages_shim<char>{this};
816 #ifdef _GLIBCXX_USE_WCHAR_T
817     if (which == &numpunct<wchar_t>::id)
818       return new numpunct_shim<wchar_t>{this};
819     if (which == &std::collate<wchar_t>::id)
820       return new collate_shim<wchar_t>{this};
821     if (which == &time_get<wchar_t>::id)
822       return new time_get_shim<wchar_t>{this};
823     if (which == &money_get<wchar_t>::id)
824       return new money_get_shim<wchar_t>{this};
825     if (which == &money_put<wchar_t>::id)
826       return new money_put_shim<wchar_t>{this};
827     if (which == &moneypunct<wchar_t, true>::id)
828       return new moneypunct_shim<wchar_t, true>{this};
829     if (which == &moneypunct<wchar_t, false>::id)
830       return new moneypunct_shim<wchar_t, false>{this};
831     if (which == &std::messages<wchar_t>::id)
832       return new messages_shim<wchar_t>{this};
833 #endif
834     __throw_logic_error("cannot create shim for unknown locale::facet");
835   }
836 
837 _GLIBCXX_END_NAMESPACE_VERSION
838 } // namespace std
839