xref: /freebsd/contrib/llvm-project/libcxx/src/string.cpp (revision 770cf0a5f02dc8983a89c6568d741fbc25baa999)
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