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