1//===------------------------- string.cpp ---------------------------------===// 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 "string" 10#include "charconv" 11#include "cstdlib" 12#include "cwchar" 13#include "cerrno" 14#include "limits" 15#include "stdexcept" 16#include <stdio.h> 17#include "__debug" 18 19_LIBCPP_BEGIN_NAMESPACE_STD 20 21template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __basic_string_common<true>; 22 23#ifdef _LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION 24_LIBCPP_STRING_UNSTABLE_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, char) 25_LIBCPP_STRING_UNSTABLE_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, wchar_t) 26#else 27_LIBCPP_STRING_V1_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, char) 28_LIBCPP_STRING_V1_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, wchar_t) 29#endif 30 31template 32 string 33 operator+<char, char_traits<char>, allocator<char> >(char const*, string const&); 34 35namespace 36{ 37 38template<typename T> 39inline 40void throw_helper( const string& msg ) 41{ 42#ifndef _LIBCPP_NO_EXCEPTIONS 43 throw T( msg ); 44#else 45 fprintf(stderr, "%s\n", msg.c_str()); 46 _VSTD::abort(); 47#endif 48} 49 50inline 51void throw_from_string_out_of_range( const string& func ) 52{ 53 throw_helper<out_of_range>(func + ": out of range"); 54} 55 56inline 57void throw_from_string_invalid_arg( const string& func ) 58{ 59 throw_helper<invalid_argument>(func + ": no conversion"); 60} 61 62// as_integer 63 64template<typename V, typename S, typename F> 65inline 66V 67as_integer_helper(const string& func, const S& str, size_t* idx, int base, F f) 68{ 69 typename S::value_type* ptr = nullptr; 70 const typename S::value_type* const p = str.c_str(); 71 typename remove_reference<decltype(errno)>::type errno_save = errno; 72 errno = 0; 73 V r = f(p, &ptr, base); 74 swap(errno, errno_save); 75 if (errno_save == ERANGE) 76 throw_from_string_out_of_range(func); 77 if (ptr == p) 78 throw_from_string_invalid_arg(func); 79 if (idx) 80 *idx = static_cast<size_t>(ptr - p); 81 return r; 82} 83 84template<typename V, typename S> 85inline 86V 87as_integer(const string& func, const S& s, size_t* idx, int base); 88 89// string 90template<> 91inline 92int 93as_integer(const string& func, const string& s, size_t* idx, int base ) 94{ 95 // Use long as no Standard string to integer exists. 96 long r = as_integer_helper<long>( func, s, idx, base, strtol ); 97 if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r) 98 throw_from_string_out_of_range(func); 99 return static_cast<int>(r); 100} 101 102template<> 103inline 104long 105as_integer(const string& func, const string& s, size_t* idx, int base ) 106{ 107 return as_integer_helper<long>( func, s, idx, base, strtol ); 108} 109 110template<> 111inline 112unsigned long 113as_integer( const string& func, const string& s, size_t* idx, int base ) 114{ 115 return as_integer_helper<unsigned long>( func, s, idx, base, strtoul ); 116} 117 118template<> 119inline 120long long 121as_integer( const string& func, const string& s, size_t* idx, int base ) 122{ 123 return as_integer_helper<long long>( func, s, idx, base, strtoll ); 124} 125 126template<> 127inline 128unsigned long long 129as_integer( const string& func, const string& s, size_t* idx, int base ) 130{ 131 return as_integer_helper<unsigned long long>( func, s, idx, base, strtoull ); 132} 133 134// wstring 135template<> 136inline 137int 138as_integer( const string& func, const wstring& s, size_t* idx, int base ) 139{ 140 // Use long as no Stantard string to integer exists. 141 long r = as_integer_helper<long>( func, s, idx, base, wcstol ); 142 if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r) 143 throw_from_string_out_of_range(func); 144 return static_cast<int>(r); 145} 146 147template<> 148inline 149long 150as_integer( const string& func, const wstring& s, size_t* idx, int base ) 151{ 152 return as_integer_helper<long>( func, s, idx, base, wcstol ); 153} 154 155template<> 156inline 157unsigned long 158as_integer( const string& func, const wstring& s, size_t* idx, int base ) 159{ 160 return as_integer_helper<unsigned long>( func, s, idx, base, wcstoul ); 161} 162 163template<> 164inline 165long long 166as_integer( const string& func, const wstring& s, size_t* idx, int base ) 167{ 168 return as_integer_helper<long long>( func, s, idx, base, wcstoll ); 169} 170 171template<> 172inline 173unsigned long long 174as_integer( const string& func, const wstring& s, size_t* idx, int base ) 175{ 176 return as_integer_helper<unsigned long long>( func, s, idx, base, wcstoull ); 177} 178 179// as_float 180 181template<typename V, typename S, typename F> 182inline 183V 184as_float_helper(const string& func, const S& str, size_t* idx, F f ) 185{ 186 typename S::value_type* ptr = nullptr; 187 const typename S::value_type* const p = str.c_str(); 188 typename remove_reference<decltype(errno)>::type errno_save = errno; 189 errno = 0; 190 V r = f(p, &ptr); 191 swap(errno, errno_save); 192 if (errno_save == ERANGE) 193 throw_from_string_out_of_range(func); 194 if (ptr == p) 195 throw_from_string_invalid_arg(func); 196 if (idx) 197 *idx = static_cast<size_t>(ptr - p); 198 return r; 199} 200 201template<typename V, typename S> 202inline 203V as_float( const string& func, const S& s, size_t* idx = nullptr ); 204 205template<> 206inline 207float 208as_float( const string& func, const string& s, size_t* idx ) 209{ 210 return as_float_helper<float>( func, s, idx, strtof ); 211} 212 213template<> 214inline 215double 216as_float(const string& func, const string& s, size_t* idx ) 217{ 218 return as_float_helper<double>( func, s, idx, strtod ); 219} 220 221template<> 222inline 223long double 224as_float( const string& func, const string& s, size_t* idx ) 225{ 226 return as_float_helper<long double>( func, s, idx, strtold ); 227} 228 229template<> 230inline 231float 232as_float( const string& func, const wstring& s, size_t* idx ) 233{ 234 return as_float_helper<float>( func, s, idx, wcstof ); 235} 236 237template<> 238inline 239double 240as_float( const string& func, const wstring& s, size_t* idx ) 241{ 242 return as_float_helper<double>( func, s, idx, wcstod ); 243} 244 245template<> 246inline 247long double 248as_float( const string& func, const wstring& s, size_t* idx ) 249{ 250 return as_float_helper<long double>( func, s, idx, wcstold ); 251} 252 253} // unnamed namespace 254 255int 256stoi(const string& str, size_t* idx, int base) 257{ 258 return as_integer<int>( "stoi", str, idx, base ); 259} 260 261int 262stoi(const wstring& str, size_t* idx, int base) 263{ 264 return as_integer<int>( "stoi", str, idx, base ); 265} 266 267long 268stol(const string& str, size_t* idx, int base) 269{ 270 return as_integer<long>( "stol", str, idx, base ); 271} 272 273long 274stol(const wstring& str, size_t* idx, int base) 275{ 276 return as_integer<long>( "stol", str, idx, base ); 277} 278 279unsigned long 280stoul(const string& str, size_t* idx, int base) 281{ 282 return as_integer<unsigned long>( "stoul", str, idx, base ); 283} 284 285unsigned long 286stoul(const wstring& str, size_t* idx, int base) 287{ 288 return as_integer<unsigned long>( "stoul", str, idx, base ); 289} 290 291long long 292stoll(const string& str, size_t* idx, int base) 293{ 294 return as_integer<long long>( "stoll", str, idx, base ); 295} 296 297long long 298stoll(const wstring& str, size_t* idx, int base) 299{ 300 return as_integer<long long>( "stoll", str, idx, base ); 301} 302 303unsigned long long 304stoull(const string& str, size_t* idx, int base) 305{ 306 return as_integer<unsigned long long>( "stoull", str, idx, base ); 307} 308 309unsigned long long 310stoull(const wstring& str, size_t* idx, int base) 311{ 312 return as_integer<unsigned long long>( "stoull", str, idx, base ); 313} 314 315float 316stof(const string& str, size_t* idx) 317{ 318 return as_float<float>( "stof", str, idx ); 319} 320 321float 322stof(const wstring& str, size_t* idx) 323{ 324 return as_float<float>( "stof", str, idx ); 325} 326 327double 328stod(const string& str, size_t* idx) 329{ 330 return as_float<double>( "stod", str, idx ); 331} 332 333double 334stod(const wstring& str, size_t* idx) 335{ 336 return as_float<double>( "stod", str, idx ); 337} 338 339long double 340stold(const string& str, size_t* idx) 341{ 342 return as_float<long double>( "stold", str, idx ); 343} 344 345long double 346stold(const wstring& str, size_t* idx) 347{ 348 return as_float<long double>( "stold", str, idx ); 349} 350 351// to_string 352 353namespace 354{ 355 356// as_string 357 358template<typename S, typename P, typename V > 359inline 360S 361as_string(P sprintf_like, S s, const typename S::value_type* fmt, V a) 362{ 363 typedef typename S::size_type size_type; 364 size_type available = s.size(); 365 while (true) 366 { 367 int status = sprintf_like(&s[0], available + 1, fmt, a); 368 if ( status >= 0 ) 369 { 370 size_type used = static_cast<size_type>(status); 371 if ( used <= available ) 372 { 373 s.resize( used ); 374 break; 375 } 376 available = used; // Assume this is advice of how much space we need. 377 } 378 else 379 available = available * 2 + 1; 380 s.resize(available); 381 } 382 return s; 383} 384 385template <class S> 386struct initial_string; 387 388template <> 389struct initial_string<string> 390{ 391 string 392 operator()() const 393 { 394 string s; 395 s.resize(s.capacity()); 396 return s; 397 } 398}; 399 400template <> 401struct initial_string<wstring> 402{ 403 wstring 404 operator()() const 405 { 406 wstring s(20, wchar_t()); 407 s.resize(s.capacity()); 408 return s; 409 } 410}; 411 412typedef int (*wide_printf)(wchar_t* __restrict, size_t, const wchar_t*__restrict, ...); 413 414inline 415wide_printf 416get_swprintf() 417{ 418#ifndef _LIBCPP_MSVCRT 419 return swprintf; 420#else 421 return static_cast<int (__cdecl*)(wchar_t* __restrict, size_t, const wchar_t*__restrict, ...)>(_snwprintf); 422#endif 423} 424 425template <typename S, typename V> 426S i_to_string(const V v) 427{ 428// numeric_limits::digits10 returns value less on 1 than desired for unsigned numbers. 429// For example, for 1-byte unsigned value digits10 is 2 (999 can not be represented), 430// so we need +1 here. 431 constexpr size_t bufsize = numeric_limits<V>::digits10 + 2; // +1 for minus, +1 for digits10 432 char buf[bufsize]; 433 const auto res = to_chars(buf, buf + bufsize, v); 434 _LIBCPP_ASSERT(res.ec == errc(), "bufsize must be large enough to accomodate the value"); 435 return S(buf, res.ptr); 436} 437 438} // unnamed namespace 439 440string to_string (int val) { return i_to_string< string>(val); } 441string to_string (long val) { return i_to_string< string>(val); } 442string to_string (long long val) { return i_to_string< string>(val); } 443string to_string (unsigned val) { return i_to_string< string>(val); } 444string to_string (unsigned long val) { return i_to_string< string>(val); } 445string to_string (unsigned long long val) { return i_to_string< string>(val); } 446 447wstring to_wstring(int val) { return i_to_string<wstring>(val); } 448wstring to_wstring(long val) { return i_to_string<wstring>(val); } 449wstring to_wstring(long long val) { return i_to_string<wstring>(val); } 450wstring to_wstring(unsigned val) { return i_to_string<wstring>(val); } 451wstring to_wstring(unsigned long val) { return i_to_string<wstring>(val); } 452wstring to_wstring(unsigned long long val) { return i_to_string<wstring>(val); } 453 454 455string to_string (float val) { return as_string(snprintf, initial_string< string>()(), "%f", val); } 456string to_string (double val) { return as_string(snprintf, initial_string< string>()(), "%f", val); } 457string to_string (long double val) { return as_string(snprintf, initial_string< string>()(), "%Lf", val); } 458 459wstring to_wstring(float val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%f", val); } 460wstring to_wstring(double val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%f", val); } 461wstring to_wstring(long double val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%Lf", val); } 462 463_LIBCPP_END_NAMESPACE_STD 464