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