[WebAssembly] Add new target feature in support of 'extended-const' proposal
[llvm-project.git] / libcxx / src / string.cpp
blob9d1de0cf6ca1a6c0e27b438201402e3df9225686
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 //===----------------------------------------------------------------------===//
9 #include <__assert>
10 #include <cerrno>
11 #include <charconv>
12 #include <cstdlib>
13 #include <limits>
14 #include <stdexcept>
15 #include <stdio.h>
16 #include <string>
18 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
19 # include <cwchar>
20 #endif
22 _LIBCPP_BEGIN_NAMESPACE_STD
24 #ifndef _LIBCPP_ABI_DO_NOT_EXPORT_BASIC_STRING_COMMON
26 template <bool>
27 struct __basic_string_common;
29 // The struct isn't declared anymore in the headers. It's only here for ABI compatibility.
30 template <>
31 struct __basic_string_common<true> {
32 _LIBCPP_NORETURN _LIBCPP_EXPORTED_FROM_ABI void __throw_length_error() const;
33 _LIBCPP_NORETURN _LIBCPP_EXPORTED_FROM_ABI void __throw_out_of_range() const;
36 void __basic_string_common<true>::__throw_length_error() const {
37 std::__throw_length_error("basic_string");
39 void __basic_string_common<true>::__throw_out_of_range() const {
40 std::__throw_out_of_range("basic_string");
43 #endif // _LIBCPP_ABI_DO_NOT_EXPORT_BASIC_STRING_COMMON
45 #define _LIBCPP_EXTERN_TEMPLATE_DEFINE(...) template __VA_ARGS__;
46 #ifdef _LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION
47 _LIBCPP_STRING_UNSTABLE_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, char)
48 # ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
49 _LIBCPP_STRING_UNSTABLE_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, wchar_t)
50 # endif
51 #else
52 _LIBCPP_STRING_V1_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, char)
53 # ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
54 _LIBCPP_STRING_V1_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, wchar_t)
55 # endif
56 #endif
57 #undef _LIBCPP_EXTERN_TEMPLATE_DEFINE
59 template string operator+<char, char_traits<char>, allocator<char> >(char const*, string const&);
61 namespace
64 template<typename T>
65 inline
66 void throw_helper( const string& msg )
68 #ifndef _LIBCPP_NO_EXCEPTIONS
69 throw T( msg );
70 #else
71 fprintf(stderr, "%s\n", msg.c_str());
72 _VSTD::abort();
73 #endif
76 inline
77 void throw_from_string_out_of_range( const string& func )
79 throw_helper<out_of_range>(func + ": out of range");
82 inline
83 void throw_from_string_invalid_arg( const string& func )
85 throw_helper<invalid_argument>(func + ": no conversion");
88 // as_integer
90 template<typename V, typename S, typename F>
91 inline
93 as_integer_helper(const string& func, const S& str, size_t* idx, int base, F f)
95 typename S::value_type* ptr = nullptr;
96 const typename S::value_type* const p = str.c_str();
97 typename remove_reference<decltype(errno)>::type errno_save = errno;
98 errno = 0;
99 V r = f(p, &ptr, base);
100 swap(errno, errno_save);
101 if (errno_save == ERANGE)
102 throw_from_string_out_of_range(func);
103 if (ptr == p)
104 throw_from_string_invalid_arg(func);
105 if (idx)
106 *idx = static_cast<size_t>(ptr - p);
107 return r;
110 template<typename V, typename S>
111 inline
113 as_integer(const string& func, const S& s, size_t* idx, int base);
115 // string
116 template<>
117 inline
119 as_integer(const string& func, const string& s, size_t* idx, int base )
121 // Use long as no Standard string to integer exists.
122 long r = as_integer_helper<long>( func, s, idx, base, strtol );
123 if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r)
124 throw_from_string_out_of_range(func);
125 return static_cast<int>(r);
128 template<>
129 inline
130 long
131 as_integer(const string& func, const string& s, size_t* idx, int base )
133 return as_integer_helper<long>( func, s, idx, base, strtol );
136 template<>
137 inline
138 unsigned long
139 as_integer( const string& func, const string& s, size_t* idx, int base )
141 return as_integer_helper<unsigned long>( func, s, idx, base, strtoul );
144 template<>
145 inline
146 long long
147 as_integer( const string& func, const string& s, size_t* idx, int base )
149 return as_integer_helper<long long>( func, s, idx, base, strtoll );
152 template<>
153 inline
154 unsigned long long
155 as_integer( const string& func, const string& s, size_t* idx, int base )
157 return as_integer_helper<unsigned long long>( func, s, idx, base, strtoull );
160 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
161 // wstring
162 template<>
163 inline
165 as_integer( const string& func, const wstring& s, size_t* idx, int base )
167 // Use long as no Stantard string to integer exists.
168 long r = as_integer_helper<long>( func, s, idx, base, wcstol );
169 if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r)
170 throw_from_string_out_of_range(func);
171 return static_cast<int>(r);
174 template<>
175 inline
176 long
177 as_integer( const string& func, const wstring& s, size_t* idx, int base )
179 return as_integer_helper<long>( func, s, idx, base, wcstol );
182 template<>
183 inline
184 unsigned long
185 as_integer( const string& func, const wstring& s, size_t* idx, int base )
187 return as_integer_helper<unsigned long>( func, s, idx, base, wcstoul );
190 template<>
191 inline
192 long long
193 as_integer( const string& func, const wstring& s, size_t* idx, int base )
195 return as_integer_helper<long long>( func, s, idx, base, wcstoll );
198 template<>
199 inline
200 unsigned long long
201 as_integer( const string& func, const wstring& s, size_t* idx, int base )
203 return as_integer_helper<unsigned long long>( func, s, idx, base, wcstoull );
205 #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
207 // as_float
209 template<typename V, typename S, typename F>
210 inline
212 as_float_helper(const string& func, const S& str, size_t* idx, F f )
214 typename S::value_type* ptr = nullptr;
215 const typename S::value_type* const p = str.c_str();
216 typename remove_reference<decltype(errno)>::type errno_save = errno;
217 errno = 0;
218 V r = f(p, &ptr);
219 swap(errno, errno_save);
220 if (errno_save == ERANGE)
221 throw_from_string_out_of_range(func);
222 if (ptr == p)
223 throw_from_string_invalid_arg(func);
224 if (idx)
225 *idx = static_cast<size_t>(ptr - p);
226 return r;
229 template<typename V, typename S>
230 inline
231 V as_float( const string& func, const S& s, size_t* idx = nullptr );
233 template<>
234 inline
235 float
236 as_float( const string& func, const string& s, size_t* idx )
238 return as_float_helper<float>( func, s, idx, strtof );
241 template<>
242 inline
243 double
244 as_float(const string& func, const string& s, size_t* idx )
246 return as_float_helper<double>( func, s, idx, strtod );
249 template<>
250 inline
251 long double
252 as_float( const string& func, const string& s, size_t* idx )
254 return as_float_helper<long double>( func, s, idx, strtold );
257 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
258 template<>
259 inline
260 float
261 as_float( const string& func, const wstring& s, size_t* idx )
263 return as_float_helper<float>( func, s, idx, wcstof );
266 template<>
267 inline
268 double
269 as_float( const string& func, const wstring& s, size_t* idx )
271 return as_float_helper<double>( func, s, idx, wcstod );
274 template<>
275 inline
276 long double
277 as_float( const string& func, const wstring& s, size_t* idx )
279 return as_float_helper<long double>( func, s, idx, wcstold );
281 #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
283 } // unnamed namespace
286 stoi(const string& str, size_t* idx, int base)
288 return as_integer<int>( "stoi", str, idx, base );
291 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
293 stoi(const wstring& str, size_t* idx, int base)
295 return as_integer<int>( "stoi", str, idx, base );
297 #endif
299 long
300 stol(const string& str, size_t* idx, int base)
302 return as_integer<long>( "stol", str, idx, base );
305 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
306 long
307 stol(const wstring& str, size_t* idx, int base)
309 return as_integer<long>( "stol", str, idx, base );
311 #endif
313 unsigned long
314 stoul(const string& str, size_t* idx, int base)
316 return as_integer<unsigned long>( "stoul", str, idx, base );
319 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
320 unsigned long
321 stoul(const wstring& str, size_t* idx, int base)
323 return as_integer<unsigned long>( "stoul", str, idx, base );
325 #endif
327 long long
328 stoll(const string& str, size_t* idx, int base)
330 return as_integer<long long>( "stoll", str, idx, base );
333 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
334 long long
335 stoll(const wstring& str, size_t* idx, int base)
337 return as_integer<long long>( "stoll", str, idx, base );
339 #endif
341 unsigned long long
342 stoull(const string& str, size_t* idx, int base)
344 return as_integer<unsigned long long>( "stoull", str, idx, base );
347 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
348 unsigned long long
349 stoull(const wstring& str, size_t* idx, int base)
351 return as_integer<unsigned long long>( "stoull", str, idx, base );
353 #endif
355 float
356 stof(const string& str, size_t* idx)
358 return as_float<float>( "stof", str, idx );
361 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
362 float
363 stof(const wstring& str, size_t* idx)
365 return as_float<float>( "stof", str, idx );
367 #endif
369 double
370 stod(const string& str, size_t* idx)
372 return as_float<double>( "stod", str, idx );
375 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
376 double
377 stod(const wstring& str, size_t* idx)
379 return as_float<double>( "stod", str, idx );
381 #endif
383 long double
384 stold(const string& str, size_t* idx)
386 return as_float<long double>( "stold", str, idx );
389 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
390 long double
391 stold(const wstring& str, size_t* idx)
393 return as_float<long double>( "stold", str, idx );
395 #endif
397 // to_string
399 namespace
402 // as_string
404 template<typename S, typename P, typename V >
405 inline
407 as_string(P sprintf_like, S s, const typename S::value_type* fmt, V a)
409 typedef typename S::size_type size_type;
410 size_type available = s.size();
411 while (true)
413 int status = sprintf_like(&s[0], available + 1, fmt, a);
414 if ( status >= 0 )
416 size_type used = static_cast<size_type>(status);
417 if ( used <= available )
419 s.resize( used );
420 break;
422 available = used; // Assume this is advice of how much space we need.
424 else
425 available = available * 2 + 1;
426 s.resize(available);
428 return s;
431 template <class S>
432 struct initial_string;
434 template <>
435 struct initial_string<string>
437 string
438 operator()() const
440 string s;
441 s.resize(s.capacity());
442 return s;
446 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
447 template <>
448 struct initial_string<wstring>
450 wstring
451 operator()() const
453 wstring s(20, wchar_t());
454 s.resize(s.capacity());
455 return s;
459 typedef int (*wide_printf)(wchar_t* __restrict, size_t, const wchar_t*__restrict, ...);
461 inline
462 wide_printf
463 get_swprintf()
465 #ifndef _LIBCPP_MSVCRT
466 return swprintf;
467 #else
468 return static_cast<int (__cdecl*)(wchar_t* __restrict, size_t, const wchar_t*__restrict, ...)>(_snwprintf);
469 #endif
471 #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
473 template <typename S, typename V>
474 S i_to_string(V v)
476 // numeric_limits::digits10 returns value less on 1 than desired for unsigned numbers.
477 // For example, for 1-byte unsigned value digits10 is 2 (999 can not be represented),
478 // so we need +1 here.
479 constexpr size_t bufsize = numeric_limits<V>::digits10 + 2; // +1 for minus, +1 for digits10
480 char buf[bufsize];
481 const auto res = to_chars(buf, buf + bufsize, v);
482 _LIBCPP_ASSERT(res.ec == errc(), "bufsize must be large enough to accomodate the value");
483 return S(buf, res.ptr);
486 } // unnamed namespace
488 string to_string (int val) { return i_to_string< string>(val); }
489 string to_string (long val) { return i_to_string< string>(val); }
490 string to_string (long long val) { return i_to_string< string>(val); }
491 string to_string (unsigned val) { return i_to_string< string>(val); }
492 string to_string (unsigned long val) { return i_to_string< string>(val); }
493 string to_string (unsigned long long val) { return i_to_string< string>(val); }
495 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
496 wstring to_wstring(int val) { return i_to_string<wstring>(val); }
497 wstring to_wstring(long val) { return i_to_string<wstring>(val); }
498 wstring to_wstring(long long val) { return i_to_string<wstring>(val); }
499 wstring to_wstring(unsigned val) { return i_to_string<wstring>(val); }
500 wstring to_wstring(unsigned long val) { return i_to_string<wstring>(val); }
501 wstring to_wstring(unsigned long long val) { return i_to_string<wstring>(val); }
502 #endif
504 string to_string (float val) { return as_string(snprintf, initial_string< string>()(), "%f", val); }
505 string to_string (double val) { return as_string(snprintf, initial_string< string>()(), "%f", val); }
506 string to_string (long double val) { return as_string(snprintf, initial_string< string>()(), "%Lf", val); }
508 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
509 wstring to_wstring(float val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%f", val); }
510 wstring to_wstring(double val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%f", val); }
511 wstring to_wstring(long double val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%Lf", val); }
512 #endif
514 _LIBCPP_END_NAMESPACE_STD