374 lines · cpp
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-exception6//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_CHARACTERS18# include <cwchar>19#endif20 21_LIBCPP_BEGIN_NAMESPACE_STD22 23#ifndef _LIBCPP_ABI_DO_NOT_EXPORT_BASIC_STRING_COMMON24 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_COMMON39 40// Define legacy ABI functions41// ---------------------------42 43#ifndef _LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION44 45// This initializes the string with [__s, __s + __sz), but capacity() == __reserve. Assumes that __reserve >= __sz.46template <class _CharT, class _Traits, class _Allocator>47void basic_string<_CharT, _Traits, _Allocator>::__init(const value_type* __s, size_type __sz, size_type __reserve) {48 pointer __p = __init_internal_buffer(__reserve);49 __annotate_delete();50 __set_size(__sz);51 traits_type::copy(std::__to_address(__p), __s, __sz);52 traits_type::assign(__p[__sz], value_type());53 __annotate_new(__sz);54}55 56# define STRING_LEGACY_API(CharT) \57 template _LIBCPP_EXPORTED_FROM_ABI void basic_string<CharT>::__init(const value_type*, size_type, size_type)58 59STRING_LEGACY_API(char);60# if _LIBCPP_HAS_WIDE_CHARACTERS61STRING_LEGACY_API(wchar_t);62# endif63 64#endif // _LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION65 66#define _LIBCPP_EXTERN_TEMPLATE_DEFINE(...) template _LIBCPP_EXPORTED_FROM_ABI __VA_ARGS__;67#ifdef _LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION68_LIBCPP_STRING_UNSTABLE_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, char)69# if _LIBCPP_HAS_WIDE_CHARACTERS70_LIBCPP_STRING_UNSTABLE_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, wchar_t)71# endif72#else73_LIBCPP_STRING_V1_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, char)74# if _LIBCPP_HAS_WIDE_CHARACTERS75_LIBCPP_STRING_V1_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, wchar_t)76# endif77#endif78#undef _LIBCPP_EXTERN_TEMPLATE_DEFINE79 80template string operator+ <char, char_traits<char>, allocator<char>>(char const*, string const&);81 82namespace {83 84inline void throw_from_string_out_of_range(const string& func) {85 std::__throw_out_of_range((func + ": out of range").c_str());86}87 88inline void throw_from_string_invalid_arg(const string& func) {89 std::__throw_invalid_argument((func + ": no conversion").c_str());90}91 92// as_integer93 94template <typename V, typename S, typename F>95inline V as_integer_helper(const string& func, const S& str, size_t* idx, int base, F f) {96 typename S::value_type* ptr = nullptr;97 const typename S::value_type* const p = str.c_str();98 __libcpp_remove_reference_t<decltype(errno)> errno_save = errno;99 errno = 0;100 V r = f(p, &ptr, base);101 swap(errno, errno_save);102 if (errno_save == ERANGE)103 throw_from_string_out_of_range(func);104 if (ptr == p)105 throw_from_string_invalid_arg(func);106 if (idx)107 *idx = static_cast<size_t>(ptr - p);108 return r;109}110 111template <typename V, typename S>112inline V as_integer(const string& func, const S& s, size_t* idx, int base);113 114// string115template <>116inline int as_integer(const string& func, const string& s, size_t* idx, int base) {117 // Use long as no Standard string to integer exists.118 long r = as_integer_helper<long>(func, s, idx, base, strtol);119 if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r)120 throw_from_string_out_of_range(func);121 return static_cast<int>(r);122}123 124template <>125inline long as_integer(const string& func, const string& s, size_t* idx, int base) {126 return as_integer_helper<long>(func, s, idx, base, strtol);127}128 129template <>130inline unsigned long as_integer(const string& func, const string& s, size_t* idx, int base) {131 return as_integer_helper<unsigned long>(func, s, idx, base, strtoul);132}133 134template <>135inline long long as_integer(const string& func, const string& s, size_t* idx, int base) {136 return as_integer_helper<long long>(func, s, idx, base, strtoll);137}138 139template <>140inline unsigned long long as_integer(const string& func, const string& s, size_t* idx, int base) {141 return as_integer_helper<unsigned long long>(func, s, idx, base, strtoull);142}143 144#if _LIBCPP_HAS_WIDE_CHARACTERS145// wstring146template <>147inline int as_integer(const string& func, const wstring& s, size_t* idx, int base) {148 // Use long as no Stantard string to integer exists.149 long r = as_integer_helper<long>(func, s, idx, base, wcstol);150 if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r)151 throw_from_string_out_of_range(func);152 return static_cast<int>(r);153}154 155template <>156inline long as_integer(const string& func, const wstring& s, size_t* idx, int base) {157 return as_integer_helper<long>(func, s, idx, base, wcstol);158}159 160template <>161inline unsigned long as_integer(const string& func, const wstring& s, size_t* idx, int base) {162 return as_integer_helper<unsigned long>(func, s, idx, base, wcstoul);163}164 165template <>166inline long long as_integer(const string& func, const wstring& s, size_t* idx, int base) {167 return as_integer_helper<long long>(func, s, idx, base, wcstoll);168}169 170template <>171inline unsigned long long as_integer(const string& func, const wstring& s, size_t* idx, int base) {172 return as_integer_helper<unsigned long long>(func, s, idx, base, wcstoull);173}174#endif // _LIBCPP_HAS_WIDE_CHARACTERS175 176// as_float177 178template <typename V, typename S, typename F>179inline V as_float_helper(const string& func, const S& str, size_t* idx, F f) {180 typename S::value_type* ptr = nullptr;181 const typename S::value_type* const p = str.c_str();182 __libcpp_remove_reference_t<decltype(errno)> errno_save = errno;183 errno = 0;184 V r = f(p, &ptr);185 swap(errno, errno_save);186 if (errno_save == ERANGE)187 throw_from_string_out_of_range(func);188 if (ptr == p)189 throw_from_string_invalid_arg(func);190 if (idx)191 *idx = static_cast<size_t>(ptr - p);192 return r;193}194 195template <typename V, typename S>196inline V as_float(const string& func, const S& s, size_t* idx = nullptr);197 198template <>199inline float as_float(const string& func, const string& s, size_t* idx) {200 return as_float_helper<float>(func, s, idx, strtof);201}202 203template <>204inline double as_float(const string& func, const string& s, size_t* idx) {205 return as_float_helper<double>(func, s, idx, strtod);206}207 208template <>209inline long double as_float(const string& func, const string& s, size_t* idx) {210 return as_float_helper<long double>(func, s, idx, strtold);211}212 213#if _LIBCPP_HAS_WIDE_CHARACTERS214template <>215inline float as_float(const string& func, const wstring& s, size_t* idx) {216 return as_float_helper<float>(func, s, idx, wcstof);217}218 219template <>220inline double as_float(const string& func, const wstring& s, size_t* idx) {221 return as_float_helper<double>(func, s, idx, wcstod);222}223 224template <>225inline long double as_float(const string& func, const wstring& s, size_t* idx) {226 return as_float_helper<long double>(func, s, idx, wcstold);227}228#endif // _LIBCPP_HAS_WIDE_CHARACTERS229 230} // unnamed namespace231 232int stoi(const string& str, size_t* idx, int base) { return as_integer<int>("stoi", str, idx, base); }233 234long stol(const string& str, size_t* idx, int base) { return as_integer<long>("stol", str, idx, base); }235 236unsigned long stoul(const string& str, size_t* idx, int base) {237 return as_integer<unsigned long>("stoul", str, idx, base);238}239 240long long stoll(const string& str, size_t* idx, int base) { return as_integer<long long>("stoll", str, idx, base); }241 242unsigned long long stoull(const string& str, size_t* idx, int base) {243 return as_integer<unsigned long long>("stoull", str, idx, base);244}245 246float stof(const string& str, size_t* idx) { return as_float<float>("stof", str, idx); }247 248double stod(const string& str, size_t* idx) { return as_float<double>("stod", str, idx); }249 250long double stold(const string& str, size_t* idx) { return as_float<long double>("stold", str, idx); }251 252#if _LIBCPP_HAS_WIDE_CHARACTERS253int stoi(const wstring& str, size_t* idx, int base) { return as_integer<int>("stoi", str, idx, base); }254 255long stol(const wstring& str, size_t* idx, int base) { return as_integer<long>("stol", str, idx, base); }256 257unsigned long stoul(const wstring& str, size_t* idx, int base) {258 return as_integer<unsigned long>("stoul", str, idx, base);259}260 261long long stoll(const wstring& str, size_t* idx, int base) { return as_integer<long long>("stoll", str, idx, base); }262 263unsigned long long stoull(const wstring& str, size_t* idx, int base) {264 return as_integer<unsigned long long>("stoull", str, idx, base);265}266 267float stof(const wstring& str, size_t* idx) { return as_float<float>("stof", str, idx); }268 269double stod(const wstring& str, size_t* idx) { return as_float<double>("stod", str, idx); }270 271long double stold(const wstring& str, size_t* idx) { return as_float<long double>("stold", str, idx); }272#endif // _LIBCPP_HAS_WIDE_CHARACTERS273 274// to_string275 276namespace {277 278// as_string279 280template <typename S, typename P, typename V >281inline S as_string(P sprintf_like, S s, const typename S::value_type* fmt, V a) {282 typedef typename S::size_type size_type;283 size_type available = s.size();284 while (true) {285 int status = sprintf_like(&s[0], available + 1, fmt, a);286 if (status >= 0) {287 size_type used = static_cast<size_type>(status);288 if (used <= available) {289 s.resize(used);290 break;291 }292 available = used; // Assume this is advice of how much space we need.293 } else294 available = available * 2 + 1;295 s.resize(available);296 }297 return s;298}299 300template <class S>301struct initial_string;302 303template <>304struct initial_string<string> {305 string operator()() const {306 string s;307 s.resize(s.capacity());308 return s;309 }310};311 312#if _LIBCPP_HAS_WIDE_CHARACTERS313template <>314struct initial_string<wstring> {315 wstring operator()() const {316 wstring s(20, wchar_t());317 s.resize(s.capacity());318 return s;319 }320};321 322typedef int (*wide_printf)(wchar_t* __restrict, size_t, const wchar_t* __restrict, ...);323 324inline wide_printf get_swprintf() {325# ifndef _LIBCPP_MSVCRT326 return swprintf;327# else328 return static_cast<int(__cdecl*)(wchar_t* __restrict, size_t, const wchar_t* __restrict, ...)>(_snwprintf);329# endif330}331#endif // _LIBCPP_HAS_WIDE_CHARACTERS332 333template <typename S, typename V>334S i_to_string(V v) {335 // numeric_limits::digits10 returns value less on 1 than desired for unsigned numbers.336 // For example, for 1-byte unsigned value digits10 is 2 (999 can not be represented),337 // so we need +1 here.338 constexpr size_t bufsize = numeric_limits<V>::digits10 + 2; // +1 for minus, +1 for digits10339 char buf[bufsize];340 const auto res = to_chars(buf, buf + bufsize, v);341 _LIBCPP_ASSERT_INTERNAL(res.ec == errc(), "bufsize must be large enough to accomodate the value");342 return S(buf, res.ptr);343}344 345} // unnamed namespace346 347string to_string(int val) { return i_to_string< string>(val); }348string to_string(long val) { return i_to_string< string>(val); }349string to_string(long long val) { return i_to_string< string>(val); }350string to_string(unsigned val) { return i_to_string< string>(val); }351string to_string(unsigned long val) { return i_to_string< string>(val); }352string to_string(unsigned long long val) { return i_to_string< string>(val); }353 354#if _LIBCPP_HAS_WIDE_CHARACTERS355wstring to_wstring(int val) { return i_to_string<wstring>(val); }356wstring to_wstring(long val) { return i_to_string<wstring>(val); }357wstring to_wstring(long long val) { return i_to_string<wstring>(val); }358wstring to_wstring(unsigned val) { return i_to_string<wstring>(val); }359wstring to_wstring(unsigned long val) { return i_to_string<wstring>(val); }360wstring to_wstring(unsigned long long val) { return i_to_string<wstring>(val); }361#endif362 363string to_string(float val) { return as_string(snprintf, initial_string< string>()(), "%f", val); }364string to_string(double val) { return as_string(snprintf, initial_string< string>()(), "%f", val); }365string to_string(long double val) { return as_string(snprintf, initial_string< string>()(), "%Lf", val); }366 367#if _LIBCPP_HAS_WIDE_CHARACTERS368wstring to_wstring(float val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%f", val); }369wstring to_wstring(double val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%f", val); }370wstring to_wstring(long double val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%Lf", val); }371#endif372 373_LIBCPP_END_NAMESPACE_STD374