xref: /freebsd/contrib/llvm-project/libcxx/src/string.cpp (revision 8ddb146abcdf061be9f2c0db7e391697dafad85c)
1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "string"
10 #include "charconv"
11 #include "cstdlib"
12 #include "cerrno"
13 #include "limits"
14 #include "stdexcept"
15 #include <stdio.h>
16 #include "__debug"
17 
18 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
19 #   include "cwchar"
20 #endif
21 
22 _LIBCPP_BEGIN_NAMESPACE_STD
23 
24 #ifndef _LIBCPP_ABI_DO_NOT_EXPORT_BASIC_STRING_COMMON
25 
26 template <bool>
27 struct __basic_string_common;
28 
29 // The struct isn't declared anymore in the headers. It's only here for ABI compatibility.
30 template <>
31 struct __basic_string_common<true> {
32     _LIBCPP_NORETURN _LIBCPP_EXPORTED_FROM_ABI void __throw_length_error() const;
33     _LIBCPP_NORETURN _LIBCPP_EXPORTED_FROM_ABI void __throw_out_of_range() const;
34 };
35 
36 void __basic_string_common<true>::__throw_length_error() const {
37     std::__throw_length_error("basic_string");
38 }
39 void __basic_string_common<true>::__throw_out_of_range() const {
40     std::__throw_out_of_range("basic_string");
41 }
42 
43 #endif // _LIBCPP_ABI_DO_NOT_EXPORT_BASIC_STRING_COMMON
44 
45 #define _LIBCPP_EXTERN_TEMPLATE_DEFINE(...) template __VA_ARGS__;
46 #ifdef _LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION
47     _LIBCPP_STRING_UNSTABLE_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, char)
48 #   ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
49         _LIBCPP_STRING_UNSTABLE_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, wchar_t)
50 #   endif
51 #else
52     _LIBCPP_STRING_V1_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, char)
53 #   ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
54         _LIBCPP_STRING_V1_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, wchar_t)
55 #   endif
56 #endif
57 #undef _LIBCPP_EXTERN_TEMPLATE_DEFINE
58 
59 template string operator+<char, char_traits<char>, allocator<char> >(char const*, string const&);
60 
61 namespace
62 {
63 
64 template<typename T>
65 inline
66 void throw_helper( const string& msg )
67 {
68 #ifndef _LIBCPP_NO_EXCEPTIONS
69     throw T( msg );
70 #else
71     fprintf(stderr, "%s\n", msg.c_str());
72     _VSTD::abort();
73 #endif
74 }
75 
76 inline
77 void throw_from_string_out_of_range( const string& func )
78 {
79     throw_helper<out_of_range>(func + ": out of range");
80 }
81 
82 inline
83 void throw_from_string_invalid_arg( const string& func )
84 {
85     throw_helper<invalid_argument>(func + ": no conversion");
86 }
87 
88 // as_integer
89 
90 template<typename V, typename S, typename F>
91 inline
92 V
93 as_integer_helper(const string& func, const S& str, size_t* idx, int base, F f)
94 {
95     typename S::value_type* ptr = nullptr;
96     const typename S::value_type* const p = str.c_str();
97     typename remove_reference<decltype(errno)>::type errno_save = errno;
98     errno = 0;
99     V r = f(p, &ptr, base);
100     swap(errno, errno_save);
101     if (errno_save == ERANGE)
102         throw_from_string_out_of_range(func);
103     if (ptr == p)
104         throw_from_string_invalid_arg(func);
105     if (idx)
106         *idx = static_cast<size_t>(ptr - p);
107     return r;
108 }
109 
110 template<typename V, typename S>
111 inline
112 V
113 as_integer(const string& func, const S& s, size_t* idx, int base);
114 
115 // string
116 template<>
117 inline
118 int
119 as_integer(const string& func, const string& s, size_t* idx, int base )
120 {
121     // Use long as no Standard string to integer exists.
122     long r = as_integer_helper<long>( func, s, idx, base, strtol );
123     if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r)
124         throw_from_string_out_of_range(func);
125     return static_cast<int>(r);
126 }
127 
128 template<>
129 inline
130 long
131 as_integer(const string& func, const string& s, size_t* idx, int base )
132 {
133     return as_integer_helper<long>( func, s, idx, base, strtol );
134 }
135 
136 template<>
137 inline
138 unsigned long
139 as_integer( const string& func, const string& s, size_t* idx, int base )
140 {
141     return as_integer_helper<unsigned long>( func, s, idx, base, strtoul );
142 }
143 
144 template<>
145 inline
146 long long
147 as_integer( const string& func, const string& s, size_t* idx, int base )
148 {
149     return as_integer_helper<long long>( func, s, idx, base, strtoll );
150 }
151 
152 template<>
153 inline
154 unsigned long long
155 as_integer( const string& func, const string& s, size_t* idx, int base )
156 {
157     return as_integer_helper<unsigned long long>( func, s, idx, base, strtoull );
158 }
159 
160 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
161 // wstring
162 template<>
163 inline
164 int
165 as_integer( const string& func, const wstring& s, size_t* idx, int base )
166 {
167     // Use long as no Stantard string to integer exists.
168     long r = as_integer_helper<long>( func, s, idx, base, wcstol );
169     if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r)
170         throw_from_string_out_of_range(func);
171     return static_cast<int>(r);
172 }
173 
174 template<>
175 inline
176 long
177 as_integer( const string& func, const wstring& s, size_t* idx, int base )
178 {
179     return as_integer_helper<long>( func, s, idx, base, wcstol );
180 }
181 
182 template<>
183 inline
184 unsigned long
185 as_integer( const string& func, const wstring& s, size_t* idx, int base )
186 {
187     return as_integer_helper<unsigned long>( func, s, idx, base, wcstoul );
188 }
189 
190 template<>
191 inline
192 long long
193 as_integer( const string& func, const wstring& s, size_t* idx, int base )
194 {
195     return as_integer_helper<long long>( func, s, idx, base, wcstoll );
196 }
197 
198 template<>
199 inline
200 unsigned long long
201 as_integer( const string& func, const wstring& s, size_t* idx, int base )
202 {
203     return as_integer_helper<unsigned long long>( func, s, idx, base, wcstoull );
204 }
205 #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
206 
207 // as_float
208 
209 template<typename V, typename S, typename F>
210 inline
211 V
212 as_float_helper(const string& func, const S& str, size_t* idx, F f )
213 {
214     typename S::value_type* ptr = nullptr;
215     const typename S::value_type* const p = str.c_str();
216     typename remove_reference<decltype(errno)>::type errno_save = errno;
217     errno = 0;
218     V r = f(p, &ptr);
219     swap(errno, errno_save);
220     if (errno_save == ERANGE)
221         throw_from_string_out_of_range(func);
222     if (ptr == p)
223         throw_from_string_invalid_arg(func);
224     if (idx)
225         *idx = static_cast<size_t>(ptr - p);
226     return r;
227 }
228 
229 template<typename V, typename S>
230 inline
231 V as_float( const string& func, const S& s, size_t* idx = nullptr );
232 
233 template<>
234 inline
235 float
236 as_float( const string& func, const string& s, size_t* idx )
237 {
238     return as_float_helper<float>( func, s, idx, strtof );
239 }
240 
241 template<>
242 inline
243 double
244 as_float(const string& func, const string& s, size_t* idx )
245 {
246     return as_float_helper<double>( func, s, idx, strtod );
247 }
248 
249 template<>
250 inline
251 long double
252 as_float( const string& func, const string& s, size_t* idx )
253 {
254     return as_float_helper<long double>( func, s, idx, strtold );
255 }
256 
257 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
258 template<>
259 inline
260 float
261 as_float( const string& func, const wstring& s, size_t* idx )
262 {
263     return as_float_helper<float>( func, s, idx, wcstof );
264 }
265 
266 template<>
267 inline
268 double
269 as_float( const string& func, const wstring& s, size_t* idx )
270 {
271     return as_float_helper<double>( func, s, idx, wcstod );
272 }
273 
274 template<>
275 inline
276 long double
277 as_float( const string& func, const wstring& s, size_t* idx )
278 {
279     return as_float_helper<long double>( func, s, idx, wcstold );
280 }
281 #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
282 
283 }  // unnamed namespace
284 
285 int
286 stoi(const string& str, size_t* idx, int base)
287 {
288     return as_integer<int>( "stoi", str, idx, base );
289 }
290 
291 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
292 int
293 stoi(const wstring& str, size_t* idx, int base)
294 {
295     return as_integer<int>( "stoi", str, idx, base );
296 }
297 #endif
298 
299 long
300 stol(const string& str, size_t* idx, int base)
301 {
302     return as_integer<long>( "stol", str, idx, base );
303 }
304 
305 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
306 long
307 stol(const wstring& str, size_t* idx, int base)
308 {
309     return as_integer<long>( "stol", str, idx, base );
310 }
311 #endif
312 
313 unsigned long
314 stoul(const string& str, size_t* idx, int base)
315 {
316     return as_integer<unsigned long>( "stoul", str, idx, base );
317 }
318 
319 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
320 unsigned long
321 stoul(const wstring& str, size_t* idx, int base)
322 {
323     return as_integer<unsigned long>( "stoul", str, idx, base );
324 }
325 #endif
326 
327 long long
328 stoll(const string& str, size_t* idx, int base)
329 {
330     return as_integer<long long>( "stoll", str, idx, base );
331 }
332 
333 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
334 long long
335 stoll(const wstring& str, size_t* idx, int base)
336 {
337     return as_integer<long long>( "stoll", str, idx, base );
338 }
339 #endif
340 
341 unsigned long long
342 stoull(const string& str, size_t* idx, int base)
343 {
344     return as_integer<unsigned long long>( "stoull", str, idx, base );
345 }
346 
347 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
348 unsigned long long
349 stoull(const wstring& str, size_t* idx, int base)
350 {
351     return as_integer<unsigned long long>( "stoull", str, idx, base );
352 }
353 #endif
354 
355 float
356 stof(const string& str, size_t* idx)
357 {
358     return as_float<float>( "stof", str, idx );
359 }
360 
361 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
362 float
363 stof(const wstring& str, size_t* idx)
364 {
365     return as_float<float>( "stof", str, idx );
366 }
367 #endif
368 
369 double
370 stod(const string& str, size_t* idx)
371 {
372     return as_float<double>( "stod", str, idx );
373 }
374 
375 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
376 double
377 stod(const wstring& str, size_t* idx)
378 {
379     return as_float<double>( "stod", str, idx );
380 }
381 #endif
382 
383 long double
384 stold(const string& str, size_t* idx)
385 {
386     return as_float<long double>( "stold", str, idx );
387 }
388 
389 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
390 long double
391 stold(const wstring& str, size_t* idx)
392 {
393     return as_float<long double>( "stold", str, idx );
394 }
395 #endif
396 
397 // to_string
398 
399 namespace
400 {
401 
402 // as_string
403 
404 template<typename S, typename P, typename V >
405 inline
406 S
407 as_string(P sprintf_like, S s, const typename S::value_type* fmt, V a)
408 {
409     typedef typename S::size_type size_type;
410     size_type available = s.size();
411     while (true)
412     {
413         int status = sprintf_like(&s[0], available + 1, fmt, a);
414         if ( status >= 0 )
415         {
416             size_type used = static_cast<size_type>(status);
417             if ( used <= available )
418             {
419                 s.resize( used );
420                 break;
421             }
422             available = used; // Assume this is advice of how much space we need.
423         }
424         else
425             available = available * 2 + 1;
426         s.resize(available);
427     }
428     return s;
429 }
430 
431 template <class S>
432 struct initial_string;
433 
434 template <>
435 struct initial_string<string>
436 {
437     string
438     operator()() const
439     {
440         string s;
441         s.resize(s.capacity());
442         return s;
443     }
444 };
445 
446 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
447 template <>
448 struct initial_string<wstring>
449 {
450     wstring
451     operator()() const
452     {
453         wstring s(20, wchar_t());
454         s.resize(s.capacity());
455         return s;
456     }
457 };
458 
459 typedef int (*wide_printf)(wchar_t* __restrict, size_t, const wchar_t*__restrict, ...);
460 
461 inline
462 wide_printf
463 get_swprintf()
464 {
465 #ifndef _LIBCPP_MSVCRT
466     return swprintf;
467 #else
468     return static_cast<int (__cdecl*)(wchar_t* __restrict, size_t, const wchar_t*__restrict, ...)>(_snwprintf);
469 #endif
470 }
471 #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
472 
473 template <typename S, typename V>
474 S i_to_string(V v)
475 {
476 //  numeric_limits::digits10 returns value less on 1 than desired for unsigned numbers.
477 //  For example, for 1-byte unsigned value digits10 is 2 (999 can not be represented),
478 //  so we need +1 here.
479     constexpr size_t bufsize = numeric_limits<V>::digits10 + 2;  // +1 for minus, +1 for digits10
480     char buf[bufsize];
481     const auto res = to_chars(buf, buf + bufsize, v);
482     _LIBCPP_ASSERT(res.ec == errc(), "bufsize must be large enough to accomodate the value");
483     return S(buf, res.ptr);
484 }
485 
486 }  // unnamed namespace
487 
488 string  to_string (int val)                { return i_to_string< string>(val); }
489 string  to_string (long val)               { return i_to_string< string>(val); }
490 string  to_string (long long val)          { return i_to_string< string>(val); }
491 string  to_string (unsigned val)           { return i_to_string< string>(val); }
492 string  to_string (unsigned long val)      { return i_to_string< string>(val); }
493 string  to_string (unsigned long long val) { return i_to_string< string>(val); }
494 
495 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
496 wstring to_wstring(int val)                { return i_to_string<wstring>(val); }
497 wstring to_wstring(long val)               { return i_to_string<wstring>(val); }
498 wstring to_wstring(long long val)          { return i_to_string<wstring>(val); }
499 wstring to_wstring(unsigned val)           { return i_to_string<wstring>(val); }
500 wstring to_wstring(unsigned long val)      { return i_to_string<wstring>(val); }
501 wstring to_wstring(unsigned long long val) { return i_to_string<wstring>(val); }
502 #endif
503 
504 string  to_string (float val)       { return as_string(snprintf,       initial_string< string>()(),   "%f", val); }
505 string  to_string (double val)      { return as_string(snprintf,       initial_string< string>()(),   "%f", val); }
506 string  to_string (long double val) { return as_string(snprintf,       initial_string< string>()(),  "%Lf", val); }
507 
508 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
509 wstring to_wstring(float val)       { return as_string(get_swprintf(), initial_string<wstring>()(),  L"%f", val); }
510 wstring to_wstring(double val)      { return as_string(get_swprintf(), initial_string<wstring>()(),  L"%f", val); }
511 wstring to_wstring(long double val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%Lf", val); }
512 #endif
513 
514 _LIBCPP_END_NAMESPACE_STD
515