| // Locale support -*- C++ -*- |
| |
| // Copyright (C) 2014-2022 Free Software Foundation, Inc. |
| // |
| // This file is part of the GNU ISO C++ Library. This library is free |
| // software; you can redistribute it and/or modify it under the |
| // terms of the GNU General Public License as published by the |
| // Free Software Foundation; either version 3, or (at your option) |
| // any later version. |
| |
| // This library is distributed in the hope that it will be useful, |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| // GNU General Public License for more details. |
| |
| // Under Section 7 of GPL version 3, you are granted additional |
| // permissions described in the GCC Runtime Library Exception, version |
| // 3.1, as published by the Free Software Foundation. |
| |
| // You should have received a copy of the GNU General Public License and |
| // a copy of the GCC Runtime Library Exception along with this program; |
| // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
| // <http://www.gnu.org/licenses/>. |
| |
| // |
| // ISO C++ 14882: 22.1 Locales |
| // |
| |
| // This file defines classes that behave like the standard predefined locale |
| // facets (collate, money_get etc.) except that they forward all virtual |
| // functions to another facet which uses a different std::string ABI, |
| // converting between string types as needed. |
| // When a user replaces one of the relevant facets the corresponding shim in |
| // this file is used so that the replacement facet can be used (via the shim) |
| // in code that uses the other std::string ABI from the replacing code. |
| |
| #ifndef _GLIBCXX_USE_CXX11_ABI |
| # define _GLIBCXX_USE_CXX11_ABI 1 |
| #endif |
| #include <locale> |
| |
| #if ! _GLIBCXX_USE_DUAL_ABI |
| # error This file should not be compiled for this configuration. |
| #endif |
| |
| namespace std _GLIBCXX_VISIBILITY(default) |
| { |
| _GLIBCXX_BEGIN_NAMESPACE_VERSION |
| |
| // Base class of facet shims, holds a reference to the underlying facet |
| // that the shim forwards to. |
| class locale::facet::__shim |
| { |
| public: |
| const facet* _M_get() const { return _M_facet; } |
| |
| __shim(const __shim&) = delete; |
| __shim& operator=(const __shim&) = delete; |
| |
| protected: |
| explicit |
| __shim(const facet* __f) : _M_facet(__f) { __f->_M_add_reference(); } |
| |
| ~__shim() { _M_facet->_M_remove_reference(); } |
| |
| private: |
| const facet* _M_facet; |
| }; |
| |
| namespace __facet_shims |
| { |
| namespace // unnamed |
| { |
| template<typename C> |
| void __destroy_string(void* p) |
| { |
| static_cast<std::basic_string<C>*>(p)->~basic_string(); |
| } |
| } // namespace |
| |
| // Manages a buffer of uninitialized memory that can store a std::string |
| // or std::wstring, using either ABI, and convert to the other ABI. |
| class __any_string |
| { |
| struct __attribute__((may_alias)) __str_rep |
| { |
| union { |
| const void* _M_p; |
| char* _M_pc; |
| #ifdef _GLIBCXX_USE_WCHAR_T |
| wchar_t* _M_pwc; |
| #endif |
| }; |
| size_t _M_len; |
| char _M_unused[16]; |
| |
| operator const char*() const { return _M_pc; } |
| #ifdef _GLIBCXX_USE_WCHAR_T |
| operator const wchar_t*() const { return _M_pwc; } |
| #endif |
| }; |
| union { |
| __str_rep _M_str; |
| char _M_bytes[sizeof(__str_rep)]; |
| }; |
| using __dtor_func = void(*)(void*); |
| __dtor_func _M_dtor = nullptr; |
| |
| #if _GLIBCXX_USE_CXX11_ABI |
| // SSO strings overlay the entire __str_rep structure. |
| static_assert(sizeof(std::string) == sizeof(__str_rep), |
| "std::string changed size!"); |
| #else |
| // COW strings overlay just the pointer, the length is stored manually. |
| static_assert(sizeof(std::string) == sizeof(__str_rep::_M_p), |
| "std::string changed size!"); |
| #endif |
| # ifdef _GLIBCXX_USE_WCHAR_T |
| static_assert(sizeof(std::wstring) == sizeof(std::string), |
| "std::wstring and std::string are different sizes!"); |
| # endif |
| |
| public: |
| __any_string() = default; |
| ~__any_string() { if (_M_dtor) _M_dtor(_M_bytes); } |
| |
| __any_string(const __any_string&) = delete; |
| __any_string& operator=(const __any_string&) = delete; |
| |
| // Store a string (and its length if needed) in the buffer and |
| // set _M_dtor to the function that runs the right destructor. |
| template<typename C> |
| __any_string& |
| operator=(const basic_string<C>& s) |
| { |
| if (_M_dtor) |
| _M_dtor(_M_bytes); |
| ::new(_M_bytes) basic_string<C>(s); |
| #if ! _GLIBCXX_USE_CXX11_ABI |
| _M_str._M_len = s.length(); |
| #endif |
| _M_dtor = __destroy_string<C>; |
| return *this; |
| } |
| |
| // Create a new string with a copy of the characters in the stored string. |
| // The returned object will match the caller's string ABI, even when the |
| // stored string doesn't. |
| template<typename C> |
| _GLIBCXX_DEFAULT_ABI_TAG |
| operator basic_string<C>() const |
| { |
| if (!_M_dtor) |
| __throw_logic_error("uninitialized __any_string"); |
| return basic_string<C>(static_cast<const C*>(_M_str), _M_str._M_len); |
| } |
| }; |
| |
| // This file is compiled twice, with and without this macro defined. |
| // Define tag types to distinguish between the two cases and to allow |
| // overloading on the tag. |
| using current_abi = __bool_constant<_GLIBCXX_USE_CXX11_ABI>; |
| using other_abi = __bool_constant<!_GLIBCXX_USE_CXX11_ABI>; |
| |
| using facet = locale::facet; |
| |
| // Declare the functions that shims defined in this file will call to |
| // perform work in the context of the other ABI. |
| // These will be defined when this file is recompiled for the other ABI |
| // (at which point what is now "current_abi" will become "other_abi"). |
| |
| template<typename C> |
| void |
| __numpunct_fill_cache(other_abi, const facet*, __numpunct_cache<C>*); |
| |
| template<typename C> |
| int |
| __collate_compare(other_abi, const facet*, const C*, const C*, |
| const C*, const C*); |
| |
| template<typename C> |
| void |
| __collate_transform(other_abi, const facet*, __any_string&, |
| const C*, const C*); |
| |
| template<typename C> |
| time_base::dateorder |
| __time_get_dateorder(other_abi, const facet* f); |
| |
| template<typename C> |
| istreambuf_iterator<C> |
| __time_get(other_abi, const facet* f, |
| istreambuf_iterator<C> beg, istreambuf_iterator<C> end, |
| ios_base& io, ios_base::iostate& err, tm* t, char which); |
| |
| template<typename C, bool Intl> |
| void |
| __moneypunct_fill_cache(other_abi, const facet*, |
| __moneypunct_cache<C, Intl>*); |
| |
| template<typename C> |
| istreambuf_iterator<C> |
| __money_get(other_abi, const facet*, |
| istreambuf_iterator<C>, istreambuf_iterator<C>, |
| bool, ios_base&, ios_base::iostate&, |
| long double*, __any_string*); |
| |
| template<typename C> |
| ostreambuf_iterator<C> |
| __money_put(other_abi, const facet*, ostreambuf_iterator<C>, bool, |
| ios_base&, C, long double, const __any_string*); |
| |
| template<typename C> |
| messages_base::catalog |
| __messages_open(other_abi, const facet*, const char*, size_t, |
| const locale&); |
| |
| template<typename C> |
| void |
| __messages_get(other_abi, const facet*, __any_string&, |
| messages_base::catalog, int, int, const C*, size_t); |
| |
| template<typename C> |
| void |
| __messages_close(other_abi, const facet*, messages_base::catalog); |
| |
| #pragma GCC diagnostic push |
| // Suppress -Wabi=2 warnings due to empty struct argument passing changes. |
| // TODO This should use -Wabi=12 but that currently fails (PR c++/87611). |
| #pragma GCC diagnostic ignored "-Wabi" |
| |
| namespace // unnamed |
| { |
| struct __shim_accessor : facet |
| { |
| using facet::__shim; // Redeclare protected member as public. |
| }; |
| using __shim = __shim_accessor::__shim; |
| |
| template<typename _CharT> |
| struct numpunct_shim : std::numpunct<_CharT>, __shim |
| { |
| typedef typename numpunct<_CharT>::__cache_type __cache_type; |
| |
| // f must point to a type derived from numpunct<C>[abi:other] |
| numpunct_shim(const facet* f, __cache_type* c = new __cache_type) |
| : std::numpunct<_CharT>(c), __shim(f), _M_cache(c) |
| { |
| __numpunct_fill_cache(other_abi{}, f, c); |
| } |
| |
| ~numpunct_shim() |
| { |
| // Stop GNU locale's ~numpunct() from freeing the cached string. |
| _M_cache->_M_grouping_size = 0; |
| } |
| |
| // No need to override any virtual functions, the base definitions |
| // will return the cached data. |
| |
| __cache_type* _M_cache; |
| }; |
| |
| template<typename _CharT> |
| struct collate_shim : std::collate<_CharT>, __shim |
| { |
| typedef basic_string<_CharT> string_type; |
| |
| // f must point to a type derived from collate<C>[abi:other] |
| collate_shim(const facet* f) : __shim(f) { } |
| |
| virtual int |
| do_compare(const _CharT* lo1, const _CharT* hi1, |
| const _CharT* lo2, const _CharT* hi2) const |
| { |
| return __collate_compare(other_abi{}, _M_get(), |
| lo1, hi1, lo2, hi2); |
| } |
| |
| virtual string_type |
| do_transform(const _CharT* lo, const _CharT* hi) const |
| { |
| __any_string st; |
| __collate_transform(other_abi{}, _M_get(), st, lo, hi); |
| return st; |
| } |
| }; |
| |
| template<typename _CharT> |
| struct time_get_shim : std::time_get<_CharT>, __shim |
| { |
| typedef typename std::time_get<_CharT>::iter_type iter_type; |
| typedef typename std::time_get<_CharT>::char_type char_type; |
| |
| // f must point to a type derived from time_get<C>[abi:other] |
| time_get_shim(const facet* f) : __shim(f) { } |
| |
| virtual time_base::dateorder |
| do_date_order() const |
| { return __time_get_dateorder<_CharT>(other_abi{}, _M_get()); } |
| |
| virtual iter_type |
| do_get_time(iter_type beg, iter_type end, ios_base& io, |
| ios_base::iostate& err, tm* t) const |
| { |
| return __time_get(other_abi{}, _M_get(), beg, end, io, err, t, |
| 't'); |
| } |
| |
| virtual iter_type |
| do_get_date(iter_type beg, iter_type end, ios_base& io, |
| ios_base::iostate& err, tm* t) const |
| { |
| return __time_get(other_abi{}, _M_get(), beg, end, io, err, t, |
| 'd'); |
| } |
| |
| virtual iter_type |
| do_get_weekday(iter_type beg, iter_type end, ios_base& io, |
| ios_base::iostate& err, tm* t) const |
| { |
| return __time_get(other_abi{}, _M_get(), beg, end, io, err, t, |
| 'w'); |
| } |
| |
| virtual iter_type |
| do_get_monthname(iter_type beg, iter_type end, ios_base& io, |
| ios_base::iostate& err, tm* t) const |
| { |
| return __time_get(other_abi{}, _M_get(), beg, end, io, err, t, |
| 'm'); |
| } |
| |
| virtual iter_type |
| do_get_year(iter_type beg, iter_type end, ios_base& io, |
| ios_base::iostate& err, tm* t) const |
| { |
| return __time_get(other_abi{}, _M_get(), beg, end, io, err, t, |
| 'y'); |
| } |
| }; |
| |
| template<typename _CharT, bool _Intl> |
| struct moneypunct_shim : std::moneypunct<_CharT, _Intl>, __shim |
| { |
| typedef typename moneypunct<_CharT, _Intl>::__cache_type __cache_type; |
| |
| // f must point to a type derived from moneypunct<C>[abi:other] |
| moneypunct_shim(const facet* f, __cache_type* c = new __cache_type) |
| : std::moneypunct<_CharT, _Intl>(c), __shim(f), _M_cache(c) |
| { |
| __moneypunct_fill_cache(other_abi{}, f, c); |
| } |
| |
| ~moneypunct_shim() |
| { |
| // Stop GNU locale's ~moneypunct() from freeing the cached strings. |
| _M_cache->_M_grouping_size = 0; |
| _M_cache->_M_curr_symbol_size = 0; |
| _M_cache->_M_positive_sign_size = 0; |
| _M_cache->_M_negative_sign_size = 0; |
| } |
| |
| // No need to override any virtual functions, the base definitions |
| // will return the cached data. |
| |
| __cache_type* _M_cache; |
| }; |
| |
| template<typename _CharT> |
| struct money_get_shim : std::money_get<_CharT>, __shim |
| { |
| typedef typename std::money_get<_CharT>::iter_type iter_type; |
| typedef typename std::money_get<_CharT>::char_type char_type; |
| typedef typename std::money_get<_CharT>::string_type string_type; |
| |
| // f must point to a type derived from money_get<C>[abi:other] |
| money_get_shim(const facet* f) : __shim(f) { } |
| |
| virtual iter_type |
| do_get(iter_type s, iter_type end, bool intl, ios_base& io, |
| ios_base::iostate& err, long double& units) const |
| { |
| ios_base::iostate err2 = ios_base::goodbit; |
| long double units2; |
| s = __money_get(other_abi{}, _M_get(), s, end, intl, io, err2, |
| &units2, nullptr); |
| if (err2 == ios_base::goodbit) |
| units = units2; |
| else |
| err = err2; |
| return s; |
| } |
| |
| virtual iter_type |
| do_get(iter_type s, iter_type end, bool intl, ios_base& io, |
| ios_base::iostate& err, string_type& digits) const |
| { |
| __any_string st; |
| ios_base::iostate err2 = ios_base::goodbit; |
| s = __money_get(other_abi{}, _M_get(), s, end, intl, io, err2, |
| nullptr, &st); |
| if (err2 == ios_base::goodbit) |
| digits = st; |
| else |
| err = err2; |
| return s; |
| } |
| }; |
| |
| template<typename _CharT> |
| struct money_put_shim : std::money_put<_CharT>, __shim |
| { |
| typedef typename std::money_put<_CharT>::iter_type iter_type; |
| typedef typename std::money_put<_CharT>::char_type char_type; |
| typedef typename std::money_put<_CharT>::string_type string_type; |
| |
| // f must point to a type derived from money_put<C>[abi:other] |
| money_put_shim(const facet* f) : __shim(f) { } |
| |
| virtual iter_type |
| do_put(iter_type s, bool intl, ios_base& io, |
| char_type fill, long double units) const |
| { |
| return __money_put(other_abi{}, _M_get(), s, intl, io, fill, units, |
| nullptr); |
| } |
| |
| virtual iter_type |
| do_put(iter_type s, bool intl, ios_base& io, |
| char_type fill, const string_type& digits) const |
| { |
| __any_string st; |
| st = digits; |
| return __money_put(other_abi{}, _M_get(), s, intl, io, fill, 0.L, |
| &st); |
| } |
| }; |
| |
| template<typename _CharT> |
| struct messages_shim : std::messages<_CharT>, __shim |
| { |
| typedef messages_base::catalog catalog; |
| typedef basic_string<_CharT> string_type; |
| |
| // f must point to a type derived from messages<C>[abi:other] |
| messages_shim(const facet* f) : __shim(f) { } |
| |
| virtual catalog |
| do_open(const basic_string<char>& s, const locale& l) const |
| { |
| return __messages_open<_CharT>(other_abi{}, _M_get(), |
| s.c_str(), s.size(), l); |
| } |
| |
| virtual string_type |
| do_get(catalog c, int set, int msgid, const string_type& dfault) const |
| { |
| __any_string st; |
| __messages_get(other_abi{}, _M_get(), st, c, set, msgid, |
| dfault.c_str(), dfault.size()); |
| return st; |
| } |
| |
| virtual void |
| do_close(catalog c) const |
| { |
| __messages_close<_CharT>(other_abi{}, _M_get(), c); |
| } |
| }; |
| |
| template struct numpunct_shim<char>; |
| template struct collate_shim<char>; |
| template struct moneypunct_shim<char, true>; |
| template struct moneypunct_shim<char, false>; |
| template struct money_get_shim<char>; |
| template struct money_put_shim<char>; |
| template struct messages_shim<char>; |
| #ifdef _GLIBCXX_USE_WCHAR_T |
| template struct numpunct_shim<wchar_t>; |
| template struct collate_shim<wchar_t>; |
| template struct moneypunct_shim<wchar_t, true>; |
| template struct moneypunct_shim<wchar_t, false>; |
| template struct money_get_shim<wchar_t>; |
| template struct money_put_shim<wchar_t>; |
| template struct messages_shim<wchar_t>; |
| #endif |
| |
| template<typename C> |
| inline size_t |
| __copy(const C*& dest, const basic_string<C>& s) |
| { |
| auto len = s.length(); |
| C* p = new C[len+1]; |
| s.copy(p, len); |
| p[len] = '\0'; |
| dest = p; |
| return len; |
| } |
| |
| } // namespace |
| |
| // Now define and instantiate the functions that will be called by the |
| // shim facets defined when this file is recompiled for the other ABI. |
| |
| // Cache the values returned by the numpunct facet f. |
| // Sets c->_M_allocated so that the __numpunct_cache destructor will |
| // delete[] the strings allocated by this function. |
| template<typename C> |
| void |
| __numpunct_fill_cache(current_abi, const facet* f, __numpunct_cache<C>* c) |
| { |
| auto* m = static_cast<const numpunct<C>*>(f); |
| |
| c->_M_decimal_point = m->decimal_point(); |
| c->_M_thousands_sep = m->thousands_sep(); |
| |
| c->_M_grouping = nullptr; |
| c->_M_truename = nullptr; |
| c->_M_falsename = nullptr; |
| // set _M_allocated so that if any allocation fails the previously |
| // allocated strings will be deleted in ~__numpunct_cache() |
| c->_M_allocated = true; |
| |
| c->_M_grouping_size = __copy(c->_M_grouping, m->grouping()); |
| c->_M_truename_size = __copy(c->_M_truename, m->truename()); |
| c->_M_falsename_size = __copy(c->_M_falsename, m->falsename()); |
| } |
| |
| template void |
| __numpunct_fill_cache(current_abi, const facet*, __numpunct_cache<char>*); |
| |
| #ifdef _GLIBCXX_USE_WCHAR_T |
| template void |
| __numpunct_fill_cache(current_abi, const facet*, __numpunct_cache<wchar_t>*); |
| #endif |
| |
| template<typename C> |
| int |
| __collate_compare(current_abi, const facet* f, const C* lo1, const C* hi1, |
| const C* lo2, const C* hi2) |
| { |
| return static_cast<const collate<C>*>(f)->compare(lo1, hi1, lo2, hi2); |
| } |
| |
| template int |
| __collate_compare(current_abi, const facet*, const char*, const char*, |
| const char*, const char*); |
| |
| #ifdef _GLIBCXX_USE_WCHAR_T |
| template int |
| __collate_compare(current_abi, const facet*, const wchar_t*, const wchar_t*, |
| const wchar_t*, const wchar_t*); |
| #endif |
| |
| template<typename C> |
| void |
| __collate_transform(current_abi, const facet* f, __any_string& st, |
| const C* __lo, const C* __hi) |
| { |
| auto* c = static_cast<const collate<C>*>(f); |
| st = c->transform(__lo, __hi); |
| } |
| |
| template void |
| __collate_transform(current_abi, const facet*, __any_string&, |
| const char*, const char*); |
| |
| #ifdef _GLIBCXX_USE_WCHAR_T |
| template void |
| __collate_transform(current_abi, const facet*, __any_string&, |
| const wchar_t*, const wchar_t*); |
| #endif |
| |
| // Cache the values returned by the moneypunct facet, f. |
| // Sets c->_M_allocated so that the __moneypunct_cache destructor will |
| // delete[] the strings allocated by this function. |
| template<typename C, bool Intl> |
| void |
| __moneypunct_fill_cache(current_abi, const facet* f, |
| __moneypunct_cache<C, Intl>* c) |
| { |
| auto* m = static_cast<const moneypunct<C, Intl>*>(f); |
| |
| c->_M_decimal_point = m->decimal_point(); |
| c->_M_thousands_sep = m->thousands_sep(); |
| c->_M_frac_digits = m->frac_digits(); |
| |
| c->_M_grouping = nullptr; |
| c->_M_curr_symbol = nullptr; |
| c->_M_positive_sign = nullptr; |
| c->_M_negative_sign = nullptr; |
| // Set _M_allocated so that if any allocation fails the previously |
| // allocated strings will be deleted in ~__moneypunct_cache(). |
| c->_M_allocated = true; |
| |
| c->_M_grouping_size = __copy(c->_M_grouping, m->grouping()); |
| c->_M_curr_symbol_size = __copy(c->_M_curr_symbol, m->curr_symbol()); |
| c->_M_positive_sign_size |
| = __copy(c->_M_positive_sign, m->positive_sign()); |
| c->_M_negative_sign_size |
| = __copy(c->_M_negative_sign, m->negative_sign()); |
| |
| c->_M_pos_format = m->pos_format(); |
| c->_M_neg_format = m->neg_format(); |
| } |
| |
| template void |
| __moneypunct_fill_cache(current_abi, const facet*, |
| __moneypunct_cache<char, true>*); |
| |
| template void |
| __moneypunct_fill_cache(current_abi, const facet*, |
| __moneypunct_cache<char, false>*); |
| |
| #ifdef _GLIBCXX_USE_WCHAR_T |
| template void |
| __moneypunct_fill_cache(current_abi, const facet*, |
| __moneypunct_cache<wchar_t, true>*); |
| |
| template void |
| __moneypunct_fill_cache(current_abi, const facet*, |
| __moneypunct_cache<wchar_t, false>*); |
| #endif |
| |
| template<typename C> |
| messages_base::catalog |
| __messages_open(current_abi, const facet* f, const char* s, size_t n, |
| const locale& l) |
| { |
| auto* m = static_cast<const messages<C>*>(f); |
| string str(s, n); |
| return m->open(str, l); |
| } |
| |
| template messages_base::catalog |
| __messages_open<char>(current_abi, const facet*, const char*, size_t, |
| const locale&); |
| |
| #ifdef _GLIBCXX_USE_WCHAR_T |
| template messages_base::catalog |
| __messages_open<wchar_t>(current_abi, const facet*, const char*, size_t, |
| const locale&); |
| #endif |
| |
| template<typename C> |
| 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) |
| { |
| auto* m = static_cast<const messages<C>*>(f); |
| st = m->get(c, set, msgid, basic_string<C>(s, n)); |
| } |
| |
| template void |
| __messages_get(current_abi, const facet*, __any_string&, |
| messages_base::catalog, int, int, const char*, size_t); |
| |
| #ifdef _GLIBCXX_USE_WCHAR_T |
| template void |
| __messages_get(current_abi, const facet*, __any_string&, |
| messages_base::catalog, int, int, const wchar_t*, size_t); |
| #endif |
| |
| template<typename C> |
| void |
| __messages_close(current_abi, const facet* f, messages_base::catalog c) |
| { |
| static_cast<const messages<C>*>(f)->close(c); |
| } |
| |
| template void |
| __messages_close<char>(current_abi, const facet*, messages_base::catalog c); |
| |
| #ifdef _GLIBCXX_USE_WCHAR_T |
| template void |
| __messages_close<wchar_t>(current_abi, const facet*, |
| messages_base::catalog c); |
| #endif |
| |
| template<typename C> |
| time_base::dateorder |
| __time_get_dateorder(current_abi, const facet* f) |
| { return static_cast<const time_get<C>*>(f)->date_order(); } |
| |
| template time_base::dateorder |
| __time_get_dateorder<char>(current_abi, const facet*); |
| |
| #ifdef _GLIBCXX_USE_WCHAR_T |
| template time_base::dateorder |
| __time_get_dateorder<wchar_t>(current_abi, const facet*); |
| #endif |
| |
| template<typename C> |
| 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) |
| { |
| auto* g = static_cast<const time_get<C>*>(f); |
| switch(which) |
| { |
| case 't': |
| return g->get_time(beg, end, io, err, t); |
| case 'd': |
| return g->get_date(beg, end, io, err, t); |
| case 'w': |
| return g->get_weekday(beg, end, io, err, t); |
| case 'm': |
| return g->get_monthname(beg, end, io, err, t); |
| case 'y': |
| return g->get_year(beg, end, io, err, t); |
| default: |
| __builtin_unreachable(); |
| } |
| } |
| |
| template istreambuf_iterator<char> |
| __time_get(current_abi, const facet*, |
| istreambuf_iterator<char>, istreambuf_iterator<char>, |
| ios_base&, ios_base::iostate&, tm*, char); |
| |
| #ifdef _GLIBCXX_USE_WCHAR_T |
| template istreambuf_iterator<wchar_t> |
| __time_get(current_abi, const facet*, |
| istreambuf_iterator<wchar_t>, istreambuf_iterator<wchar_t>, |
| ios_base&, ios_base::iostate&, tm*, char); |
| #endif |
| |
| template<typename C> |
| 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) |
| { |
| auto* m = static_cast<const money_get<C>*>(f); |
| if (units) |
| return m->get(s, end, intl, str, err, *units); |
| basic_string<C> digits2; |
| s = m->get(s, end, intl, str, err, digits2); |
| if (err == ios_base::goodbit) |
| *digits = digits2; |
| return s; |
| } |
| |
| template istreambuf_iterator<char> |
| __money_get(current_abi, const facet*, |
| istreambuf_iterator<char>, istreambuf_iterator<char>, |
| bool, ios_base&, ios_base::iostate&, |
| long double*, __any_string*); |
| |
| #ifdef _GLIBCXX_USE_WCHAR_T |
| template istreambuf_iterator<wchar_t> |
| __money_get(current_abi, const facet*, |
| istreambuf_iterator<wchar_t>, istreambuf_iterator<wchar_t>, |
| bool, ios_base&, ios_base::iostate&, |
| long double*, __any_string*); |
| #endif |
| |
| template<typename C> |
| 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) |
| { |
| auto* m = static_cast<const money_put<C>*>(f); |
| if (digits) |
| return m->put(s, intl, io, fill, *digits); |
| else |
| return m->put(s, intl, io, fill, units); |
| } |
| |
| #pragma GCC diagnostic pop |
| |
| template ostreambuf_iterator<char> |
| __money_put(current_abi, const facet*, ostreambuf_iterator<char>, |
| bool, ios_base&, char, long double, const __any_string*); |
| |
| #ifdef _GLIBCXX_USE_WCHAR_T |
| template ostreambuf_iterator<wchar_t> |
| __money_put(current_abi, const facet*, ostreambuf_iterator<wchar_t>, |
| bool, ios_base&, wchar_t, long double, const __any_string*); |
| #endif |
| |
| } // namespace __facet_shims |
| |
| // Create a new shim facet of type WHICH that forwards calls to F. |
| // F is the replacement facet provided by the user, WHICH is the ID of |
| // F's "other ABI twin" which we are replacing with a shim. |
| const locale::facet* |
| #if _GLIBCXX_USE_CXX11_ABI |
| locale::facet::_M_sso_shim(const locale::id* which) const |
| #else |
| locale::facet::_M_cow_shim(const locale::id* which) const |
| #endif |
| { |
| using namespace __facet_shims; |
| |
| #if __cpp_rtti |
| // If this is already a shim just use its underlying facet. |
| if (auto* p = dynamic_cast<const __shim*>(this)) |
| return p->_M_get(); |
| #endif |
| |
| if (which == &numpunct<char>::id) |
| return new numpunct_shim<char>{this}; |
| if (which == &std::collate<char>::id) |
| return new collate_shim<char>{this}; |
| if (which == &time_get<char>::id) |
| return new time_get_shim<char>{this}; |
| if (which == &money_get<char>::id) |
| return new money_get_shim<char>{this}; |
| if (which == &money_put<char>::id) |
| return new money_put_shim<char>{this}; |
| if (which == &moneypunct<char, true>::id) |
| return new moneypunct_shim<char, true>{this}; |
| if (which == &moneypunct<char, false>::id) |
| return new moneypunct_shim<char, false>{this}; |
| if (which == &std::messages<char>::id) |
| return new messages_shim<char>{this}; |
| #ifdef _GLIBCXX_USE_WCHAR_T |
| if (which == &numpunct<wchar_t>::id) |
| return new numpunct_shim<wchar_t>{this}; |
| if (which == &std::collate<wchar_t>::id) |
| return new collate_shim<wchar_t>{this}; |
| if (which == &time_get<wchar_t>::id) |
| return new time_get_shim<wchar_t>{this}; |
| if (which == &money_get<wchar_t>::id) |
| return new money_get_shim<wchar_t>{this}; |
| if (which == &money_put<wchar_t>::id) |
| return new money_put_shim<wchar_t>{this}; |
| if (which == &moneypunct<wchar_t, true>::id) |
| return new moneypunct_shim<wchar_t, true>{this}; |
| if (which == &moneypunct<wchar_t, false>::id) |
| return new moneypunct_shim<wchar_t, false>{this}; |
| if (which == &std::messages<wchar_t>::id) |
| return new messages_shim<wchar_t>{this}; |
| #endif |
| __throw_logic_error("cannot create shim for unknown locale::facet"); |
| } |
| |
| _GLIBCXX_END_NAMESPACE_VERSION |
| } // namespace std |