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