master
  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
 25template <bool>
 26struct __basic_string_common;
 27
 28// The struct isn't declared anymore in the headers. It's only here for ABI compatibility.
 29template <>
 30struct __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
 35void __basic_string_common<true>::__throw_length_error() const { std::__throw_length_error("basic_string"); }
 36void __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
 45template <class _CharT, class _Traits, class _Allocator>
 46void 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
 71STRING_LEGACY_API(char);
 72#  if _LIBCPP_HAS_WIDE_CHARACTERS
 73STRING_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
 92template string operator+ <char, char_traits<char>, allocator<char>>(char const*, string const&);
 93
 94namespace {
 95
 96inline void throw_from_string_out_of_range(const string& func) {
 97  std::__throw_out_of_range((func + ": out of range").c_str());
 98}
 99
100inline 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
106template <typename V, typename S, typename F>
107inline 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
123template <typename V, typename S>
124inline V as_integer(const string& func, const S& s, size_t* idx, int base);
125
126// string
127template <>
128inline 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
136template <>
137inline 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
141template <>
142inline 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
146template <>
147inline 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
151template <>
152inline 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
158template <>
159inline 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
167template <>
168inline 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
172template <>
173inline 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
177template <>
178inline 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
182template <>
183inline 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
190template <typename V, typename S, typename F>
191inline 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
207template <typename V, typename S>
208inline V as_float(const string& func, const S& s, size_t* idx = nullptr);
209
210template <>
211inline float as_float(const string& func, const string& s, size_t* idx) {
212  return as_float_helper<float>(func, s, idx, strtof);
213}
214
215template <>
216inline double as_float(const string& func, const string& s, size_t* idx) {
217  return as_float_helper<double>(func, s, idx, strtod);
218}
219
220template <>
221inline 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
226template <>
227inline float as_float(const string& func, const wstring& s, size_t* idx) {
228  return as_float_helper<float>(func, s, idx, wcstof);
229}
230
231template <>
232inline double as_float(const string& func, const wstring& s, size_t* idx) {
233  return as_float_helper<double>(func, s, idx, wcstod);
234}
235
236template <>
237inline 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
244int stoi(const string& str, size_t* idx, int base) { return as_integer<int>("stoi", str, idx, base); }
245
246long stol(const string& str, size_t* idx, int base) { return as_integer<long>("stol", str, idx, base); }
247
248unsigned long stoul(const string& str, size_t* idx, int base) {
249  return as_integer<unsigned long>("stoul", str, idx, base);
250}
251
252long long stoll(const string& str, size_t* idx, int base) { return as_integer<long long>("stoll", str, idx, base); }
253
254unsigned long long stoull(const string& str, size_t* idx, int base) {
255  return as_integer<unsigned long long>("stoull", str, idx, base);
256}
257
258float stof(const string& str, size_t* idx) { return as_float<float>("stof", str, idx); }
259
260double stod(const string& str, size_t* idx) { return as_float<double>("stod", str, idx); }
261
262long double stold(const string& str, size_t* idx) { return as_float<long double>("stold", str, idx); }
263
264#if _LIBCPP_HAS_WIDE_CHARACTERS
265int stoi(const wstring& str, size_t* idx, int base) { return as_integer<int>("stoi", str, idx, base); }
266
267long stol(const wstring& str, size_t* idx, int base) { return as_integer<long>("stol", str, idx, base); }
268
269unsigned long stoul(const wstring& str, size_t* idx, int base) {
270  return as_integer<unsigned long>("stoul", str, idx, base);
271}
272
273long long stoll(const wstring& str, size_t* idx, int base) { return as_integer<long long>("stoll", str, idx, base); }
274
275unsigned long long stoull(const wstring& str, size_t* idx, int base) {
276  return as_integer<unsigned long long>("stoull", str, idx, base);
277}
278
279float stof(const wstring& str, size_t* idx) { return as_float<float>("stof", str, idx); }
280
281double stod(const wstring& str, size_t* idx) { return as_float<double>("stod", str, idx); }
282
283long 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
288namespace {
289
290// as_string
291
292template <typename S, typename P, typename V >
293inline 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
312template <class S>
313struct initial_string;
314
315template <>
316struct 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
325template <>
326struct initial_string<wstring> {
327  wstring operator()() const {
328    wstring s(20, wchar_t());
329    s.resize(s.capacity());
330    return s;
331  }
332};
333
334typedef int (*wide_printf)(wchar_t* __restrict, size_t, const wchar_t* __restrict, ...);
335
336inline 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
345template <typename S, typename V>
346S 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
359string to_string(int val) { return i_to_string< string>(val); }
360string to_string(long val) { return i_to_string< string>(val); }
361string to_string(long long val) { return i_to_string< string>(val); }
362string to_string(unsigned val) { return i_to_string< string>(val); }
363string to_string(unsigned long val) { return i_to_string< string>(val); }
364string to_string(unsigned long long val) { return i_to_string< string>(val); }
365
366#if _LIBCPP_HAS_WIDE_CHARACTERS
367wstring to_wstring(int val) { return i_to_string<wstring>(val); }
368wstring to_wstring(long val) { return i_to_string<wstring>(val); }
369wstring to_wstring(long long val) { return i_to_string<wstring>(val); }
370wstring to_wstring(unsigned val) { return i_to_string<wstring>(val); }
371wstring to_wstring(unsigned long val) { return i_to_string<wstring>(val); }
372wstring to_wstring(unsigned long long val) { return i_to_string<wstring>(val); }
373#endif
374
375string to_string(float val) { return as_string(snprintf, initial_string< string>()(), "%f", val); }
376string to_string(double val) { return as_string(snprintf, initial_string< string>()(), "%f", val); }
377string to_string(long double val) { return as_string(snprintf, initial_string< string>()(), "%Lf", val); }
378
379#if _LIBCPP_HAS_WIDE_CHARACTERS
380wstring to_wstring(float val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%f", val); }
381wstring to_wstring(double val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%f", val); }
382wstring to_wstring(long double val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%Lf", val); }
383#endif
384
385_LIBCPP_END_NAMESPACE_STD