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