libstdc++
locale_classes.tcc
Go to the documentation of this file.
1// Locale support -*- C++ -*-
2
3// Copyright (C) 2007-2024 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/** @file bits/locale_classes.tcc
26 * This is an internal header file, included by other library headers.
27 * Do not attempt to use it directly. @headername{locale}
28 */
29
30//
31// ISO C++ 14882: 22.1 Locales
32//
33
34#ifndef _LOCALE_CLASSES_TCC
35#define _LOCALE_CLASSES_TCC 1
36
37#ifdef _GLIBCXX_SYSHDR
38#pragma GCC system_header
39#endif
40#pragma GCC diagnostic push
41#pragma GCC diagnostic ignored "-Wc++11-extensions" // extern template
42#pragma GCC diagnostic ignored "-Wvariadic-macros"
43
44namespace std _GLIBCXX_VISIBILITY(default)
45{
46_GLIBCXX_BEGIN_NAMESPACE_VERSION
47
48 template<typename _Facet>
50 locale(const locale& __other, _Facet* __f)
51 {
52 // _GLIBCXX_RESOLVE_LIB_DEFECTS
53 // 2295. Locale name when the provided Facet is a nullptr
54 if (__builtin_expect(!__f, 0))
55 {
56 _M_impl = __other._M_impl;
57 _M_impl->_M_add_reference();
58 return;
59 }
60
61 _M_impl = new _Impl(*__other._M_impl, 1);
62
63 __try
64 { _M_impl->_M_install_facet(&_Facet::id, __f); }
65 __catch(...)
66 {
67 _M_impl->_M_remove_reference();
68 __throw_exception_again;
69 }
70 delete [] _M_impl->_M_names[0];
71 _M_impl->_M_names[0] = 0; // Unnamed.
72 }
73
74 template<typename _Facet>
75 locale
77 combine(const locale& __other) const
78 {
79#if __cpp_lib_type_trait_variable_templates // C++ >= 17
80 static_assert(__is_facet<_Facet>, "Template argument must be a facet");
81#endif
82
83 _Impl* __tmp = new _Impl(*_M_impl, 1);
84 __try
85 {
86 __tmp->_M_replace_facet(__other._M_impl, &_Facet::id);
87 }
88 __catch(...)
89 {
90 __tmp->_M_remove_reference();
91 __throw_exception_again;
92 }
93 delete[] __tmp->_M_names[0];
94 __tmp->_M_names[0] = 0; // Unnamed.
95 return locale(__tmp);
96 }
97
98 template<typename _CharT, typename _Traits, typename _Alloc>
99 bool
103 {
104 typedef std::collate<_CharT> __collate_type;
105 const __collate_type& __collate = use_facet<__collate_type>(*this);
106 return (__collate.compare(__s1.data(), __s1.data() + __s1.length(),
107 __s2.data(), __s2.data() + __s2.length()) < 0);
108 }
109
110#pragma GCC diagnostic push
111#pragma GCC diagnostic ignored "-Wc++17-extensions"
112 template<typename _Facet>
113 inline const _Facet*
114 __try_use_facet(const locale& __loc) _GLIBCXX_NOTHROW
115 {
116 const size_t __i = _Facet::id._M_id();
117 const locale::facet** __facets = __loc._M_impl->_M_facets;
118
119 // We know these standard facets are always installed in every locale
120 // so dynamic_cast always succeeds, just use static_cast instead.
121#define _GLIBCXX_STD_FACET(...) \
122 if _GLIBCXX_CONSTEXPR (__is_same(const _Facet, const __VA_ARGS__)) \
123 return static_cast<const _Facet*>(__facets[__i])
124
125 _GLIBCXX_STD_FACET(ctype<char>);
126 _GLIBCXX_STD_FACET(num_get<char>);
127 _GLIBCXX_STD_FACET(num_put<char>);
128 _GLIBCXX_STD_FACET(codecvt<char, char, mbstate_t>);
129 _GLIBCXX_STD_FACET(collate<char>);
130 _GLIBCXX_STD_FACET(moneypunct<char>);
131 _GLIBCXX_STD_FACET(moneypunct<char, true>);
132 _GLIBCXX_STD_FACET(money_get<char>);
133 _GLIBCXX_STD_FACET(money_put<char>);
134 _GLIBCXX_STD_FACET(numpunct<char>);
135 _GLIBCXX_STD_FACET(time_get<char>);
136 _GLIBCXX_STD_FACET(time_put<char>);
137 _GLIBCXX_STD_FACET(messages<char>);
138
139#ifdef _GLIBCXX_USE_WCHAR_T
140 _GLIBCXX_STD_FACET(ctype<wchar_t>);
141 _GLIBCXX_STD_FACET(num_get<wchar_t>);
142 _GLIBCXX_STD_FACET(num_put<wchar_t>);
143 _GLIBCXX_STD_FACET(codecvt<wchar_t, char, mbstate_t>);
144 _GLIBCXX_STD_FACET(collate<wchar_t>);
145 _GLIBCXX_STD_FACET(moneypunct<wchar_t>);
146 _GLIBCXX_STD_FACET(moneypunct<wchar_t, true>);
147 _GLIBCXX_STD_FACET(money_get<wchar_t>);
148 _GLIBCXX_STD_FACET(money_put<wchar_t>);
149 _GLIBCXX_STD_FACET(numpunct<wchar_t>);
150 _GLIBCXX_STD_FACET(time_get<wchar_t>);
151 _GLIBCXX_STD_FACET(time_put<wchar_t>);
152 _GLIBCXX_STD_FACET(messages<wchar_t>);
153#endif
154#if __cplusplus >= 201103L
155 _GLIBCXX_STD_FACET(codecvt<char16_t, char, mbstate_t>);
156 _GLIBCXX_STD_FACET(codecvt<char32_t, char, mbstate_t>);
157#endif
158
159#undef _GLIBCXX_STD_FACET
160
161 if (__i >= __loc._M_impl->_M_facets_size || !__facets[__i])
162 return 0;
163
164#if __cpp_rtti
165 return dynamic_cast<const _Facet*>(__facets[__i]);
166#else
167 return static_cast<const _Facet*>(__facets[__i]);
168#endif
169 }
170#pragma GCC diagnostic pop
171
172 /**
173 * @brief Test for the presence of a facet.
174 * @ingroup locales
175 *
176 * has_facet tests the locale argument for the presence of the facet type
177 * provided as the template parameter. Facets derived from the facet
178 * parameter will also return true.
179 *
180 * @tparam _Facet The facet type to test the presence of.
181 * @param __loc The locale to test.
182 * @return true if @p __loc contains a facet of type _Facet, else false.
183 */
184 template<typename _Facet>
185 _GLIBCXX_NODISCARD
186 inline bool
187 has_facet(const locale& __loc) _GLIBCXX_USE_NOEXCEPT
188 {
189#if __cplusplus >= 201103L
190 static_assert(__is_base_of(locale::facet, _Facet),
191 "template argument must be derived from locale::facet");
192#else
193 (void) static_cast<const _Facet*>(static_cast<const locale::facet*>(0));
194#endif
195 return std::__try_use_facet<_Facet>(__loc) != 0;
196 }
197
198 /**
199 * @brief Return a facet.
200 * @ingroup locales
201 *
202 * use_facet looks for and returns a reference to a facet of type Facet
203 * where Facet is the template parameter. If has_facet(locale) is true,
204 * there is a suitable facet to return. It throws std::bad_cast if the
205 * locale doesn't contain a facet of type Facet.
206 *
207 * @tparam _Facet The facet type to access.
208 * @param __loc The locale to use.
209 * @return Reference to facet of type Facet.
210 * @throw std::bad_cast if @p __loc doesn't contain a facet of type _Facet.
211 */
212#pragma GCC diagnostic push
213#pragma GCC diagnostic ignored "-Wdangling-reference"
214 template<typename _Facet>
215 _GLIBCXX_NODISCARD
216 inline const _Facet&
217 use_facet(const locale& __loc)
218 {
219#if __cplusplus >= 201103L
220 static_assert(__is_base_of(locale::facet, _Facet),
221 "template argument must be derived from locale::facet");
222#else
223 (void) static_cast<const _Facet*>(static_cast<const locale::facet*>(0));
224#endif
225 if (const _Facet* __f = std::__try_use_facet<_Facet>(__loc))
226 return *__f;
227 __throw_bad_cast();
228 }
229#pragma GCC diagnostic pop
230
231
232 // Generic version does nothing.
233 template<typename _CharT>
234 int
235 collate<_CharT>::_M_compare(const _CharT*, const _CharT*) const throw ()
236 { return 0; }
237
238 // Generic version does nothing.
239 template<typename _CharT>
240 size_t
241 collate<_CharT>::_M_transform(_CharT*, const _CharT*, size_t) const throw ()
242 { return 0; }
243
244 template<typename _CharT>
245 int
247 do_compare(const _CharT* __lo1, const _CharT* __hi1,
248 const _CharT* __lo2, const _CharT* __hi2) const
249 {
250 // strcoll assumes zero-terminated strings so we make a copy
251 // and then put a zero at the end.
252 const string_type __one(__lo1, __hi1);
253 const string_type __two(__lo2, __hi2);
254
255 const _CharT* __p = __one.c_str();
256 const _CharT* __pend = __one.data() + __one.length();
257 const _CharT* __q = __two.c_str();
258 const _CharT* __qend = __two.data() + __two.length();
259
260 // strcoll stops when it sees a nul character so we break
261 // the strings into zero-terminated substrings and pass those
262 // to strcoll.
263 for (;;)
264 {
265 const int __res = _M_compare(__p, __q);
266 if (__res)
267 return __res;
268
269 __p += char_traits<_CharT>::length(__p);
270 __q += char_traits<_CharT>::length(__q);
271 if (__p == __pend && __q == __qend)
272 return 0;
273 else if (__p == __pend)
274 return -1;
275 else if (__q == __qend)
276 return 1;
277
278 __p++;
279 __q++;
280 }
281 }
282
283 template<typename _CharT>
286 do_transform(const _CharT* __lo, const _CharT* __hi) const
287 {
288 string_type __ret;
289
290 // strxfrm assumes zero-terminated strings so we make a copy
291 const string_type __str(__lo, __hi);
292
293 const _CharT* __p = __str.c_str();
294 const _CharT* __pend = __str.data() + __str.length();
295
296 size_t __len = (__hi - __lo) * 2;
297
298 _CharT* __c = new _CharT[__len];
299
300 __try
301 {
302 // strxfrm stops when it sees a nul character so we break
303 // the string into zero-terminated substrings and pass those
304 // to strxfrm.
305 for (;;)
306 {
307 // First try a buffer perhaps big enough.
308 size_t __res = _M_transform(__c, __p, __len);
309 // If the buffer was not large enough, try again with the
310 // correct size.
311 if (__res >= __len)
312 {
313 __len = __res + 1;
314 delete [] __c, __c = 0;
315 __c = new _CharT[__len];
316 __res = _M_transform(__c, __p, __len);
317 }
318
319 __ret.append(__c, __res);
320 __p += char_traits<_CharT>::length(__p);
321 if (__p == __pend)
322 break;
323
324 __p++;
325 __ret.push_back(_CharT());
326 }
327 }
328 __catch(...)
329 {
330 delete [] __c;
331 __throw_exception_again;
332 }
333
334 delete [] __c;
335
336 return __ret;
337 }
338
339 template<typename _CharT>
340 long
342 do_hash(const _CharT* __lo, const _CharT* __hi) const
343 {
344 unsigned long __val = 0;
345 for (; __lo < __hi; ++__lo)
346 __val =
347 *__lo + ((__val << 7)
348 | (__val >> (__gnu_cxx::__numeric_traits<unsigned long>::
349 __digits - 7)));
350 return static_cast<long>(__val);
351 }
352
353 // Inhibit implicit instantiations for required instantiations,
354 // which are defined via explicit instantiations elsewhere.
355#if _GLIBCXX_EXTERN_TEMPLATE
356 extern template class collate<char>;
357 extern template class collate_byname<char>;
358
359 extern template
360 const collate<char>*
361 __try_use_facet<collate<char> >(const locale&) _GLIBCXX_NOTHROW;
362
363 extern template
364 const collate<char>&
366
367 extern template
368 bool
370
371#ifdef _GLIBCXX_USE_WCHAR_T
372 extern template class collate<wchar_t>;
373 extern template class collate_byname<wchar_t>;
374
375 extern template
376 const collate<wchar_t>*
377 __try_use_facet<collate<wchar_t> >(const locale&) _GLIBCXX_NOTHROW;
378
379 extern template
380 const collate<wchar_t>&
382
383 extern template
384 bool
386#endif
387#endif
388
389_GLIBCXX_END_NAMESPACE_VERSION
390} // namespace std
391
392#pragma GCC diagnostic pop
393#endif
bool has_facet(const locale &__loc) noexcept
Test for the presence of a facet.
const _Facet & use_facet(const locale &__loc)
Return a facet.
ISO C++ entities toplevel namespace is std.
Managing sequences of characters and character-like objects.
Definition stringfwd.h:74
constexpr const _CharT * data() const noexcept
Return const pointer to contents.
constexpr size_type length() const noexcept
Returns the number of characters in the string, not including any null-termination.
Basis for explicit traits specializations.
Definition stringfwd.h:55
Container class for localization functionality.
friend const _Facet & use_facet(const locale &)
Return a facet.
locale combine(const locale &__other) const
Construct locale with another facet.
bool operator()(const basic_string< _Char, _Traits, _Alloc > &__s1, const basic_string< _Char, _Traits, _Alloc > &__s2) const
Compare two strings according to collate.
locale()
Default constructor.
Localization functionality base class.
Facet for localized string comparison.
basic_string< _CharT > string_type
Public typedefs.
class collate_byname [22.2.4.2].