Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
emscripten-core
GitHub Repository: emscripten-core/emscripten
Path: blob/main/system/lib/libcxx/src/string.cpp
6175 views
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, s, idx, base, 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, s, idx, base, 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, s, idx, base, 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, s, idx, base, 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, s, idx, base, 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, s, idx, 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, s, idx, 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, s, idx, 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>("stoi", str, idx, base); }
245
246
long stol(const string& str, size_t* idx, int base) { return as_integer<long>("stol", str, idx, base); }
247
248
unsigned long stoul(const string& str, size_t* idx, int base) {
249
return as_integer<unsigned long>("stoul", str, idx, base);
250
}
251
252
long long stoll(const string& str, size_t* idx, int base) { return as_integer<long long>("stoll", str, idx, base); }
253
254
unsigned long long stoull(const string& str, size_t* idx, int base) {
255
return as_integer<unsigned long long>("stoull", str, idx, base);
256
}
257
258
float stof(const string& str, size_t* idx) { return as_float<float>("stof", str, idx); }
259
260
double stod(const string& str, size_t* idx) { return as_float<double>("stod", 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
387