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