Path: blob/main/contrib/llvm-project/libcxx/src/string.cpp
35147 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#ifndef _LIBCPP_HAS_NO_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_LIBCPP_NORETURN _LIBCPP_EXPORTED_FROM_ABI void __throw_length_error() const;31_LIBCPP_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 _LIBCPP_EXTERN_TEMPLATE_DEFINE(...) template __VA_ARGS__;40#ifdef _LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION41_LIBCPP_STRING_UNSTABLE_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, char)42# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS43_LIBCPP_STRING_UNSTABLE_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, wchar_t)44# endif45#else46_LIBCPP_STRING_V1_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, char)47# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS48_LIBCPP_STRING_V1_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, wchar_t)49# endif50#endif51#undef _LIBCPP_EXTERN_TEMPLATE_DEFINE5253template string operator+ <char, char_traits<char>, allocator<char>>(char const*, string const&);5455namespace {5657inline void throw_from_string_out_of_range(const string& func) {58std::__throw_out_of_range((func + ": out of range").c_str());59}6061inline void throw_from_string_invalid_arg(const string& func) {62std::__throw_invalid_argument((func + ": no conversion").c_str());63}6465// as_integer6667template <typename V, typename S, typename F>68inline V as_integer_helper(const string& func, const S& str, size_t* idx, int base, F f) {69typename S::value_type* ptr = nullptr;70const typename S::value_type* const p = str.c_str();71__libcpp_remove_reference_t<decltype(errno)> errno_save = errno;72errno = 0;73V r = f(p, &ptr, base);74swap(errno, errno_save);75if (errno_save == ERANGE)76throw_from_string_out_of_range(func);77if (ptr == p)78throw_from_string_invalid_arg(func);79if (idx)80*idx = static_cast<size_t>(ptr - p);81return r;82}8384template <typename V, typename S>85inline V as_integer(const string& func, const S& s, size_t* idx, int base);8687// string88template <>89inline int as_integer(const string& func, const string& s, size_t* idx, int base) {90// Use long as no Standard string to integer exists.91long r = as_integer_helper<long>(func, s, idx, base, strtol);92if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r)93throw_from_string_out_of_range(func);94return static_cast<int>(r);95}9697template <>98inline long as_integer(const string& func, const string& s, size_t* idx, int base) {99return as_integer_helper<long>(func, s, idx, base, strtol);100}101102template <>103inline unsigned long as_integer(const string& func, const string& s, size_t* idx, int base) {104return as_integer_helper<unsigned long>(func, s, idx, base, strtoul);105}106107template <>108inline long long as_integer(const string& func, const string& s, size_t* idx, int base) {109return as_integer_helper<long long>(func, s, idx, base, strtoll);110}111112template <>113inline unsigned long long as_integer(const string& func, const string& s, size_t* idx, int base) {114return as_integer_helper<unsigned long long>(func, s, idx, base, strtoull);115}116117#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS118// wstring119template <>120inline int as_integer(const string& func, const wstring& s, size_t* idx, int base) {121// Use long as no Stantard string to integer exists.122long r = as_integer_helper<long>(func, s, idx, base, wcstol);123if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r)124throw_from_string_out_of_range(func);125return static_cast<int>(r);126}127128template <>129inline long as_integer(const string& func, const wstring& s, size_t* idx, int base) {130return as_integer_helper<long>(func, s, idx, base, wcstol);131}132133template <>134inline unsigned long as_integer(const string& func, const wstring& s, size_t* idx, int base) {135return as_integer_helper<unsigned long>(func, s, idx, base, wcstoul);136}137138template <>139inline long long as_integer(const string& func, const wstring& s, size_t* idx, int base) {140return as_integer_helper<long long>(func, s, idx, base, wcstoll);141}142143template <>144inline unsigned long long as_integer(const string& func, const wstring& s, size_t* idx, int base) {145return as_integer_helper<unsigned long long>(func, s, idx, base, wcstoull);146}147#endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS148149// as_float150151template <typename V, typename S, typename F>152inline V as_float_helper(const string& func, const S& str, size_t* idx, F f) {153typename S::value_type* ptr = nullptr;154const typename S::value_type* const p = str.c_str();155__libcpp_remove_reference_t<decltype(errno)> errno_save = errno;156errno = 0;157V r = f(p, &ptr);158swap(errno, errno_save);159if (errno_save == ERANGE)160throw_from_string_out_of_range(func);161if (ptr == p)162throw_from_string_invalid_arg(func);163if (idx)164*idx = static_cast<size_t>(ptr - p);165return r;166}167168template <typename V, typename S>169inline V as_float(const string& func, const S& s, size_t* idx = nullptr);170171template <>172inline float as_float(const string& func, const string& s, size_t* idx) {173return as_float_helper<float>(func, s, idx, strtof);174}175176template <>177inline double as_float(const string& func, const string& s, size_t* idx) {178return as_float_helper<double>(func, s, idx, strtod);179}180181template <>182inline long double as_float(const string& func, const string& s, size_t* idx) {183return as_float_helper<long double>(func, s, idx, strtold);184}185186#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS187template <>188inline float as_float(const string& func, const wstring& s, size_t* idx) {189return as_float_helper<float>(func, s, idx, wcstof);190}191192template <>193inline double as_float(const string& func, const wstring& s, size_t* idx) {194return as_float_helper<double>(func, s, idx, wcstod);195}196197template <>198inline long double as_float(const string& func, const wstring& s, size_t* idx) {199return as_float_helper<long double>(func, s, idx, wcstold);200}201#endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS202203} // unnamed namespace204205int stoi(const string& str, size_t* idx, int base) { return as_integer<int>("stoi", str, idx, base); }206207long stol(const string& str, size_t* idx, int base) { return as_integer<long>("stol", str, idx, base); }208209unsigned long stoul(const string& str, size_t* idx, int base) {210return as_integer<unsigned long>("stoul", str, idx, base);211}212213long long stoll(const string& str, size_t* idx, int base) { return as_integer<long long>("stoll", str, idx, base); }214215unsigned long long stoull(const string& str, size_t* idx, int base) {216return as_integer<unsigned long long>("stoull", str, idx, base);217}218219float stof(const string& str, size_t* idx) { return as_float<float>("stof", str, idx); }220221double stod(const string& str, size_t* idx) { return as_float<double>("stod", str, idx); }222223long double stold(const string& str, size_t* idx) { return as_float<long double>("stold", str, idx); }224225#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS226int stoi(const wstring& str, size_t* idx, int base) { return as_integer<int>("stoi", str, idx, base); }227228long stol(const wstring& str, size_t* idx, int base) { return as_integer<long>("stol", str, idx, base); }229230unsigned long stoul(const wstring& str, size_t* idx, int base) {231return as_integer<unsigned long>("stoul", str, idx, base);232}233234long long stoll(const wstring& str, size_t* idx, int base) { return as_integer<long long>("stoll", str, idx, base); }235236unsigned long long stoull(const wstring& str, size_t* idx, int base) {237return as_integer<unsigned long long>("stoull", str, idx, base);238}239240float stof(const wstring& str, size_t* idx) { return as_float<float>("stof", str, idx); }241242double stod(const wstring& str, size_t* idx) { return as_float<double>("stod", str, idx); }243244long double stold(const wstring& str, size_t* idx) { return as_float<long double>("stold", str, idx); }245#endif // !_LIBCPP_HAS_NO_WIDE_CHARACTERS246247// to_string248249namespace {250251// as_string252253template <typename S, typename P, typename V >254inline S as_string(P sprintf_like, S s, const typename S::value_type* fmt, V a) {255typedef typename S::size_type size_type;256size_type available = s.size();257while (true) {258int status = sprintf_like(&s[0], available + 1, fmt, a);259if (status >= 0) {260size_type used = static_cast<size_type>(status);261if (used <= available) {262s.resize(used);263break;264}265available = used; // Assume this is advice of how much space we need.266} else267available = available * 2 + 1;268s.resize(available);269}270return s;271}272273template <class S>274struct initial_string;275276template <>277struct initial_string<string> {278string operator()() const {279string s;280s.resize(s.capacity());281return s;282}283};284285#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS286template <>287struct initial_string<wstring> {288wstring operator()() const {289wstring s(20, wchar_t());290s.resize(s.capacity());291return s;292}293};294295typedef int (*wide_printf)(wchar_t* __restrict, size_t, const wchar_t* __restrict, ...);296297inline wide_printf get_swprintf() {298# ifndef _LIBCPP_MSVCRT299return swprintf;300# else301return static_cast<int(__cdecl*)(wchar_t* __restrict, size_t, const wchar_t* __restrict, ...)>(_snwprintf);302# endif303}304#endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS305306template <typename S, typename V>307S i_to_string(V v) {308// numeric_limits::digits10 returns value less on 1 than desired for unsigned numbers.309// For example, for 1-byte unsigned value digits10 is 2 (999 can not be represented),310// so we need +1 here.311constexpr size_t bufsize = numeric_limits<V>::digits10 + 2; // +1 for minus, +1 for digits10312char buf[bufsize];313const auto res = to_chars(buf, buf + bufsize, v);314_LIBCPP_ASSERT_INTERNAL(res.ec == errc(), "bufsize must be large enough to accomodate the value");315return S(buf, res.ptr);316}317318} // unnamed namespace319320string to_string(int val) { return i_to_string< string>(val); }321string to_string(long val) { return i_to_string< string>(val); }322string to_string(long long val) { return i_to_string< string>(val); }323string to_string(unsigned val) { return i_to_string< string>(val); }324string to_string(unsigned long val) { return i_to_string< string>(val); }325string to_string(unsigned long long val) { return i_to_string< string>(val); }326327#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS328wstring to_wstring(int val) { return i_to_string<wstring>(val); }329wstring to_wstring(long val) { return i_to_string<wstring>(val); }330wstring to_wstring(long long val) { return i_to_string<wstring>(val); }331wstring to_wstring(unsigned val) { return i_to_string<wstring>(val); }332wstring to_wstring(unsigned long val) { return i_to_string<wstring>(val); }333wstring to_wstring(unsigned long long val) { return i_to_string<wstring>(val); }334#endif335336string to_string(float val) { return as_string(snprintf, initial_string< string>()(), "%f", val); }337string to_string(double val) { return as_string(snprintf, initial_string< string>()(), "%f", val); }338string to_string(long double val) { return as_string(snprintf, initial_string< string>()(), "%Lf", val); }339340#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS341wstring to_wstring(float val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%f", val); }342wstring to_wstring(double val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%f", val); }343wstring to_wstring(long double val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%Lf", val); }344#endif345346_LIBCPP_END_NAMESPACE_STD347348349