1// Locale support -*- C++ -*-
2
3// Copyright (C) 2007-2022 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 /**
91 * @brief Test for the presence of a facet.
92 * @ingroup locales
93 *
94 * has_facet tests the locale argument for the presence of the facet type
95 * provided as the template parameter. Facets derived from the facet
96 * parameter will also return true.
97 *
98 * @tparam _Facet The facet type to test the presence of.
99 * @param __loc The locale to test.
100 * @return true if @p __loc contains a facet of type _Facet, else false.
101 */
102 template<typename _Facet>
103 bool
104 has_facet(const locale& __loc) throw()
105 {
106 if _GLIBCXX17_CONSTEXPR (__is_same(_Facet, ctype<char>)
107 || __is_same(_Facet, num_get<char>)
108 || __is_same(_Facet, num_put<char>))
109 return true;
110#ifdef _GLIBCXX_USE_WCHAR_T
111 else if _GLIBCXX17_CONSTEXPR (__is_same(_Facet, ctype<wchar_t>)
112 || __is_same(_Facet, num_get<wchar_t>)
113 || __is_same(_Facet, num_put<wchar_t>))
114 return true;
115#endif
116
117 const size_t __i = _Facet::id._M_id();
118 const locale::facet** __facets = __loc._M_impl->_M_facets;
119 return (__i < __loc._M_impl->_M_facets_size
120#if __cpp_rtti
121 && dynamic_cast<const _Facet*>(__facets[__i]));
122#else
123 && static_cast<const _Facet*>(__facets[__i]));
124#endif
125 }
126
127 /**
128 * @brief Return a facet.
129 * @ingroup locales
130 *
131 * use_facet looks for and returns a reference to a facet of type Facet
132 * where Facet is the template parameter. If has_facet(locale) is true,
133 * there is a suitable facet to return. It throws std::bad_cast if the
134 * locale doesn't contain a facet of type Facet.
135 *
136 * @tparam _Facet The facet type to access.
137 * @param __loc The locale to use.
138 * @return Reference to facet of type Facet.
139 * @throw std::bad_cast if @p __loc doesn't contain a facet of type _Facet.
140 */
141 template<typename _Facet>
142 const _Facet&
143 use_facet(const locale& __loc)
144 {
145 const size_t __i = _Facet::id._M_id();
146 const locale::facet** __facets = __loc._M_impl->_M_facets;
147
148 if _GLIBCXX17_CONSTEXPR (__is_same(_Facet, ctype<char>)
149 || __is_same(_Facet, num_get<char>)
150 || __is_same(_Facet, num_put<char>))
151 return static_cast<const _Facet&>(*__facets[__i]);
152#ifdef _GLIBCXX_USE_WCHAR_T
153 else if _GLIBCXX17_CONSTEXPR (__is_same(_Facet, ctype<wchar_t>)
154 || __is_same(_Facet, num_get<wchar_t>)
155 || __is_same(_Facet, num_put<wchar_t>))
156 return static_cast<const _Facet&>(*__facets[__i]);
157#endif
158
159 if (__i >= __loc._M_impl->_M_facets_size || !__facets[__i])
160 __throw_bad_cast();
161#if __cpp_rtti
162 return dynamic_cast<const _Facet&>(*__facets[__i]);
163#else
164 return static_cast<const _Facet&>(*__facets[__i]);
165#endif
166 }
167
168
169 // Generic version does nothing.
170 template<typename _CharT>
171 int
172 collate<_CharT>::_M_compare(const _CharT*, const _CharT*) const throw ()
173 { return 0; }
174
175 // Generic version does nothing.
176 template<typename _CharT>
177 size_t
178 collate<_CharT>::_M_transform(_CharT*, const _CharT*, size_t) const throw ()
179 { return 0; }
180
181 template<typename _CharT>
182 int
183 collate<_CharT>::
184 do_compare(const _CharT* __lo1, const _CharT* __hi1,
185 const _CharT* __lo2, const _CharT* __hi2) const
186 {
187 // strcoll assumes zero-terminated strings so we make a copy
188 // and then put a zero at the end.
189 const string_type __one(__lo1, __hi1);
190 const string_type __two(__lo2, __hi2);
191
192 const _CharT* __p = __one.c_str();
193 const _CharT* __pend = __one.data() + __one.length();
194 const _CharT* __q = __two.c_str();
195 const _CharT* __qend = __two.data() + __two.length();
196
197 // strcoll stops when it sees a nul character so we break
198 // the strings into zero-terminated substrings and pass those
199 // to strcoll.
200 for (;;)
201 {
202 const int __res = _M_compare(__p, __q);
203 if (__res)
204 return __res;
205
206 __p += char_traits<_CharT>::length(__p);
207 __q += char_traits<_CharT>::length(__q);
208 if (__p == __pend && __q == __qend)
209 return 0;
210 else if (__p == __pend)
211 return -1;
212 else if (__q == __qend)
213 return 1;
214
215 __p++;
216 __q++;
217 }
218 }
219
220 template<typename _CharT>
221 typename collate<_CharT>::string_type
222 collate<_CharT>::
223 do_transform(const _CharT* __lo, const _CharT* __hi) const
224 {
225 string_type __ret;
226
227 // strxfrm assumes zero-terminated strings so we make a copy
228 const string_type __str(__lo, __hi);
229
230 const _CharT* __p = __str.c_str();
231 const _CharT* __pend = __str.data() + __str.length();
232
233 size_t __len = (__hi - __lo) * 2;
234
235 _CharT* __c = new _CharT[__len];
236
237 __try
238 {
239 // strxfrm stops when it sees a nul character so we break
240 // the string into zero-terminated substrings and pass those
241 // to strxfrm.
242 for (;;)
243 {
244 // First try a buffer perhaps big enough.
245 size_t __res = _M_transform(__c, __p, __len);
246 // If the buffer was not large enough, try again with the
247 // correct size.
248 if (__res >= __len)
249 {
250 __len = __res + 1;
251 delete [] __c, __c = 0;
252 __c = new _CharT[__len];
253 __res = _M_transform(__c, __p, __len);
254 }
255
256 __ret.append(__c, __res);
257 __p += char_traits<_CharT>::length(__p);
258 if (__p == __pend)
259 break;
260
261 __p++;
262 __ret.push_back(_CharT());
263 }
264 }
265 __catch(...)
266 {
267 delete [] __c;
268 __throw_exception_again;
269 }
270
271 delete [] __c;
272
273 return __ret;
274 }
275
276 template<typename _CharT>
277 long
278 collate<_CharT>::
279 do_hash(const _CharT* __lo, const _CharT* __hi) const
280 {
281 unsigned long __val = 0;
282 for (; __lo < __hi; ++__lo)
283 __val =
284 *__lo + ((__val << 7)
285 | (__val >> (__gnu_cxx::__numeric_traits<unsigned long>::
286 __digits - 7)));
287 return static_cast<long>(__val);
288 }
289
290 // Inhibit implicit instantiations for required instantiations,
291 // which are defined via explicit instantiations elsewhere.
292#if _GLIBCXX_EXTERN_TEMPLATE
293 extern template class collate<char>;
294 extern template class collate_byname<char>;
295
296 extern template
297 const collate<char>&
298 use_facet<collate<char> >(const locale&);
299
300 extern template
301 bool
302 has_facet<collate<char> >(const locale&);
303
304#ifdef _GLIBCXX_USE_WCHAR_T
305 extern template class collate<wchar_t>;
306 extern template class collate_byname<wchar_t>;
307
308 extern template
309 const collate<wchar_t>&
310 use_facet<collate<wchar_t> >(const locale&);
311
312 extern template
313 bool
314 has_facet<collate<wchar_t> >(const locale&);
315#endif
316#endif
317
318_GLIBCXX_END_NAMESPACE_VERSION
319} // namespace std
320
321#endif
322