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