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