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