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 inline bool
166 has_facet(const locale& __loc) throw()
167 {
168#if __cplusplus >= 201103L
169 static_assert(__is_base_of(locale::facet, _Facet),
170 "template argument must be derived from locale::facet");
171#else
172 (void) static_cast<const _Facet*>(static_cast<const locale::facet*>(0));
173#endif
174 return std::__try_use_facet<_Facet>(__loc) != 0;
175 }
176
177 /**
178 * @brief Return a facet.
179 * @ingroup locales
180 *
181 * use_facet looks for and returns a reference to a facet of type Facet
182 * where Facet is the template parameter. If has_facet(locale) is true,
183 * there is a suitable facet to return. It throws std::bad_cast if the
184 * locale doesn't contain a facet of type Facet.
185 *
186 * @tparam _Facet The facet type to access.
187 * @param __loc The locale to use.
188 * @return Reference to facet of type Facet.
189 * @throw std::bad_cast if @p __loc doesn't contain a facet of type _Facet.
190 */
191#pragma GCC diagnostic push
192#pragma GCC diagnostic ignored "-Wdangling-reference"
193 template<typename _Facet>
194 inline const _Facet&
195 use_facet(const locale& __loc)
196 {
197#if __cplusplus >= 201103L
198 static_assert(__is_base_of(locale::facet, _Facet),
199 "template argument must be derived from locale::facet");
200#else
201 (void) static_cast<const _Facet*>(static_cast<const locale::facet*>(0));
202#endif
203 if (const _Facet* __f = std::__try_use_facet<_Facet>(__loc))
204 return *__f;
205 __throw_bad_cast();
206 }
207#pragma GCC diagnostic pop
208
209
210 // Generic version does nothing.
211 template<typename _CharT>
212 int
213 collate<_CharT>::_M_compare(const _CharT*, const _CharT*) const throw ()
214 { return 0; }
215
216 // Generic version does nothing.
217 template<typename _CharT>
218 size_t
219 collate<_CharT>::_M_transform(_CharT*, const _CharT*, size_t) const throw ()
220 { return 0; }
221
222 template<typename _CharT>
223 int
224 collate<_CharT>::
225 do_compare(const _CharT* __lo1, const _CharT* __hi1,
226 const _CharT* __lo2, const _CharT* __hi2) const
227 {
228 // strcoll assumes zero-terminated strings so we make a copy
229 // and then put a zero at the end.
230 const string_type __one(__lo1, __hi1);
231 const string_type __two(__lo2, __hi2);
232
233 const _CharT* __p = __one.c_str();
234 const _CharT* __pend = __one.data() + __one.length();
235 const _CharT* __q = __two.c_str();
236 const _CharT* __qend = __two.data() + __two.length();
237
238 // strcoll stops when it sees a nul character so we break
239 // the strings into zero-terminated substrings and pass those
240 // to strcoll.
241 for (;;)
242 {
243 const int __res = _M_compare(__p, __q);
244 if (__res)
245 return __res;
246
247 __p += char_traits<_CharT>::length(__p);
248 __q += char_traits<_CharT>::length(__q);
249 if (__p == __pend && __q == __qend)
250 return 0;
251 else if (__p == __pend)
252 return -1;
253 else if (__q == __qend)
254 return 1;
255
256 __p++;
257 __q++;
258 }
259 }
260
261 template<typename _CharT>
262 typename collate<_CharT>::string_type
263 collate<_CharT>::
264 do_transform(const _CharT* __lo, const _CharT* __hi) const
265 {
266 string_type __ret;
267
268 // strxfrm assumes zero-terminated strings so we make a copy
269 const string_type __str(__lo, __hi);
270
271 const _CharT* __p = __str.c_str();
272 const _CharT* __pend = __str.data() + __str.length();
273
274 size_t __len = (__hi - __lo) * 2;
275
276 _CharT* __c = new _CharT[__len];
277
278 __try
279 {
280 // strxfrm stops when it sees a nul character so we break
281 // the string into zero-terminated substrings and pass those
282 // to strxfrm.
283 for (;;)
284 {
285 // First try a buffer perhaps big enough.
286 size_t __res = _M_transform(__c, __p, __len);
287 // If the buffer was not large enough, try again with the
288 // correct size.
289 if (__res >= __len)
290 {
291 __len = __res + 1;
292 delete [] __c, __c = 0;
293 __c = new _CharT[__len];
294 __res = _M_transform(__c, __p, __len);
295 }
296
297 __ret.append(__c, __res);
298 __p += char_traits<_CharT>::length(__p);
299 if (__p == __pend)
300 break;
301
302 __p++;
303 __ret.push_back(_CharT());
304 }
305 }
306 __catch(...)
307 {
308 delete [] __c;
309 __throw_exception_again;
310 }
311
312 delete [] __c;
313
314 return __ret;
315 }
316
317 template<typename _CharT>
318 long
319 collate<_CharT>::
320 do_hash(const _CharT* __lo, const _CharT* __hi) const
321 {
322 unsigned long __val = 0;
323 for (; __lo < __hi; ++__lo)
324 __val =
325 *__lo + ((__val << 7)
326 | (__val >> (__gnu_cxx::__numeric_traits<unsigned long>::
327 __digits - 7)));
328 return static_cast<long>(__val);
329 }
330
331 // Inhibit implicit instantiations for required instantiations,
332 // which are defined via explicit instantiations elsewhere.
333#if _GLIBCXX_EXTERN_TEMPLATE
334 extern template class collate<char>;
335 extern template class collate_byname<char>;
336
337 extern template
338 const collate<char>*
339 __try_use_facet<collate<char> >(const locale&) _GLIBCXX_NOTHROW;
340
341 extern template
342 const collate<char>&
343 use_facet<collate<char> >(const locale&);
344
345 extern template
346 bool
347 has_facet<collate<char> >(const locale&);
348
349#ifdef _GLIBCXX_USE_WCHAR_T
350 extern template class collate<wchar_t>;
351 extern template class collate_byname<wchar_t>;
352
353 extern template
354 const collate<wchar_t>*
355 __try_use_facet<collate<wchar_t> >(const locale&) _GLIBCXX_NOTHROW;
356
357 extern template
358 const collate<wchar_t>&
359 use_facet<collate<wchar_t> >(const locale&);
360
361 extern template
362 bool
363 has_facet<collate<wchar_t> >(const locale&);
364#endif
365#endif
366
367_GLIBCXX_END_NAMESPACE_VERSION
368} // namespace std
369
370#endif
371