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