1 // Locale support -*- C++ -*- 2 3 // Copyright (C) 2014-2019 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: _M_get() const55 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 __shim(const facet * __f)62 __shim(const facet* __f) : _M_facet(__f) { __f->_M_add_reference(); } 63 ~__shim()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> __destroy_string(void * p)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; ~__any_string()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& operator =(const basic_string<C> & s)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 operator basic_string<C>() const151 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 #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 232 namespace // unnamed 233 { 234 struct __shim_accessor : facet 235 { 236 using facet::__shim; // Redeclare protected member as public. 237 }; 238 using __shim = __shim_accessor::__shim; 239 240 template<typename _CharT> 241 struct numpunct_shim : std::numpunct<_CharT>, __shim 242 { 243 typedef typename numpunct<_CharT>::__cache_type __cache_type; 244 245 // f must point to a type derived from numpunct<C>[abi:other] numpunct_shimstd::__facet_shims::__anon3a5d188e0411::numpunct_shim246 numpunct_shim(const facet* f, __cache_type* c = new __cache_type) 247 : std::numpunct<_CharT>(c), __shim(f), _M_cache(c) 248 { 249 __numpunct_fill_cache(other_abi{}, f, c); 250 } 251 ~numpunct_shimstd::__facet_shims::__anon3a5d188e0411::numpunct_shim252 ~numpunct_shim() 253 { 254 // Stop GNU locale's ~numpunct() from freeing the cached string. 255 _M_cache->_M_grouping_size = 0; 256 } 257 258 // No need to override any virtual functions, the base definitions 259 // will return the cached data. 260 261 __cache_type* _M_cache; 262 }; 263 264 template<typename _CharT> 265 struct collate_shim : std::collate<_CharT>, __shim 266 { 267 typedef basic_string<_CharT> string_type; 268 269 // f must point to a type derived from collate<C>[abi:other] collate_shimstd::__facet_shims::__anon3a5d188e0411::collate_shim270 collate_shim(const facet* f) : __shim(f) { } 271 272 virtual int do_comparestd::__facet_shims::__anon3a5d188e0411::collate_shim273 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 do_transformstd::__facet_shims::__anon3a5d188e0411::collate_shim281 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 289 template<typename _CharT> 290 struct time_get_shim : std::time_get<_CharT>, __shim 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] time_get_shimstd::__facet_shims::__anon3a5d188e0411::time_get_shim296 time_get_shim(const facet* f) : __shim(f) { } 297 298 virtual time_base::dateorder do_date_orderstd::__facet_shims::__anon3a5d188e0411::time_get_shim299 do_date_order() const 300 { return __time_get_dateorder<_CharT>(other_abi{}, _M_get()); } 301 302 virtual iter_type do_get_timestd::__facet_shims::__anon3a5d188e0411::time_get_shim303 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 do_get_datestd::__facet_shims::__anon3a5d188e0411::time_get_shim311 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 do_get_weekdaystd::__facet_shims::__anon3a5d188e0411::time_get_shim319 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 do_get_monthnamestd::__facet_shims::__anon3a5d188e0411::time_get_shim327 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 do_get_yearstd::__facet_shims::__anon3a5d188e0411::time_get_shim335 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> 344 struct moneypunct_shim : std::moneypunct<_CharT, _Intl>, __shim 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] moneypunct_shimstd::__facet_shims::__anon3a5d188e0411::moneypunct_shim349 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 ~moneypunct_shimstd::__facet_shims::__anon3a5d188e0411::moneypunct_shim355 ~moneypunct_shim() 356 { 357 // Stop GNU locale's ~moneypunct() from freeing the cached strings. 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 370 template<typename _CharT> 371 struct money_get_shim : std::money_get<_CharT>, __shim 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] money_get_shimstd::__facet_shims::__anon3a5d188e0411::money_get_shim378 money_get_shim(const facet* f) : __shim(f) { } 379 380 virtual iter_type do_getstd::__facet_shims::__anon3a5d188e0411::money_get_shim381 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 do_getstd::__facet_shims::__anon3a5d188e0411::money_get_shim396 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 411 template<typename _CharT> 412 struct money_put_shim : std::money_put<_CharT>, __shim 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] money_put_shimstd::__facet_shims::__anon3a5d188e0411::money_put_shim419 money_put_shim(const facet* f) : __shim(f) { } 420 421 virtual iter_type do_putstd::__facet_shims::__anon3a5d188e0411::money_put_shim422 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 do_putstd::__facet_shims::__anon3a5d188e0411::money_put_shim430 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 440 template<typename _CharT> 441 struct messages_shim : std::messages<_CharT>, __shim 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] messages_shimstd::__facet_shims::__anon3a5d188e0411::messages_shim447 messages_shim(const facet* f) : __shim(f) { } 448 449 virtual catalog do_openstd::__facet_shims::__anon3a5d188e0411::messages_shim450 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 do_getstd::__facet_shims::__anon3a5d188e0411::messages_shim457 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 do_closestd::__facet_shims::__anon3a5d188e0411::messages_shim466 do_close(catalog c) const 467 { 468 __messages_close<_CharT>(other_abi{}, _M_get(), c); 469 } 470 }; 471 472 template class numpunct_shim<char>; 473 template class collate_shim<char>; 474 template class moneypunct_shim<char, true>; 475 template class moneypunct_shim<char, false>; 476 template class money_get_shim<char>; 477 template class money_put_shim<char>; 478 template class messages_shim<char>; 479 #ifdef _GLIBCXX_USE_WCHAR_T 480 template class numpunct_shim<wchar_t>; 481 template class collate_shim<wchar_t>; 482 template class moneypunct_shim<wchar_t, true>; 483 template class moneypunct_shim<wchar_t, false>; 484 template class money_get_shim<wchar_t>; 485 template class money_put_shim<wchar_t>; 486 template class messages_shim<wchar_t>; 487 #endif 488 489 template<typename C> 490 inline size_t __copy(const C * & dest,const basic_string<C> & s)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 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. 509 template<typename C> 510 void __numpunct_fill_cache(current_abi,const facet * f,__numpunct_cache<C> * c)511 __numpunct_fill_cache(current_abi, const facet* f, __numpunct_cache<C>* c) 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 518 c->_M_grouping = nullptr; 519 c->_M_truename = nullptr; 520 c->_M_falsename = nullptr; 521 // set _M_allocated so that if any allocation fails the previously 522 // allocated strings will be deleted in ~__numpunct_cache() 523 c->_M_allocated = true; 524 525 c->_M_grouping_size = __copy(c->_M_grouping, m->grouping()); 526 c->_M_truename_size = __copy(c->_M_truename, m->truename()); 527 c->_M_falsename_size = __copy(c->_M_falsename, m->falsename()); 528 } 529 530 template void 531 __numpunct_fill_cache(current_abi, const facet*, __numpunct_cache<char>*); 532 533 #ifdef _GLIBCXX_USE_WCHAR_T 534 template void 535 __numpunct_fill_cache(current_abi, const facet*, __numpunct_cache<wchar_t>*); 536 #endif 537 538 template<typename C> 539 int __collate_compare(current_abi,const facet * f,const C * lo1,const C * hi1,const C * lo2,const C * hi2)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 550 #ifdef _GLIBCXX_USE_WCHAR_T 551 template int 552 __collate_compare(current_abi, const facet*, const wchar_t*, const wchar_t*, 553 const wchar_t*, const wchar_t*); 554 #endif 555 556 template<typename C> 557 void __collate_transform(current_abi,const facet * f,__any_string & st,const C * __lo,const C * __hi)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 569 #ifdef _GLIBCXX_USE_WCHAR_T 570 template void 571 __collate_transform(current_abi, const facet*, __any_string&, 572 const wchar_t*, const wchar_t*); 573 #endif 574 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. 578 template<typename C, bool Intl> 579 void __moneypunct_fill_cache(current_abi,const facet * f,__moneypunct_cache<C,Intl> * c)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; 593 // Set _M_allocated so that if any allocation fails the previously 594 // allocated strings will be deleted in ~__moneypunct_cache(). 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 616 #ifdef _GLIBCXX_USE_WCHAR_T 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>*); 624 #endif 625 626 template<typename C> 627 messages_base::catalog __messages_open(current_abi,const facet * f,const char * s,size_t n,const locale & l)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 640 #ifdef _GLIBCXX_USE_WCHAR_T 641 template messages_base::catalog 642 __messages_open<wchar_t>(current_abi, const facet*, const char*, size_t, 643 const locale&); 644 #endif 645 646 template<typename C> 647 void __messages_get(current_abi,const facet * f,__any_string & st,messages_base::catalog c,int set,int msgid,const C * s,size_t n)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 660 #ifdef _GLIBCXX_USE_WCHAR_T 661 template void 662 __messages_get(current_abi, const facet*, __any_string&, 663 messages_base::catalog, int, int, const wchar_t*, size_t); 664 #endif 665 666 template<typename C> 667 void __messages_close(current_abi,const facet * f,messages_base::catalog c)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 676 #ifdef _GLIBCXX_USE_WCHAR_T 677 template void 678 __messages_close<wchar_t>(current_abi, const facet*, 679 messages_base::catalog c); 680 #endif 681 682 template<typename C> 683 time_base::dateorder __time_get_dateorder(current_abi,const facet * f)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 690 #ifdef _GLIBCXX_USE_WCHAR_T 691 template time_base::dateorder 692 __time_get_dateorder<wchar_t>(current_abi, const facet*); 693 #endif 694 695 template<typename C> 696 istreambuf_iterator<C> __time_get(current_abi,const facet * f,istreambuf_iterator<C> beg,istreambuf_iterator<C> end,ios_base & io,ios_base::iostate & err,tm * t,char which)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 724 #ifdef _GLIBCXX_USE_WCHAR_T 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); 729 #endif 730 731 template<typename C> 732 istreambuf_iterator<C> __money_get(current_abi,const facet * f,istreambuf_iterator<C> s,istreambuf_iterator<C> end,bool intl,ios_base & str,ios_base::iostate & err,long double * units,__any_string * digits)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 754 #ifdef _GLIBCXX_USE_WCHAR_T 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*); 760 #endif 761 762 template<typename C> 763 ostreambuf_iterator<C> __money_put(current_abi,const facet * f,ostreambuf_iterator<C> s,bool intl,ios_base & io,C fill,long double units,const __any_string * digits)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 775 #pragma GCC diagnostic pop 776 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 781 #ifdef _GLIBCXX_USE_WCHAR_T 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*); 785 #endif 786 787 } // namespace __facet_shims 788 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 _M_sso_shim(const locale::id * which) const794 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 801 #if __cpp_rtti 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(); 805 #endif 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 846