]>
Commit | Line | Data |
---|---|---|
34a2b755 JW |
1 | // Locale support -*- C++ -*- |
2 | ||
83ffe9cd | 3 | // Copyright (C) 2014-2023 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 | ||
f9bd185f JW |
227 | #pragma GCC diagnostic push |
228 | // Suppress -Wabi=2 warnings due to empty struct argument passing changes. | |
229 | // TODO This should use -Wabi=12 but that currently fails (PR c++/87611). | |
230 | #pragma GCC diagnostic ignored "-Wabi" | |
231 | ||
34a2b755 JW |
232 | namespace // unnamed |
233 | { | |
b497fbc1 JW |
234 | struct __shim_accessor : facet |
235 | { | |
236 | using facet::__shim; // Redeclare protected member as public. | |
237 | }; | |
238 | using __shim = __shim_accessor::__shim; | |
239 | ||
34a2b755 | 240 | template<typename _CharT> |
b497fbc1 | 241 | struct numpunct_shim : std::numpunct<_CharT>, __shim |
34a2b755 JW |
242 | { |
243 | typedef typename numpunct<_CharT>::__cache_type __cache_type; | |
244 | ||
245 | // f must point to a type derived from numpunct<C>[abi:other] | |
246 | numpunct_shim(const facet* f, __cache_type* c = new __cache_type) | |
247 | : std::numpunct<_CharT>(c), __shim(f), _M_cache(c) | |
248 | { | |
831a3a9e | 249 | __numpunct_fill_cache(other_abi{}, f, c); |
34a2b755 JW |
250 | } |
251 | ||
831a3a9e JW |
252 | ~numpunct_shim() |
253 | { | |
254 | // Stop GNU locale's ~numpunct() from freeing the cached string. | |
255 | _M_cache->_M_grouping_size = 0; | |
256 | } | |
34a2b755 | 257 | |
831a3a9e | 258 | // No need to override any virtual functions, the base definitions |
34a2b755 JW |
259 | // will return the cached data. |
260 | ||
261 | __cache_type* _M_cache; | |
34a2b755 JW |
262 | }; |
263 | ||
34a2b755 | 264 | template<typename _CharT> |
b497fbc1 | 265 | struct collate_shim : std::collate<_CharT>, __shim |
34a2b755 JW |
266 | { |
267 | typedef basic_string<_CharT> string_type; | |
268 | ||
269 | // f must point to a type derived from collate<C>[abi:other] | |
270 | collate_shim(const facet* f) : __shim(f) { } | |
271 | ||
272 | virtual int | |
273 | do_compare(const _CharT* lo1, const _CharT* hi1, | |
274 | const _CharT* lo2, const _CharT* hi2) const | |
275 | { | |
276 | return __collate_compare(other_abi{}, _M_get(), | |
277 | lo1, hi1, lo2, hi2); | |
278 | } | |
279 | ||
280 | virtual string_type | |
281 | do_transform(const _CharT* lo, const _CharT* hi) const | |
282 | { | |
283 | __any_string st; | |
284 | __collate_transform(other_abi{}, _M_get(), st, lo, hi); | |
285 | return st; | |
286 | } | |
287 | }; | |
288 | ||
34a2b755 | 289 | template<typename _CharT> |
b497fbc1 | 290 | struct time_get_shim : std::time_get<_CharT>, __shim |
34a2b755 JW |
291 | { |
292 | typedef typename std::time_get<_CharT>::iter_type iter_type; | |
293 | typedef typename std::time_get<_CharT>::char_type char_type; | |
294 | ||
295 | // f must point to a type derived from time_get<C>[abi:other] | |
296 | time_get_shim(const facet* f) : __shim(f) { } | |
297 | ||
298 | virtual time_base::dateorder | |
299 | do_date_order() const | |
300 | { return __time_get_dateorder<_CharT>(other_abi{}, _M_get()); } | |
301 | ||
302 | virtual iter_type | |
303 | do_get_time(iter_type beg, iter_type end, ios_base& io, | |
304 | ios_base::iostate& err, tm* t) const | |
305 | { | |
306 | return __time_get(other_abi{}, _M_get(), beg, end, io, err, t, | |
307 | 't'); | |
308 | } | |
309 | ||
310 | virtual iter_type | |
311 | do_get_date(iter_type beg, iter_type end, ios_base& io, | |
312 | ios_base::iostate& err, tm* t) const | |
313 | { | |
314 | return __time_get(other_abi{}, _M_get(), beg, end, io, err, t, | |
315 | 'd'); | |
316 | } | |
317 | ||
318 | virtual iter_type | |
319 | do_get_weekday(iter_type beg, iter_type end, ios_base& io, | |
320 | ios_base::iostate& err, tm* t) const | |
321 | { | |
322 | return __time_get(other_abi{}, _M_get(), beg, end, io, err, t, | |
323 | 'w'); | |
324 | } | |
325 | ||
326 | virtual iter_type | |
327 | do_get_monthname(iter_type beg, iter_type end, ios_base& io, | |
328 | ios_base::iostate& err, tm* t) const | |
329 | { | |
330 | return __time_get(other_abi{}, _M_get(), beg, end, io, err, t, | |
331 | 'm'); | |
332 | } | |
333 | ||
334 | virtual iter_type | |
335 | do_get_year(iter_type beg, iter_type end, ios_base& io, | |
336 | ios_base::iostate& err, tm* t) const | |
337 | { | |
338 | return __time_get(other_abi{}, _M_get(), beg, end, io, err, t, | |
339 | 'y'); | |
340 | } | |
341 | }; | |
342 | ||
343 | template<typename _CharT, bool _Intl> | |
b497fbc1 | 344 | struct moneypunct_shim : std::moneypunct<_CharT, _Intl>, __shim |
34a2b755 JW |
345 | { |
346 | typedef typename moneypunct<_CharT, _Intl>::__cache_type __cache_type; | |
347 | ||
348 | // f must point to a type derived from moneypunct<C>[abi:other] | |
349 | moneypunct_shim(const facet* f, __cache_type* c = new __cache_type) | |
350 | : std::moneypunct<_CharT, _Intl>(c), __shim(f), _M_cache(c) | |
351 | { | |
352 | __moneypunct_fill_cache(other_abi{}, f, c); | |
353 | } | |
354 | ||
355 | ~moneypunct_shim() | |
356 | { | |
831a3a9e | 357 | // Stop GNU locale's ~moneypunct() from freeing the cached strings. |
34a2b755 JW |
358 | _M_cache->_M_grouping_size = 0; |
359 | _M_cache->_M_curr_symbol_size = 0; | |
360 | _M_cache->_M_positive_sign_size = 0; | |
361 | _M_cache->_M_negative_sign_size = 0; | |
362 | } | |
363 | ||
364 | // No need to override any virtual functions, the base definitions | |
365 | // will return the cached data. | |
366 | ||
367 | __cache_type* _M_cache; | |
368 | }; | |
369 | ||
34a2b755 | 370 | template<typename _CharT> |
b497fbc1 | 371 | struct money_get_shim : std::money_get<_CharT>, __shim |
34a2b755 JW |
372 | { |
373 | typedef typename std::money_get<_CharT>::iter_type iter_type; | |
374 | typedef typename std::money_get<_CharT>::char_type char_type; | |
375 | typedef typename std::money_get<_CharT>::string_type string_type; | |
376 | ||
377 | // f must point to a type derived from money_get<C>[abi:other] | |
378 | money_get_shim(const facet* f) : __shim(f) { } | |
379 | ||
380 | virtual iter_type | |
381 | do_get(iter_type s, iter_type end, bool intl, ios_base& io, | |
382 | ios_base::iostate& err, long double& units) const | |
383 | { | |
384 | ios_base::iostate err2 = ios_base::goodbit; | |
385 | long double units2; | |
386 | s = __money_get(other_abi{}, _M_get(), s, end, intl, io, err2, | |
387 | &units2, nullptr); | |
388 | if (err2 == ios_base::goodbit) | |
389 | units = units2; | |
390 | else | |
391 | err = err2; | |
392 | return s; | |
393 | } | |
394 | ||
395 | virtual iter_type | |
396 | do_get(iter_type s, iter_type end, bool intl, ios_base& io, | |
397 | ios_base::iostate& err, string_type& digits) const | |
398 | { | |
399 | __any_string st; | |
400 | ios_base::iostate err2 = ios_base::goodbit; | |
401 | s = __money_get(other_abi{}, _M_get(), s, end, intl, io, err2, | |
402 | nullptr, &st); | |
403 | if (err2 == ios_base::goodbit) | |
404 | digits = st; | |
405 | else | |
406 | err = err2; | |
407 | return s; | |
408 | } | |
409 | }; | |
410 | ||
34a2b755 | 411 | template<typename _CharT> |
b497fbc1 | 412 | struct money_put_shim : std::money_put<_CharT>, __shim |
34a2b755 JW |
413 | { |
414 | typedef typename std::money_put<_CharT>::iter_type iter_type; | |
415 | typedef typename std::money_put<_CharT>::char_type char_type; | |
416 | typedef typename std::money_put<_CharT>::string_type string_type; | |
417 | ||
418 | // f must point to a type derived from money_put<C>[abi:other] | |
419 | money_put_shim(const facet* f) : __shim(f) { } | |
420 | ||
421 | virtual iter_type | |
422 | do_put(iter_type s, bool intl, ios_base& io, | |
423 | char_type fill, long double units) const | |
424 | { | |
425 | return __money_put(other_abi{}, _M_get(), s, intl, io, fill, units, | |
426 | nullptr); | |
427 | } | |
428 | ||
429 | virtual iter_type | |
430 | do_put(iter_type s, bool intl, ios_base& io, | |
431 | char_type fill, const string_type& digits) const | |
432 | { | |
433 | __any_string st; | |
434 | st = digits; | |
435 | return __money_put(other_abi{}, _M_get(), s, intl, io, fill, 0.L, | |
436 | &st); | |
437 | } | |
438 | }; | |
439 | ||
34a2b755 | 440 | template<typename _CharT> |
b497fbc1 | 441 | struct messages_shim : std::messages<_CharT>, __shim |
34a2b755 JW |
442 | { |
443 | typedef messages_base::catalog catalog; | |
444 | typedef basic_string<_CharT> string_type; | |
445 | ||
446 | // f must point to a type derived from messages<C>[abi:other] | |
447 | messages_shim(const facet* f) : __shim(f) { } | |
448 | ||
449 | virtual catalog | |
450 | do_open(const basic_string<char>& s, const locale& l) const | |
451 | { | |
452 | return __messages_open<_CharT>(other_abi{}, _M_get(), | |
453 | s.c_str(), s.size(), l); | |
454 | } | |
455 | ||
456 | virtual string_type | |
457 | do_get(catalog c, int set, int msgid, const string_type& dfault) const | |
458 | { | |
459 | __any_string st; | |
460 | __messages_get(other_abi{}, _M_get(), st, c, set, msgid, | |
461 | dfault.c_str(), dfault.size()); | |
462 | return st; | |
463 | } | |
464 | ||
465 | virtual void | |
466 | do_close(catalog c) const | |
467 | { | |
468 | __messages_close<_CharT>(other_abi{}, _M_get(), c); | |
469 | } | |
470 | }; | |
471 | ||
d8b7282e JW |
472 | template struct numpunct_shim<char>; |
473 | template struct collate_shim<char>; | |
474 | template struct moneypunct_shim<char, true>; | |
475 | template struct moneypunct_shim<char, false>; | |
476 | template struct money_get_shim<char>; | |
477 | template struct money_put_shim<char>; | |
478 | template struct messages_shim<char>; | |
1b9ad1d9 | 479 | #ifdef _GLIBCXX_USE_WCHAR_T |
d8b7282e JW |
480 | template struct numpunct_shim<wchar_t>; |
481 | template struct collate_shim<wchar_t>; | |
482 | template struct moneypunct_shim<wchar_t, true>; | |
483 | template struct moneypunct_shim<wchar_t, false>; | |
484 | template struct money_get_shim<wchar_t>; | |
485 | template struct money_put_shim<wchar_t>; | |
486 | template struct messages_shim<wchar_t>; | |
1b9ad1d9 | 487 | #endif |
34a2b755 JW |
488 | |
489 | template<typename C> | |
490 | inline size_t | |
491 | __copy(const C*& dest, const basic_string<C>& s) | |
492 | { | |
493 | auto len = s.length(); | |
494 | C* p = new C[len+1]; | |
495 | s.copy(p, len); | |
496 | p[len] = '\0'; | |
497 | dest = p; | |
498 | return len; | |
499 | } | |
500 | ||
501 | } // namespace | |
502 | ||
503 | // Now define and instantiate the functions that will be called by the | |
504 | // shim facets defined when this file is recompiled for the other ABI. | |
505 | ||
831a3a9e JW |
506 | // Cache the values returned by the numpunct facet f. |
507 | // Sets c->_M_allocated so that the __numpunct_cache destructor will | |
508 | // delete[] the strings allocated by this function. | |
34a2b755 JW |
509 | template<typename C> |
510 | void | |
831a3a9e | 511 | __numpunct_fill_cache(current_abi, const facet* f, __numpunct_cache<C>* c) |
34a2b755 JW |
512 | { |
513 | auto* m = static_cast<const numpunct<C>*>(f); | |
514 | ||
515 | c->_M_decimal_point = m->decimal_point(); | |
516 | c->_M_thousands_sep = m->thousands_sep(); | |
517 | ||
831a3a9e | 518 | c->_M_grouping = nullptr; |
34a2b755 JW |
519 | c->_M_truename = nullptr; |
520 | c->_M_falsename = nullptr; | |
521 | // set _M_allocated so that if any allocation fails the previously | |
831a3a9e | 522 | // allocated strings will be deleted in ~__numpunct_cache() |
34a2b755 JW |
523 | c->_M_allocated = true; |
524 | ||
831a3a9e | 525 | c->_M_grouping_size = __copy(c->_M_grouping, m->grouping()); |
34a2b755 JW |
526 | c->_M_truename_size = __copy(c->_M_truename, m->truename()); |
527 | c->_M_falsename_size = __copy(c->_M_falsename, m->falsename()); | |
34a2b755 JW |
528 | } |
529 | ||
530 | template void | |
831a3a9e | 531 | __numpunct_fill_cache(current_abi, const facet*, __numpunct_cache<char>*); |
34a2b755 | 532 | |
1b9ad1d9 | 533 | #ifdef _GLIBCXX_USE_WCHAR_T |
34a2b755 | 534 | template void |
831a3a9e | 535 | __numpunct_fill_cache(current_abi, const facet*, __numpunct_cache<wchar_t>*); |
1b9ad1d9 | 536 | #endif |
34a2b755 JW |
537 | |
538 | template<typename C> | |
539 | int | |
540 | __collate_compare(current_abi, const facet* f, const C* lo1, const C* hi1, | |
541 | const C* lo2, const C* hi2) | |
542 | { | |
543 | return static_cast<const collate<C>*>(f)->compare(lo1, hi1, lo2, hi2); | |
544 | } | |
545 | ||
546 | template int | |
547 | __collate_compare(current_abi, const facet*, const char*, const char*, | |
548 | const char*, const char*); | |
549 | ||
1b9ad1d9 | 550 | #ifdef _GLIBCXX_USE_WCHAR_T |
34a2b755 JW |
551 | template int |
552 | __collate_compare(current_abi, const facet*, const wchar_t*, const wchar_t*, | |
553 | const wchar_t*, const wchar_t*); | |
1b9ad1d9 | 554 | #endif |
34a2b755 JW |
555 | |
556 | template<typename C> | |
557 | void | |
558 | __collate_transform(current_abi, const facet* f, __any_string& st, | |
559 | const C* __lo, const C* __hi) | |
560 | { | |
561 | auto* c = static_cast<const collate<C>*>(f); | |
562 | st = c->transform(__lo, __hi); | |
563 | } | |
564 | ||
565 | template void | |
566 | __collate_transform(current_abi, const facet*, __any_string&, | |
567 | const char*, const char*); | |
568 | ||
1b9ad1d9 | 569 | #ifdef _GLIBCXX_USE_WCHAR_T |
34a2b755 JW |
570 | template void |
571 | __collate_transform(current_abi, const facet*, __any_string&, | |
572 | const wchar_t*, const wchar_t*); | |
1b9ad1d9 | 573 | #endif |
34a2b755 | 574 | |
831a3a9e JW |
575 | // Cache the values returned by the moneypunct facet, f. |
576 | // Sets c->_M_allocated so that the __moneypunct_cache destructor will | |
577 | // delete[] the strings allocated by this function. | |
34a2b755 JW |
578 | template<typename C, bool Intl> |
579 | void | |
580 | __moneypunct_fill_cache(current_abi, const facet* f, | |
581 | __moneypunct_cache<C, Intl>* c) | |
582 | { | |
583 | auto* m = static_cast<const moneypunct<C, Intl>*>(f); | |
584 | ||
585 | c->_M_decimal_point = m->decimal_point(); | |
586 | c->_M_thousands_sep = m->thousands_sep(); | |
587 | c->_M_frac_digits = m->frac_digits(); | |
588 | ||
589 | c->_M_grouping = nullptr; | |
590 | c->_M_curr_symbol = nullptr; | |
591 | c->_M_positive_sign = nullptr; | |
592 | c->_M_negative_sign = nullptr; | |
831a3a9e JW |
593 | // Set _M_allocated so that if any allocation fails the previously |
594 | // allocated strings will be deleted in ~__moneypunct_cache(). | |
34a2b755 JW |
595 | c->_M_allocated = true; |
596 | ||
597 | c->_M_grouping_size = __copy(c->_M_grouping, m->grouping()); | |
598 | c->_M_curr_symbol_size = __copy(c->_M_curr_symbol, m->curr_symbol()); | |
599 | c->_M_positive_sign_size | |
600 | = __copy(c->_M_positive_sign, m->positive_sign()); | |
601 | c->_M_negative_sign_size | |
602 | = __copy(c->_M_negative_sign, m->negative_sign()); | |
603 | ||
604 | c->_M_pos_format = m->pos_format(); | |
605 | c->_M_neg_format = m->neg_format(); | |
606 | } | |
607 | ||
608 | template void | |
609 | __moneypunct_fill_cache(current_abi, const facet*, | |
610 | __moneypunct_cache<char, true>*); | |
611 | ||
612 | template void | |
613 | __moneypunct_fill_cache(current_abi, const facet*, | |
614 | __moneypunct_cache<char, false>*); | |
615 | ||
1b9ad1d9 | 616 | #ifdef _GLIBCXX_USE_WCHAR_T |
34a2b755 JW |
617 | template void |
618 | __moneypunct_fill_cache(current_abi, const facet*, | |
619 | __moneypunct_cache<wchar_t, true>*); | |
620 | ||
621 | template void | |
622 | __moneypunct_fill_cache(current_abi, const facet*, | |
623 | __moneypunct_cache<wchar_t, false>*); | |
1b9ad1d9 | 624 | #endif |
34a2b755 JW |
625 | |
626 | template<typename C> | |
627 | messages_base::catalog | |
628 | __messages_open(current_abi, const facet* f, const char* s, size_t n, | |
629 | const locale& l) | |
630 | { | |
631 | auto* m = static_cast<const messages<C>*>(f); | |
632 | string str(s, n); | |
633 | return m->open(str, l); | |
634 | } | |
635 | ||
636 | template messages_base::catalog | |
637 | __messages_open<char>(current_abi, const facet*, const char*, size_t, | |
638 | const locale&); | |
639 | ||
1b9ad1d9 | 640 | #ifdef _GLIBCXX_USE_WCHAR_T |
34a2b755 JW |
641 | template messages_base::catalog |
642 | __messages_open<wchar_t>(current_abi, const facet*, const char*, size_t, | |
643 | const locale&); | |
1b9ad1d9 | 644 | #endif |
34a2b755 JW |
645 | |
646 | template<typename C> | |
647 | void | |
648 | __messages_get(current_abi, const facet* f, __any_string& st, | |
649 | messages_base::catalog c, int set, int msgid, | |
650 | const C* s, size_t n) | |
651 | { | |
652 | auto* m = static_cast<const messages<C>*>(f); | |
653 | st = m->get(c, set, msgid, basic_string<C>(s, n)); | |
654 | } | |
655 | ||
656 | template void | |
657 | __messages_get(current_abi, const facet*, __any_string&, | |
658 | messages_base::catalog, int, int, const char*, size_t); | |
659 | ||
1b9ad1d9 | 660 | #ifdef _GLIBCXX_USE_WCHAR_T |
34a2b755 JW |
661 | template void |
662 | __messages_get(current_abi, const facet*, __any_string&, | |
663 | messages_base::catalog, int, int, const wchar_t*, size_t); | |
1b9ad1d9 | 664 | #endif |
34a2b755 JW |
665 | |
666 | template<typename C> | |
667 | void | |
668 | __messages_close(current_abi, const facet* f, messages_base::catalog c) | |
669 | { | |
670 | static_cast<const messages<C>*>(f)->close(c); | |
671 | } | |
672 | ||
673 | template void | |
674 | __messages_close<char>(current_abi, const facet*, messages_base::catalog c); | |
675 | ||
1b9ad1d9 | 676 | #ifdef _GLIBCXX_USE_WCHAR_T |
34a2b755 JW |
677 | template void |
678 | __messages_close<wchar_t>(current_abi, const facet*, | |
679 | messages_base::catalog c); | |
1b9ad1d9 | 680 | #endif |
34a2b755 JW |
681 | |
682 | template<typename C> | |
683 | time_base::dateorder | |
684 | __time_get_dateorder(current_abi, const facet* f) | |
685 | { return static_cast<const time_get<C>*>(f)->date_order(); } | |
686 | ||
687 | template time_base::dateorder | |
688 | __time_get_dateorder<char>(current_abi, const facet*); | |
689 | ||
1b9ad1d9 | 690 | #ifdef _GLIBCXX_USE_WCHAR_T |
34a2b755 JW |
691 | template time_base::dateorder |
692 | __time_get_dateorder<wchar_t>(current_abi, const facet*); | |
1b9ad1d9 | 693 | #endif |
34a2b755 JW |
694 | |
695 | template<typename C> | |
696 | istreambuf_iterator<C> | |
697 | __time_get(current_abi, const facet* f, | |
698 | istreambuf_iterator<C> beg, istreambuf_iterator<C> end, | |
699 | ios_base& io, ios_base::iostate& err, tm* t, char which) | |
700 | { | |
701 | auto* g = static_cast<const time_get<C>*>(f); | |
702 | switch(which) | |
703 | { | |
704 | case 't': | |
705 | return g->get_time(beg, end, io, err, t); | |
706 | case 'd': | |
707 | return g->get_date(beg, end, io, err, t); | |
708 | case 'w': | |
709 | return g->get_weekday(beg, end, io, err, t); | |
710 | case 'm': | |
711 | return g->get_monthname(beg, end, io, err, t); | |
712 | case 'y': | |
713 | return g->get_year(beg, end, io, err, t); | |
714 | default: | |
715 | __builtin_unreachable(); | |
716 | } | |
717 | } | |
718 | ||
719 | template istreambuf_iterator<char> | |
720 | __time_get(current_abi, const facet*, | |
721 | istreambuf_iterator<char>, istreambuf_iterator<char>, | |
722 | ios_base&, ios_base::iostate&, tm*, char); | |
723 | ||
1b9ad1d9 | 724 | #ifdef _GLIBCXX_USE_WCHAR_T |
34a2b755 JW |
725 | template istreambuf_iterator<wchar_t> |
726 | __time_get(current_abi, const facet*, | |
727 | istreambuf_iterator<wchar_t>, istreambuf_iterator<wchar_t>, | |
728 | ios_base&, ios_base::iostate&, tm*, char); | |
1b9ad1d9 | 729 | #endif |
34a2b755 JW |
730 | |
731 | template<typename C> | |
732 | istreambuf_iterator<C> | |
733 | __money_get(current_abi, const facet* f, | |
734 | istreambuf_iterator<C> s, istreambuf_iterator<C> end, | |
735 | bool intl, ios_base& str, ios_base::iostate& err, | |
736 | long double* units, __any_string* digits) | |
737 | { | |
738 | auto* m = static_cast<const money_get<C>*>(f); | |
739 | if (units) | |
740 | return m->get(s, end, intl, str, err, *units); | |
741 | basic_string<C> digits2; | |
742 | s = m->get(s, end, intl, str, err, digits2); | |
743 | if (err == ios_base::goodbit) | |
744 | *digits = digits2; | |
745 | return s; | |
746 | } | |
747 | ||
748 | template istreambuf_iterator<char> | |
749 | __money_get(current_abi, const facet*, | |
750 | istreambuf_iterator<char>, istreambuf_iterator<char>, | |
751 | bool, ios_base&, ios_base::iostate&, | |
752 | long double*, __any_string*); | |
753 | ||
1b9ad1d9 | 754 | #ifdef _GLIBCXX_USE_WCHAR_T |
34a2b755 JW |
755 | template istreambuf_iterator<wchar_t> |
756 | __money_get(current_abi, const facet*, | |
757 | istreambuf_iterator<wchar_t>, istreambuf_iterator<wchar_t>, | |
758 | bool, ios_base&, ios_base::iostate&, | |
759 | long double*, __any_string*); | |
1b9ad1d9 | 760 | #endif |
34a2b755 JW |
761 | |
762 | template<typename C> | |
763 | ostreambuf_iterator<C> | |
764 | __money_put(current_abi, const facet* f, ostreambuf_iterator<C> s, | |
765 | bool intl, ios_base& io, C fill, long double units, | |
766 | const __any_string* digits) | |
767 | { | |
768 | auto* m = static_cast<const money_put<C>*>(f); | |
769 | if (digits) | |
770 | return m->put(s, intl, io, fill, *digits); | |
771 | else | |
772 | return m->put(s, intl, io, fill, units); | |
773 | } | |
774 | ||
f9bd185f JW |
775 | #pragma GCC diagnostic pop |
776 | ||
34a2b755 JW |
777 | template ostreambuf_iterator<char> |
778 | __money_put(current_abi, const facet*, ostreambuf_iterator<char>, | |
779 | bool, ios_base&, char, long double, const __any_string*); | |
780 | ||
1b9ad1d9 | 781 | #ifdef _GLIBCXX_USE_WCHAR_T |
34a2b755 JW |
782 | template ostreambuf_iterator<wchar_t> |
783 | __money_put(current_abi, const facet*, ostreambuf_iterator<wchar_t>, | |
784 | bool, ios_base&, wchar_t, long double, const __any_string*); | |
1b9ad1d9 | 785 | #endif |
34a2b755 | 786 | |
34a2b755 JW |
787 | } // namespace __facet_shims |
788 | ||
34a2b755 JW |
789 | // Create a new shim facet of type WHICH that forwards calls to F. |
790 | // F is the replacement facet provided by the user, WHICH is the ID of | |
791 | // F's "other ABI twin" which we are replacing with a shim. | |
792 | const locale::facet* | |
793 | #if _GLIBCXX_USE_CXX11_ABI | |
794 | locale::facet::_M_sso_shim(const locale::id* which) const | |
795 | #else | |
796 | locale::facet::_M_cow_shim(const locale::id* which) const | |
797 | #endif | |
798 | { | |
799 | using namespace __facet_shims; | |
800 | ||
5e67acc9 | 801 | #if __cpp_rtti |
34a2b755 JW |
802 | // If this is already a shim just use its underlying facet. |
803 | if (auto* p = dynamic_cast<const __shim*>(this)) | |
804 | return p->_M_get(); | |
5e67acc9 | 805 | #endif |
34a2b755 JW |
806 | |
807 | if (which == &numpunct<char>::id) | |
808 | return new numpunct_shim<char>{this}; | |
809 | if (which == &std::collate<char>::id) | |
810 | return new collate_shim<char>{this}; | |
811 | if (which == &time_get<char>::id) | |
812 | return new time_get_shim<char>{this}; | |
813 | if (which == &money_get<char>::id) | |
814 | return new money_get_shim<char>{this}; | |
815 | if (which == &money_put<char>::id) | |
816 | return new money_put_shim<char>{this}; | |
817 | if (which == &moneypunct<char, true>::id) | |
818 | return new moneypunct_shim<char, true>{this}; | |
819 | if (which == &moneypunct<char, false>::id) | |
820 | return new moneypunct_shim<char, false>{this}; | |
821 | if (which == &std::messages<char>::id) | |
822 | return new messages_shim<char>{this}; | |
823 | #ifdef _GLIBCXX_USE_WCHAR_T | |
824 | if (which == &numpunct<wchar_t>::id) | |
825 | return new numpunct_shim<wchar_t>{this}; | |
826 | if (which == &std::collate<wchar_t>::id) | |
827 | return new collate_shim<wchar_t>{this}; | |
828 | if (which == &time_get<wchar_t>::id) | |
829 | return new time_get_shim<wchar_t>{this}; | |
830 | if (which == &money_get<wchar_t>::id) | |
831 | return new money_get_shim<wchar_t>{this}; | |
832 | if (which == &money_put<wchar_t>::id) | |
833 | return new money_put_shim<wchar_t>{this}; | |
834 | if (which == &moneypunct<wchar_t, true>::id) | |
835 | return new moneypunct_shim<wchar_t, true>{this}; | |
836 | if (which == &moneypunct<wchar_t, false>::id) | |
837 | return new moneypunct_shim<wchar_t, false>{this}; | |
838 | if (which == &std::messages<wchar_t>::id) | |
839 | return new messages_shim<wchar_t>{this}; | |
840 | #endif | |
841 | __throw_logic_error("cannot create shim for unknown locale::facet"); | |
842 | } | |
843 | ||
844 | _GLIBCXX_END_NAMESPACE_VERSION | |
845 | } // namespace std |