]>
Commit | Line | Data |
---|---|---|
34a2b755 JW |
1 | // Locale support -*- C++ -*- |
2 | ||
cbe34bb5 | 3 | // Copyright (C) 2014-2017 Free Software Foundation, Inc. |
34a2b755 JW |
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 | { | |
4a15d842 FD |
48 | _GLIBCXX_BEGIN_NAMESPACE_VERSION |
49 | ||
34a2b755 JW |
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 | { | |
34a2b755 JW |
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; | |
1b9ad1d9 | 90 | #ifdef _GLIBCXX_USE_WCHAR_T |
34a2b755 | 91 | wchar_t* _M_pwc; |
1b9ad1d9 | 92 | #endif |
34a2b755 JW |
93 | }; |
94 | size_t _M_len; | |
95 | char _M_unused[16]; | |
96 | ||
97 | operator const char*() const { return _M_pc; } | |
1b9ad1d9 | 98 | #ifdef _GLIBCXX_USE_WCHAR_T |
34a2b755 | 99 | operator const wchar_t*() const { return _M_pwc; } |
1b9ad1d9 | 100 | #endif |
34a2b755 JW |
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> | |
168ad5f5 | 150 | _GLIBCXX_DEFAULT_ABI_TAG |
34a2b755 JW |
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 | |
831a3a9e | 174 | __numpunct_fill_cache(other_abi, const facet*, __numpunct_cache<C>*); |
34a2b755 JW |
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 | { | |
b497fbc1 JW |
229 | struct __shim_accessor : facet |
230 | { | |
231 | using facet::__shim; // Redeclare protected member as public. | |
232 | }; | |
233 | using __shim = __shim_accessor::__shim; | |
234 | ||
34a2b755 | 235 | template<typename _CharT> |
b497fbc1 | 236 | struct numpunct_shim : std::numpunct<_CharT>, __shim |
34a2b755 JW |
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 | { | |
831a3a9e | 244 | __numpunct_fill_cache(other_abi{}, f, c); |
34a2b755 JW |
245 | } |
246 | ||
831a3a9e JW |
247 | ~numpunct_shim() |
248 | { | |
249 | // Stop GNU locale's ~numpunct() from freeing the cached string. | |
250 | _M_cache->_M_grouping_size = 0; | |
251 | } | |
34a2b755 | 252 | |
831a3a9e | 253 | // No need to override any virtual functions, the base definitions |
34a2b755 JW |
254 | // will return the cached data. |
255 | ||
256 | __cache_type* _M_cache; | |
34a2b755 JW |
257 | }; |
258 | ||
34a2b755 | 259 | template<typename _CharT> |
b497fbc1 | 260 | struct collate_shim : std::collate<_CharT>, __shim |
34a2b755 JW |
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 | ||
34a2b755 | 284 | template<typename _CharT> |
b497fbc1 | 285 | struct time_get_shim : std::time_get<_CharT>, __shim |
34a2b755 JW |
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> | |
b497fbc1 | 339 | struct moneypunct_shim : std::moneypunct<_CharT, _Intl>, __shim |
34a2b755 JW |
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 | { | |
831a3a9e | 352 | // Stop GNU locale's ~moneypunct() from freeing the cached strings. |
34a2b755 JW |
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 | ||
34a2b755 | 365 | template<typename _CharT> |
b497fbc1 | 366 | struct money_get_shim : std::money_get<_CharT>, __shim |
34a2b755 JW |
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 | ||
34a2b755 | 406 | template<typename _CharT> |
b497fbc1 | 407 | struct money_put_shim : std::money_put<_CharT>, __shim |
34a2b755 JW |
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 | ||
34a2b755 | 435 | template<typename _CharT> |
b497fbc1 | 436 | struct messages_shim : std::messages<_CharT>, __shim |
34a2b755 JW |
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 | ||
1b9ad1d9 JW |
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>; | |
34a2b755 | 473 | template class messages_shim<char>; |
1b9ad1d9 JW |
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>; | |
34a2b755 | 481 | template class messages_shim<wchar_t>; |
1b9ad1d9 | 482 | #endif |
34a2b755 JW |
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 | ||
831a3a9e JW |
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. | |
34a2b755 JW |
504 | template<typename C> |
505 | void | |
831a3a9e | 506 | __numpunct_fill_cache(current_abi, const facet* f, __numpunct_cache<C>* c) |
34a2b755 JW |
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 | ||
831a3a9e | 513 | c->_M_grouping = nullptr; |
34a2b755 JW |
514 | c->_M_truename = nullptr; |
515 | c->_M_falsename = nullptr; | |
516 | // set _M_allocated so that if any allocation fails the previously | |
831a3a9e | 517 | // allocated strings will be deleted in ~__numpunct_cache() |
34a2b755 JW |
518 | c->_M_allocated = true; |
519 | ||
831a3a9e | 520 | c->_M_grouping_size = __copy(c->_M_grouping, m->grouping()); |
34a2b755 JW |
521 | c->_M_truename_size = __copy(c->_M_truename, m->truename()); |
522 | c->_M_falsename_size = __copy(c->_M_falsename, m->falsename()); | |
34a2b755 JW |
523 | } |
524 | ||
525 | template void | |
831a3a9e | 526 | __numpunct_fill_cache(current_abi, const facet*, __numpunct_cache<char>*); |
34a2b755 | 527 | |
1b9ad1d9 | 528 | #ifdef _GLIBCXX_USE_WCHAR_T |
34a2b755 | 529 | template void |
831a3a9e | 530 | __numpunct_fill_cache(current_abi, const facet*, __numpunct_cache<wchar_t>*); |
1b9ad1d9 | 531 | #endif |
34a2b755 JW |
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 | ||
1b9ad1d9 | 545 | #ifdef _GLIBCXX_USE_WCHAR_T |
34a2b755 JW |
546 | template int |
547 | __collate_compare(current_abi, const facet*, const wchar_t*, const wchar_t*, | |
548 | const wchar_t*, const wchar_t*); | |
1b9ad1d9 | 549 | #endif |
34a2b755 JW |
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 | ||
1b9ad1d9 | 564 | #ifdef _GLIBCXX_USE_WCHAR_T |
34a2b755 JW |
565 | template void |
566 | __collate_transform(current_abi, const facet*, __any_string&, | |
567 | const wchar_t*, const wchar_t*); | |
1b9ad1d9 | 568 | #endif |
34a2b755 | 569 | |
831a3a9e JW |
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. | |
34a2b755 JW |
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; | |
831a3a9e JW |
588 | // Set _M_allocated so that if any allocation fails the previously |
589 | // allocated strings will be deleted in ~__moneypunct_cache(). | |
34a2b755 JW |
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 | ||
1b9ad1d9 | 611 | #ifdef _GLIBCXX_USE_WCHAR_T |
34a2b755 JW |
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>*); | |
1b9ad1d9 | 619 | #endif |
34a2b755 JW |
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 | ||
1b9ad1d9 | 635 | #ifdef _GLIBCXX_USE_WCHAR_T |
34a2b755 JW |
636 | template messages_base::catalog |
637 | __messages_open<wchar_t>(current_abi, const facet*, const char*, size_t, | |
638 | const locale&); | |
1b9ad1d9 | 639 | #endif |
34a2b755 JW |
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 | ||
1b9ad1d9 | 655 | #ifdef _GLIBCXX_USE_WCHAR_T |
34a2b755 JW |
656 | template void |
657 | __messages_get(current_abi, const facet*, __any_string&, | |
658 | messages_base::catalog, int, int, const wchar_t*, size_t); | |
1b9ad1d9 | 659 | #endif |
34a2b755 JW |
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 | ||
1b9ad1d9 | 671 | #ifdef _GLIBCXX_USE_WCHAR_T |
34a2b755 JW |
672 | template void |
673 | __messages_close<wchar_t>(current_abi, const facet*, | |
674 | messages_base::catalog c); | |
1b9ad1d9 | 675 | #endif |
34a2b755 JW |
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 | ||
1b9ad1d9 | 685 | #ifdef _GLIBCXX_USE_WCHAR_T |
34a2b755 JW |
686 | template time_base::dateorder |
687 | __time_get_dateorder<wchar_t>(current_abi, const facet*); | |
1b9ad1d9 | 688 | #endif |
34a2b755 JW |
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 | ||
1b9ad1d9 | 719 | #ifdef _GLIBCXX_USE_WCHAR_T |
34a2b755 JW |
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); | |
1b9ad1d9 | 724 | #endif |
34a2b755 JW |
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 | ||
1b9ad1d9 | 749 | #ifdef _GLIBCXX_USE_WCHAR_T |
34a2b755 JW |
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*); | |
1b9ad1d9 | 755 | #endif |
34a2b755 JW |
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 | ||
1b9ad1d9 | 774 | #ifdef _GLIBCXX_USE_WCHAR_T |
34a2b755 JW |
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*); | |
1b9ad1d9 | 778 | #endif |
34a2b755 | 779 | |
34a2b755 JW |
780 | } // namespace __facet_shims |
781 | ||
34a2b755 JW |
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 | ||
5e67acc9 | 794 | #if __cpp_rtti |
34a2b755 JW |
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(); | |
5e67acc9 | 798 | #endif |
34a2b755 JW |
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 |