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