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