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 <__assert>
10#include <cerrno>
11#include <charconv>
12#include <cstdlib>
13#include <limits>
14#include <stdexcept>
15#include <string>
16
17#if _LIBCPP_HAS_WIDE_CHARACTERS
18# include <cwchar>
19#endif
20
21_LIBCPP_BEGIN_NAMESPACE_STD
22
23#if _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 14
24
25template <bool>
26struct __basic_string_common;
27
28// The struct isn't declared anymore in the headers. It's only here for ABI compatibility.
29template <>
30struct __basic_string_common<true> {
31 [[noreturn]] _LIBCPP_EXPORTED_FROM_ABI void __throw_length_error() const;
32 [[noreturn]] _LIBCPP_EXPORTED_FROM_ABI void __throw_out_of_range() const;
33};
34
35void __basic_string_common<true>::__throw_length_error() const { std::__throw_length_error(msg: "basic_string"); }
36void __basic_string_common<true>::__throw_out_of_range() const { std::__throw_out_of_range(msg: "basic_string"); }
37
38#endif // _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 14
39
40// Define legacy ABI functions
41// ---------------------------
42
43#if _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 21
44
45// This initializes the string with [__s, __s + __sz), but capacity() == __reserve. Assumes that __reserve >= __sz.
46template <class _CharT, class _Traits, class _Allocator>
47void basic_string<_CharT, _Traits, _Allocator>::__init(const value_type* __s, size_type __sz, size_type __reserve) {
48 pointer __p = __init_internal_buffer(size: __reserve);
49 __annotate_delete();
50 __set_size(s: __sz);
51 traits_type::copy(std::__to_address(__p), __s, __sz);
52 traits_type::assign(__p[__sz], value_type());
53 __annotate_new(current_size: __sz);
54}
55
56template _LIBCPP_EXPORTED_FROM_ABI void basic_string<char>::__init(const value_type*, size_type, size_type);
57# if _LIBCPP_HAS_WIDE_CHARACTERS
58template _LIBCPP_EXPORTED_FROM_ABI void basic_string<wchar_t>::__init(const value_type*, size_type, size_type);
59# endif
60
61#endif // _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 21
62
63#define _LIBCPP_EXTERN_TEMPLATE_DEFINE(...) template _LIBCPP_EXPORTED_FROM_ABI __VA_ARGS__;
64#ifdef _LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION
65_LIBCPP_STRING_UNSTABLE_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, char)
66# if _LIBCPP_HAS_WIDE_CHARACTERS
67_LIBCPP_STRING_UNSTABLE_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, wchar_t)
68# endif
69#else
70_LIBCPP_STRING_V1_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, char)
71# if _LIBCPP_HAS_WIDE_CHARACTERS
72_LIBCPP_STRING_V1_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, wchar_t)
73# endif
74#endif
75#undef _LIBCPP_EXTERN_TEMPLATE_DEFINE
76
77template string operator+ <char, char_traits<char>, allocator<char>>(char const*, string const&);
78
79namespace {
80
81inline void throw_from_string_out_of_range(const string& func) {
82 std::__throw_out_of_range(msg: (func + ": out of range").c_str());
83}
84
85inline void throw_from_string_invalid_arg(const string& func) {
86 std::__throw_invalid_argument(msg: (func + ": no conversion").c_str());
87}
88
89// as_integer
90
91template <typename V, typename S, typename F>
92inline V as_integer_helper(const string& func, const S& str, size_t* idx, int base, F f) {
93 typename S::value_type* ptr = nullptr;
94 const typename S::value_type* const p = str.c_str();
95 __libcpp_remove_reference_t<decltype(errno)> errno_save = errno;
96 errno = 0;
97 V r = f(p, &ptr, base);
98 swap(errno, y&: errno_save);
99 if (errno_save == ERANGE)
100 throw_from_string_out_of_range(func);
101 if (ptr == p)
102 throw_from_string_invalid_arg(func);
103 if (idx)
104 *idx = static_cast<size_t>(ptr - p);
105 return r;
106}
107
108template <typename V, typename S>
109inline V as_integer(const string& func, const S& s, size_t* idx, int base);
110
111// string
112template <>
113inline int as_integer(const string& func, const string& s, size_t* idx, int base) {
114 // Use long as no Standard string to integer exists.
115 long r = as_integer_helper<long>(func, str: s, idx, base, f: strtol);
116 if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r)
117 throw_from_string_out_of_range(func);
118 return static_cast<int>(r);
119}
120
121template <>
122inline long as_integer(const string& func, const string& s, size_t* idx, int base) {
123 return as_integer_helper<long>(func, str: s, idx, base, f: strtol);
124}
125
126template <>
127inline unsigned long as_integer(const string& func, const string& s, size_t* idx, int base) {
128 return as_integer_helper<unsigned long>(func, str: s, idx, base, f: strtoul);
129}
130
131template <>
132inline long long as_integer(const string& func, const string& s, size_t* idx, int base) {
133 return as_integer_helper<long long>(func, str: s, idx, base, f: strtoll);
134}
135
136template <>
137inline unsigned long long as_integer(const string& func, const string& s, size_t* idx, int base) {
138 return as_integer_helper<unsigned long long>(func, str: s, idx, base, f: strtoull);
139}
140
141#if _LIBCPP_HAS_WIDE_CHARACTERS
142// wstring
143template <>
144inline int as_integer(const string& func, const wstring& s, size_t* idx, int base) {
145 // Use long as no Stantard string to integer exists.
146 long r = as_integer_helper<long>(func, str: s, idx, base, f: wcstol);
147 if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r)
148 throw_from_string_out_of_range(func);
149 return static_cast<int>(r);
150}
151
152template <>
153inline long as_integer(const string& func, const wstring& s, size_t* idx, int base) {
154 return as_integer_helper<long>(func, str: s, idx, base, f: wcstol);
155}
156
157template <>
158inline unsigned long as_integer(const string& func, const wstring& s, size_t* idx, int base) {
159 return as_integer_helper<unsigned long>(func, str: s, idx, base, f: wcstoul);
160}
161
162template <>
163inline long long as_integer(const string& func, const wstring& s, size_t* idx, int base) {
164 return as_integer_helper<long long>(func, str: s, idx, base, f: wcstoll);
165}
166
167template <>
168inline unsigned long long as_integer(const string& func, const wstring& s, size_t* idx, int base) {
169 return as_integer_helper<unsigned long long>(func, str: s, idx, base, f: wcstoull);
170}
171#endif // _LIBCPP_HAS_WIDE_CHARACTERS
172
173// as_float
174
175template <typename V, typename S, typename F>
176inline V as_float_helper(const string& func, const S& str, size_t* idx, F f) {
177 typename S::value_type* ptr = nullptr;
178 const typename S::value_type* const p = str.c_str();
179 __libcpp_remove_reference_t<decltype(errno)> errno_save = errno;
180 errno = 0;
181 V r = f(p, &ptr);
182 swap(errno, y&: errno_save);
183 if (errno_save == ERANGE)
184 throw_from_string_out_of_range(func);
185 if (ptr == p)
186 throw_from_string_invalid_arg(func);
187 if (idx)
188 *idx = static_cast<size_t>(ptr - p);
189 return r;
190}
191
192template <typename V, typename S>
193inline V as_float(const string& func, const S& s, size_t* idx = nullptr);
194
195template <>
196inline float as_float(const string& func, const string& s, size_t* idx) {
197 return as_float_helper<float>(func, str: s, idx, f: strtof);
198}
199
200template <>
201inline double as_float(const string& func, const string& s, size_t* idx) {
202 return as_float_helper<double>(func, str: s, idx, f: strtod);
203}
204
205template <>
206inline long double as_float(const string& func, const string& s, size_t* idx) {
207 return as_float_helper<long double>(func, str: s, idx, f: strtold);
208}
209
210#if _LIBCPP_HAS_WIDE_CHARACTERS
211template <>
212inline float as_float(const string& func, const wstring& s, size_t* idx) {
213 return as_float_helper<float>(func, str: s, idx, f: wcstof);
214}
215
216template <>
217inline double as_float(const string& func, const wstring& s, size_t* idx) {
218 return as_float_helper<double>(func, str: s, idx, f: wcstod);
219}
220
221template <>
222inline long double as_float(const string& func, const wstring& s, size_t* idx) {
223 return as_float_helper<long double>(func, str: s, idx, f: wcstold);
224}
225#endif // _LIBCPP_HAS_WIDE_CHARACTERS
226
227} // unnamed namespace
228
229int stoi(const string& str, size_t* idx, int base) { return as_integer<int>(func: "stoi", s: str, idx, base); }
230
231long stol(const string& str, size_t* idx, int base) { return as_integer<long>(func: "stol", s: str, idx, base); }
232
233unsigned long stoul(const string& str, size_t* idx, int base) {
234 return as_integer<unsigned long>(func: "stoul", s: str, idx, base);
235}
236
237long long stoll(const string& str, size_t* idx, int base) { return as_integer<long long>(func: "stoll", s: str, idx, base); }
238
239unsigned long long stoull(const string& str, size_t* idx, int base) {
240 return as_integer<unsigned long long>(func: "stoull", s: str, idx, base);
241}
242
243float stof(const string& str, size_t* idx) { return as_float<float>(func: "stof", s: str, idx); }
244
245double stod(const string& str, size_t* idx) { return as_float<double>(func: "stod", s: str, idx); }
246
247long double stold(const string& str, size_t* idx) { return as_float<long double>(func: "stold", s: str, idx); }
248
249#if _LIBCPP_HAS_WIDE_CHARACTERS
250int stoi(const wstring& str, size_t* idx, int base) { return as_integer<int>(func: "stoi", s: str, idx, base); }
251
252long stol(const wstring& str, size_t* idx, int base) { return as_integer<long>(func: "stol", s: str, idx, base); }
253
254unsigned long stoul(const wstring& str, size_t* idx, int base) {
255 return as_integer<unsigned long>(func: "stoul", s: str, idx, base);
256}
257
258long long stoll(const wstring& str, size_t* idx, int base) { return as_integer<long long>(func: "stoll", s: str, idx, base); }
259
260unsigned long long stoull(const wstring& str, size_t* idx, int base) {
261 return as_integer<unsigned long long>(func: "stoull", s: str, idx, base);
262}
263
264float stof(const wstring& str, size_t* idx) { return as_float<float>(func: "stof", s: str, idx); }
265
266double stod(const wstring& str, size_t* idx) { return as_float<double>(func: "stod", s: str, idx); }
267
268long double stold(const wstring& str, size_t* idx) { return as_float<long double>(func: "stold", s: str, idx); }
269#endif // _LIBCPP_HAS_WIDE_CHARACTERS
270
271// to_string
272
273namespace {
274
275// as_string
276
277template <typename S, typename P, typename V >
278inline S as_string(P sprintf_like, S s, const typename S::value_type* fmt, V a) {
279 typedef typename S::size_type size_type;
280 size_type available = s.size();
281 while (true) {
282 int status = sprintf_like(&s[0], available + 1, fmt, a);
283 if (status >= 0) {
284 size_type used = static_cast<size_type>(status);
285 if (used <= available) {
286 s.resize(used);
287 break;
288 }
289 available = used; // Assume this is advice of how much space we need.
290 } else
291 available = available * 2 + 1;
292 s.resize(available);
293 }
294 return s;
295}
296
297template <class S>
298struct initial_string;
299
300template <>
301struct initial_string<string> {
302 string operator()() const {
303 string s;
304 s.resize(n: s.capacity());
305 return s;
306 }
307};
308
309#if _LIBCPP_HAS_WIDE_CHARACTERS
310template <>
311struct initial_string<wstring> {
312 wstring operator()() const {
313 wstring s(20, wchar_t());
314 s.resize(n: s.capacity());
315 return s;
316 }
317};
318
319typedef int (*wide_printf)(wchar_t* __restrict, size_t, const wchar_t* __restrict, ...);
320
321inline wide_printf get_swprintf() {
322# ifndef _LIBCPP_MSVCRT
323 return swprintf;
324# else
325 return static_cast<int(__cdecl*)(wchar_t* __restrict, size_t, const wchar_t* __restrict, ...)>(_snwprintf);
326# endif
327}
328#endif // _LIBCPP_HAS_WIDE_CHARACTERS
329
330template <typename S, typename V>
331S i_to_string(V v) {
332 // numeric_limits::digits10 returns value less on 1 than desired for unsigned numbers.
333 // For example, for 1-byte unsigned value digits10 is 2 (999 can not be represented),
334 // so we need +1 here.
335 constexpr size_t bufsize = numeric_limits<V>::digits10 + 2; // +1 for minus, +1 for digits10
336 char buf[bufsize];
337 const auto res = to_chars(buf, buf + bufsize, v);
338 _LIBCPP_ASSERT_INTERNAL(res.ec == errc(), "bufsize must be large enough to accomodate the value");
339 return S(buf, res.ptr);
340}
341
342} // unnamed namespace
343
344string to_string(int val) { return i_to_string< string>(v: val); }
345string to_string(long val) { return i_to_string< string>(v: val); }
346string to_string(long long val) { return i_to_string< string>(v: val); }
347string to_string(unsigned val) { return i_to_string< string>(v: val); }
348string to_string(unsigned long val) { return i_to_string< string>(v: val); }
349string to_string(unsigned long long val) { return i_to_string< string>(v: val); }
350
351#if _LIBCPP_HAS_WIDE_CHARACTERS
352wstring to_wstring(int val) { return i_to_string<wstring>(v: val); }
353wstring to_wstring(long val) { return i_to_string<wstring>(v: val); }
354wstring to_wstring(long long val) { return i_to_string<wstring>(v: val); }
355wstring to_wstring(unsigned val) { return i_to_string<wstring>(v: val); }
356wstring to_wstring(unsigned long val) { return i_to_string<wstring>(v: val); }
357wstring to_wstring(unsigned long long val) { return i_to_string<wstring>(v: val); }
358#endif
359
360string to_string(float val) { return as_string(sprintf_like: snprintf, s: initial_string< string>()(), fmt: "%f", a: val); }
361string to_string(double val) { return as_string(sprintf_like: snprintf, s: initial_string< string>()(), fmt: "%f", a: val); }
362string to_string(long double val) { return as_string(sprintf_like: snprintf, s: initial_string< string>()(), fmt: "%Lf", a: val); }
363
364#if _LIBCPP_HAS_WIDE_CHARACTERS
365wstring to_wstring(float val) { return as_string(sprintf_like: get_swprintf(), s: initial_string<wstring>()(), fmt: L"%f", a: val); }
366wstring to_wstring(double val) { return as_string(sprintf_like: get_swprintf(), s: initial_string<wstring>()(), fmt: L"%f", a: val); }
367wstring to_wstring(long double val) { return as_string(sprintf_like: get_swprintf(), s: initial_string<wstring>()(), fmt: L"%Lf", a: val); }
368#endif
369
370_LIBCPP_END_NAMESPACE_STD
371