Path: blob/main/system/lib/libcxx/src/string.cpp
6175 views
//===----------------------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include <__assert>9#include <cerrno>10#include <charconv>11#include <cstdlib>12#include <limits>13#include <stdexcept>14#include <string>1516#if _LIBCPP_HAS_WIDE_CHARACTERS17# include <cwchar>18#endif1920_LIBCPP_BEGIN_NAMESPACE_STD2122#ifndef _LIBCPP_ABI_DO_NOT_EXPORT_BASIC_STRING_COMMON2324template <bool>25struct __basic_string_common;2627// The struct isn't declared anymore in the headers. It's only here for ABI compatibility.28template <>29struct __basic_string_common<true> {30[[noreturn]] _LIBCPP_EXPORTED_FROM_ABI void __throw_length_error() const;31[[noreturn]] _LIBCPP_EXPORTED_FROM_ABI void __throw_out_of_range() const;32};3334void __basic_string_common<true>::__throw_length_error() const { std::__throw_length_error("basic_string"); }35void __basic_string_common<true>::__throw_out_of_range() const { std::__throw_out_of_range("basic_string"); }3637#endif // _LIBCPP_ABI_DO_NOT_EXPORT_BASIC_STRING_COMMON3839// Define legacy ABI functions40// ---------------------------4142#ifndef _LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION4344template <class _CharT, class _Traits, class _Allocator>45void basic_string<_CharT, _Traits, _Allocator>::__init(const value_type* __s, size_type __sz, size_type __reserve) {46if (__libcpp_is_constant_evaluated())47__rep_ = __rep();48if (__reserve > max_size())49__throw_length_error();50pointer __p;51if (__fits_in_sso(__reserve)) {52__set_short_size(__sz);53__p = __get_short_pointer();54} else {55auto __allocation = std::__allocate_at_least(__alloc_, __recommend(__reserve) + 1);56__p = __allocation.ptr;57__begin_lifetime(__p, __allocation.count);58__set_long_pointer(__p);59__set_long_cap(__allocation.count);60__set_long_size(__sz);61}62traits_type::copy(std::__to_address(__p), __s, __sz);63traits_type::assign(__p[__sz], value_type());64__annotate_new(__sz);65}6667# define STRING_LEGACY_API(CharT) \68template _LIBCPP_EXPORTED_FROM_ABI void basic_string<CharT>::__init(const value_type*, size_type, size_type)6970STRING_LEGACY_API(char);71# if _LIBCPP_HAS_WIDE_CHARACTERS72STRING_LEGACY_API(wchar_t);73# endif7475#endif // _LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION7677#define _LIBCPP_EXTERN_TEMPLATE_DEFINE(...) template _LIBCPP_EXPORTED_FROM_ABI __VA_ARGS__;78#ifdef _LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION79_LIBCPP_STRING_UNSTABLE_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, char)80# if _LIBCPP_HAS_WIDE_CHARACTERS81_LIBCPP_STRING_UNSTABLE_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, wchar_t)82# endif83#else84_LIBCPP_STRING_V1_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, char)85# if _LIBCPP_HAS_WIDE_CHARACTERS86_LIBCPP_STRING_V1_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, wchar_t)87# endif88#endif89#undef _LIBCPP_EXTERN_TEMPLATE_DEFINE9091template string operator+ <char, char_traits<char>, allocator<char>>(char const*, string const&);9293namespace {9495inline void throw_from_string_out_of_range(const string& func) {96std::__throw_out_of_range((func + ": out of range").c_str());97}9899inline void throw_from_string_invalid_arg(const string& func) {100std::__throw_invalid_argument((func + ": no conversion").c_str());101}102103// as_integer104105template <typename V, typename S, typename F>106inline V as_integer_helper(const string& func, const S& str, size_t* idx, int base, F f) {107typename S::value_type* ptr = nullptr;108const typename S::value_type* const p = str.c_str();109__libcpp_remove_reference_t<decltype(errno)> errno_save = errno;110errno = 0;111V r = f(p, &ptr, base);112swap(errno, errno_save);113if (errno_save == ERANGE)114throw_from_string_out_of_range(func);115if (ptr == p)116throw_from_string_invalid_arg(func);117if (idx)118*idx = static_cast<size_t>(ptr - p);119return r;120}121122template <typename V, typename S>123inline V as_integer(const string& func, const S& s, size_t* idx, int base);124125// string126template <>127inline int as_integer(const string& func, const string& s, size_t* idx, int base) {128// Use long as no Standard string to integer exists.129long r = as_integer_helper<long>(func, s, idx, base, strtol);130if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r)131throw_from_string_out_of_range(func);132return static_cast<int>(r);133}134135template <>136inline long as_integer(const string& func, const string& s, size_t* idx, int base) {137return as_integer_helper<long>(func, s, idx, base, strtol);138}139140template <>141inline unsigned long as_integer(const string& func, const string& s, size_t* idx, int base) {142return as_integer_helper<unsigned long>(func, s, idx, base, strtoul);143}144145template <>146inline long long as_integer(const string& func, const string& s, size_t* idx, int base) {147return as_integer_helper<long long>(func, s, idx, base, strtoll);148}149150template <>151inline unsigned long long as_integer(const string& func, const string& s, size_t* idx, int base) {152return as_integer_helper<unsigned long long>(func, s, idx, base, strtoull);153}154155#if _LIBCPP_HAS_WIDE_CHARACTERS156// wstring157template <>158inline int as_integer(const string& func, const wstring& s, size_t* idx, int base) {159// Use long as no Stantard string to integer exists.160long r = as_integer_helper<long>(func, s, idx, base, wcstol);161if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r)162throw_from_string_out_of_range(func);163return static_cast<int>(r);164}165166template <>167inline long as_integer(const string& func, const wstring& s, size_t* idx, int base) {168return as_integer_helper<long>(func, s, idx, base, wcstol);169}170171template <>172inline unsigned long as_integer(const string& func, const wstring& s, size_t* idx, int base) {173return as_integer_helper<unsigned long>(func, s, idx, base, wcstoul);174}175176template <>177inline long long as_integer(const string& func, const wstring& s, size_t* idx, int base) {178return as_integer_helper<long long>(func, s, idx, base, wcstoll);179}180181template <>182inline unsigned long long as_integer(const string& func, const wstring& s, size_t* idx, int base) {183return as_integer_helper<unsigned long long>(func, s, idx, base, wcstoull);184}185#endif // _LIBCPP_HAS_WIDE_CHARACTERS186187// as_float188189template <typename V, typename S, typename F>190inline V as_float_helper(const string& func, const S& str, size_t* idx, F f) {191typename S::value_type* ptr = nullptr;192const typename S::value_type* const p = str.c_str();193__libcpp_remove_reference_t<decltype(errno)> errno_save = errno;194errno = 0;195V r = f(p, &ptr);196swap(errno, errno_save);197if (errno_save == ERANGE)198throw_from_string_out_of_range(func);199if (ptr == p)200throw_from_string_invalid_arg(func);201if (idx)202*idx = static_cast<size_t>(ptr - p);203return r;204}205206template <typename V, typename S>207inline V as_float(const string& func, const S& s, size_t* idx = nullptr);208209template <>210inline float as_float(const string& func, const string& s, size_t* idx) {211return as_float_helper<float>(func, s, idx, strtof);212}213214template <>215inline double as_float(const string& func, const string& s, size_t* idx) {216return as_float_helper<double>(func, s, idx, strtod);217}218219template <>220inline long double as_float(const string& func, const string& s, size_t* idx) {221return as_float_helper<long double>(func, s, idx, strtold);222}223224#if _LIBCPP_HAS_WIDE_CHARACTERS225template <>226inline float as_float(const string& func, const wstring& s, size_t* idx) {227return as_float_helper<float>(func, s, idx, wcstof);228}229230template <>231inline double as_float(const string& func, const wstring& s, size_t* idx) {232return as_float_helper<double>(func, s, idx, wcstod);233}234235template <>236inline long double as_float(const string& func, const wstring& s, size_t* idx) {237return as_float_helper<long double>(func, s, idx, wcstold);238}239#endif // _LIBCPP_HAS_WIDE_CHARACTERS240241} // unnamed namespace242243int stoi(const string& str, size_t* idx, int base) { return as_integer<int>("stoi", str, idx, base); }244245long stol(const string& str, size_t* idx, int base) { return as_integer<long>("stol", str, idx, base); }246247unsigned long stoul(const string& str, size_t* idx, int base) {248return as_integer<unsigned long>("stoul", str, idx, base);249}250251long long stoll(const string& str, size_t* idx, int base) { return as_integer<long long>("stoll", str, idx, base); }252253unsigned long long stoull(const string& str, size_t* idx, int base) {254return as_integer<unsigned long long>("stoull", str, idx, base);255}256257float stof(const string& str, size_t* idx) { return as_float<float>("stof", str, idx); }258259double stod(const string& str, size_t* idx) { return as_float<double>("stod", str, idx); }260261long double stold(const string& str, size_t* idx) { return as_float<long double>("stold", str, idx); }262263#if _LIBCPP_HAS_WIDE_CHARACTERS264int stoi(const wstring& str, size_t* idx, int base) { return as_integer<int>("stoi", str, idx, base); }265266long stol(const wstring& str, size_t* idx, int base) { return as_integer<long>("stol", str, idx, base); }267268unsigned long stoul(const wstring& str, size_t* idx, int base) {269return as_integer<unsigned long>("stoul", str, idx, base);270}271272long long stoll(const wstring& str, size_t* idx, int base) { return as_integer<long long>("stoll", str, idx, base); }273274unsigned long long stoull(const wstring& str, size_t* idx, int base) {275return as_integer<unsigned long long>("stoull", str, idx, base);276}277278float stof(const wstring& str, size_t* idx) { return as_float<float>("stof", str, idx); }279280double stod(const wstring& str, size_t* idx) { return as_float<double>("stod", str, idx); }281282long double stold(const wstring& str, size_t* idx) { return as_float<long double>("stold", str, idx); }283#endif // _LIBCPP_HAS_WIDE_CHARACTERS284285// to_string286287namespace {288289// as_string290291template <typename S, typename P, typename V >292inline S as_string(P sprintf_like, S s, const typename S::value_type* fmt, V a) {293typedef typename S::size_type size_type;294size_type available = s.size();295while (true) {296int status = sprintf_like(&s[0], available + 1, fmt, a);297if (status >= 0) {298size_type used = static_cast<size_type>(status);299if (used <= available) {300s.resize(used);301break;302}303available = used; // Assume this is advice of how much space we need.304} else305available = available * 2 + 1;306s.resize(available);307}308return s;309}310311template <class S>312struct initial_string;313314template <>315struct initial_string<string> {316string operator()() const {317string s;318s.resize(s.capacity());319return s;320}321};322323#if _LIBCPP_HAS_WIDE_CHARACTERS324template <>325struct initial_string<wstring> {326wstring operator()() const {327wstring s(20, wchar_t());328s.resize(s.capacity());329return s;330}331};332333typedef int (*wide_printf)(wchar_t* __restrict, size_t, const wchar_t* __restrict, ...);334335inline wide_printf get_swprintf() {336# ifndef _LIBCPP_MSVCRT337return swprintf;338# else339return static_cast<int(__cdecl*)(wchar_t* __restrict, size_t, const wchar_t* __restrict, ...)>(_snwprintf);340# endif341}342#endif // _LIBCPP_HAS_WIDE_CHARACTERS343344template <typename S, typename V>345S i_to_string(V v) {346// numeric_limits::digits10 returns value less on 1 than desired for unsigned numbers.347// For example, for 1-byte unsigned value digits10 is 2 (999 can not be represented),348// so we need +1 here.349constexpr size_t bufsize = numeric_limits<V>::digits10 + 2; // +1 for minus, +1 for digits10350char buf[bufsize];351const auto res = to_chars(buf, buf + bufsize, v);352_LIBCPP_ASSERT_INTERNAL(res.ec == errc(), "bufsize must be large enough to accomodate the value");353return S(buf, res.ptr);354}355356} // unnamed namespace357358string to_string(int val) { return i_to_string< string>(val); }359string to_string(long val) { return i_to_string< string>(val); }360string to_string(long long val) { return i_to_string< string>(val); }361string to_string(unsigned val) { return i_to_string< string>(val); }362string to_string(unsigned long val) { return i_to_string< string>(val); }363string to_string(unsigned long long val) { return i_to_string< string>(val); }364365#if _LIBCPP_HAS_WIDE_CHARACTERS366wstring to_wstring(int val) { return i_to_string<wstring>(val); }367wstring to_wstring(long val) { return i_to_string<wstring>(val); }368wstring to_wstring(long long val) { return i_to_string<wstring>(val); }369wstring to_wstring(unsigned val) { return i_to_string<wstring>(val); }370wstring to_wstring(unsigned long val) { return i_to_string<wstring>(val); }371wstring to_wstring(unsigned long long val) { return i_to_string<wstring>(val); }372#endif373374string to_string(float val) { return as_string(snprintf, initial_string< string>()(), "%f", val); }375string to_string(double val) { return as_string(snprintf, initial_string< string>()(), "%f", val); }376string to_string(long double val) { return as_string(snprintf, initial_string< string>()(), "%Lf", val); }377378#if _LIBCPP_HAS_WIDE_CHARACTERS379wstring to_wstring(float val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%f", val); }380wstring to_wstring(double val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%f", val); }381wstring to_wstring(long double val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%Lf", val); }382#endif383384_LIBCPP_END_NAMESPACE_STD385386387