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