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