xref: /freebsd/contrib/llvm-project/libcxx/src/string.cpp (revision 349cc55c9796c4596a5b9904cd3281af295f878f)
1*349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "string"
100b57cec5SDimitry Andric #include "charconv"
110b57cec5SDimitry Andric #include "cstdlib"
120b57cec5SDimitry Andric #include "cerrno"
130b57cec5SDimitry Andric #include "limits"
140b57cec5SDimitry Andric #include "stdexcept"
150b57cec5SDimitry Andric #include <stdio.h>
160b57cec5SDimitry Andric #include "__debug"
170b57cec5SDimitry Andric 
18*349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
19*349cc55cSDimitry Andric #   include "cwchar"
20*349cc55cSDimitry Andric #endif
21*349cc55cSDimitry Andric 
220b57cec5SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
230b57cec5SDimitry Andric 
24*349cc55cSDimitry Andric void __basic_string_common<true>::__throw_length_error() const {
25*349cc55cSDimitry Andric     _VSTD::__throw_length_error("basic_string");
26*349cc55cSDimitry Andric }
27*349cc55cSDimitry Andric 
28*349cc55cSDimitry Andric void __basic_string_common<true>::__throw_out_of_range() const {
29*349cc55cSDimitry Andric     _VSTD::__throw_out_of_range("basic_string");
30*349cc55cSDimitry Andric }
310b57cec5SDimitry Andric 
32fe6060f1SDimitry Andric #define _LIBCPP_EXTERN_TEMPLATE_DEFINE(...) template __VA_ARGS__;
335ffd83dbSDimitry Andric #ifdef _LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION
345ffd83dbSDimitry Andric     _LIBCPP_STRING_UNSTABLE_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, char)
35*349cc55cSDimitry Andric #   ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
365ffd83dbSDimitry Andric         _LIBCPP_STRING_UNSTABLE_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, wchar_t)
37*349cc55cSDimitry Andric #   endif
385ffd83dbSDimitry Andric #else
395ffd83dbSDimitry Andric     _LIBCPP_STRING_V1_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, char)
40*349cc55cSDimitry Andric #   ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
415ffd83dbSDimitry Andric         _LIBCPP_STRING_V1_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, wchar_t)
425ffd83dbSDimitry Andric #   endif
43*349cc55cSDimitry Andric #endif
44fe6060f1SDimitry Andric #undef _LIBCPP_EXTERN_TEMPLATE_DEFINE
450b57cec5SDimitry Andric 
46fe6060f1SDimitry Andric template string operator+<char, char_traits<char>, allocator<char> >(char const*, string const&);
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric namespace
490b57cec5SDimitry Andric {
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric template<typename T>
520b57cec5SDimitry Andric inline
530b57cec5SDimitry Andric void throw_helper( const string& msg )
540b57cec5SDimitry Andric {
550b57cec5SDimitry Andric #ifndef _LIBCPP_NO_EXCEPTIONS
560b57cec5SDimitry Andric     throw T( msg );
570b57cec5SDimitry Andric #else
580b57cec5SDimitry Andric     fprintf(stderr, "%s\n", msg.c_str());
590b57cec5SDimitry Andric     _VSTD::abort();
600b57cec5SDimitry Andric #endif
610b57cec5SDimitry Andric }
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric inline
640b57cec5SDimitry Andric void throw_from_string_out_of_range( const string& func )
650b57cec5SDimitry Andric {
660b57cec5SDimitry Andric     throw_helper<out_of_range>(func + ": out of range");
670b57cec5SDimitry Andric }
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric inline
700b57cec5SDimitry Andric void throw_from_string_invalid_arg( const string& func )
710b57cec5SDimitry Andric {
720b57cec5SDimitry Andric     throw_helper<invalid_argument>(func + ": no conversion");
730b57cec5SDimitry Andric }
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric // as_integer
760b57cec5SDimitry Andric 
770b57cec5SDimitry Andric template<typename V, typename S, typename F>
780b57cec5SDimitry Andric inline
790b57cec5SDimitry Andric V
800b57cec5SDimitry Andric as_integer_helper(const string& func, const S& str, size_t* idx, int base, F f)
810b57cec5SDimitry Andric {
820b57cec5SDimitry Andric     typename S::value_type* ptr = nullptr;
830b57cec5SDimitry Andric     const typename S::value_type* const p = str.c_str();
840b57cec5SDimitry Andric     typename remove_reference<decltype(errno)>::type errno_save = errno;
850b57cec5SDimitry Andric     errno = 0;
860b57cec5SDimitry Andric     V r = f(p, &ptr, base);
870b57cec5SDimitry Andric     swap(errno, errno_save);
880b57cec5SDimitry Andric     if (errno_save == ERANGE)
890b57cec5SDimitry Andric         throw_from_string_out_of_range(func);
900b57cec5SDimitry Andric     if (ptr == p)
910b57cec5SDimitry Andric         throw_from_string_invalid_arg(func);
920b57cec5SDimitry Andric     if (idx)
930b57cec5SDimitry Andric         *idx = static_cast<size_t>(ptr - p);
940b57cec5SDimitry Andric     return r;
950b57cec5SDimitry Andric }
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric template<typename V, typename S>
980b57cec5SDimitry Andric inline
990b57cec5SDimitry Andric V
1000b57cec5SDimitry Andric as_integer(const string& func, const S& s, size_t* idx, int base);
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric // string
1030b57cec5SDimitry Andric template<>
1040b57cec5SDimitry Andric inline
1050b57cec5SDimitry Andric int
1060b57cec5SDimitry Andric as_integer(const string& func, const string& s, size_t* idx, int base )
1070b57cec5SDimitry Andric {
1080b57cec5SDimitry Andric     // Use long as no Standard string to integer exists.
1090b57cec5SDimitry Andric     long r = as_integer_helper<long>( func, s, idx, base, strtol );
1100b57cec5SDimitry Andric     if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r)
1110b57cec5SDimitry Andric         throw_from_string_out_of_range(func);
1120b57cec5SDimitry Andric     return static_cast<int>(r);
1130b57cec5SDimitry Andric }
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric template<>
1160b57cec5SDimitry Andric inline
1170b57cec5SDimitry Andric long
1180b57cec5SDimitry Andric as_integer(const string& func, const string& s, size_t* idx, int base )
1190b57cec5SDimitry Andric {
1200b57cec5SDimitry Andric     return as_integer_helper<long>( func, s, idx, base, strtol );
1210b57cec5SDimitry Andric }
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric template<>
1240b57cec5SDimitry Andric inline
1250b57cec5SDimitry Andric unsigned long
1260b57cec5SDimitry Andric as_integer( const string& func, const string& s, size_t* idx, int base )
1270b57cec5SDimitry Andric {
1280b57cec5SDimitry Andric     return as_integer_helper<unsigned long>( func, s, idx, base, strtoul );
1290b57cec5SDimitry Andric }
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric template<>
1320b57cec5SDimitry Andric inline
1330b57cec5SDimitry Andric long long
1340b57cec5SDimitry Andric as_integer( const string& func, const string& s, size_t* idx, int base )
1350b57cec5SDimitry Andric {
1360b57cec5SDimitry Andric     return as_integer_helper<long long>( func, s, idx, base, strtoll );
1370b57cec5SDimitry Andric }
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric template<>
1400b57cec5SDimitry Andric inline
1410b57cec5SDimitry Andric unsigned long long
1420b57cec5SDimitry Andric as_integer( const string& func, const string& s, size_t* idx, int base )
1430b57cec5SDimitry Andric {
1440b57cec5SDimitry Andric     return as_integer_helper<unsigned long long>( func, s, idx, base, strtoull );
1450b57cec5SDimitry Andric }
1460b57cec5SDimitry Andric 
147*349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
1480b57cec5SDimitry Andric // wstring
1490b57cec5SDimitry Andric template<>
1500b57cec5SDimitry Andric inline
1510b57cec5SDimitry Andric int
1520b57cec5SDimitry Andric as_integer( const string& func, const wstring& s, size_t* idx, int base )
1530b57cec5SDimitry Andric {
1540b57cec5SDimitry Andric     // Use long as no Stantard string to integer exists.
1550b57cec5SDimitry Andric     long r = as_integer_helper<long>( func, s, idx, base, wcstol );
1560b57cec5SDimitry Andric     if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r)
1570b57cec5SDimitry Andric         throw_from_string_out_of_range(func);
1580b57cec5SDimitry Andric     return static_cast<int>(r);
1590b57cec5SDimitry Andric }
1600b57cec5SDimitry Andric 
1610b57cec5SDimitry Andric template<>
1620b57cec5SDimitry Andric inline
1630b57cec5SDimitry Andric long
1640b57cec5SDimitry Andric as_integer( const string& func, const wstring& s, size_t* idx, int base )
1650b57cec5SDimitry Andric {
1660b57cec5SDimitry Andric     return as_integer_helper<long>( func, s, idx, base, wcstol );
1670b57cec5SDimitry Andric }
1680b57cec5SDimitry Andric 
1690b57cec5SDimitry Andric template<>
1700b57cec5SDimitry Andric inline
1710b57cec5SDimitry Andric unsigned long
1720b57cec5SDimitry Andric as_integer( const string& func, const wstring& s, size_t* idx, int base )
1730b57cec5SDimitry Andric {
1740b57cec5SDimitry Andric     return as_integer_helper<unsigned long>( func, s, idx, base, wcstoul );
1750b57cec5SDimitry Andric }
1760b57cec5SDimitry Andric 
1770b57cec5SDimitry Andric template<>
1780b57cec5SDimitry Andric inline
1790b57cec5SDimitry Andric long long
1800b57cec5SDimitry Andric as_integer( const string& func, const wstring& s, size_t* idx, int base )
1810b57cec5SDimitry Andric {
1820b57cec5SDimitry Andric     return as_integer_helper<long long>( func, s, idx, base, wcstoll );
1830b57cec5SDimitry Andric }
1840b57cec5SDimitry Andric 
1850b57cec5SDimitry Andric template<>
1860b57cec5SDimitry Andric inline
1870b57cec5SDimitry Andric unsigned long long
1880b57cec5SDimitry Andric as_integer( const string& func, const wstring& s, size_t* idx, int base )
1890b57cec5SDimitry Andric {
1900b57cec5SDimitry Andric     return as_integer_helper<unsigned long long>( func, s, idx, base, wcstoull );
1910b57cec5SDimitry Andric }
192*349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric // as_float
1950b57cec5SDimitry Andric 
1960b57cec5SDimitry Andric template<typename V, typename S, typename F>
1970b57cec5SDimitry Andric inline
1980b57cec5SDimitry Andric V
1990b57cec5SDimitry Andric as_float_helper(const string& func, const S& str, size_t* idx, F f )
2000b57cec5SDimitry Andric {
2010b57cec5SDimitry Andric     typename S::value_type* ptr = nullptr;
2020b57cec5SDimitry Andric     const typename S::value_type* const p = str.c_str();
2030b57cec5SDimitry Andric     typename remove_reference<decltype(errno)>::type errno_save = errno;
2040b57cec5SDimitry Andric     errno = 0;
2050b57cec5SDimitry Andric     V r = f(p, &ptr);
2060b57cec5SDimitry Andric     swap(errno, errno_save);
2070b57cec5SDimitry Andric     if (errno_save == ERANGE)
2080b57cec5SDimitry Andric         throw_from_string_out_of_range(func);
2090b57cec5SDimitry Andric     if (ptr == p)
2100b57cec5SDimitry Andric         throw_from_string_invalid_arg(func);
2110b57cec5SDimitry Andric     if (idx)
2120b57cec5SDimitry Andric         *idx = static_cast<size_t>(ptr - p);
2130b57cec5SDimitry Andric     return r;
2140b57cec5SDimitry Andric }
2150b57cec5SDimitry Andric 
2160b57cec5SDimitry Andric template<typename V, typename S>
2170b57cec5SDimitry Andric inline
2180b57cec5SDimitry Andric V as_float( const string& func, const S& s, size_t* idx = nullptr );
2190b57cec5SDimitry Andric 
2200b57cec5SDimitry Andric template<>
2210b57cec5SDimitry Andric inline
2220b57cec5SDimitry Andric float
2230b57cec5SDimitry Andric as_float( const string& func, const string& s, size_t* idx )
2240b57cec5SDimitry Andric {
2250b57cec5SDimitry Andric     return as_float_helper<float>( func, s, idx, strtof );
2260b57cec5SDimitry Andric }
2270b57cec5SDimitry Andric 
2280b57cec5SDimitry Andric template<>
2290b57cec5SDimitry Andric inline
2300b57cec5SDimitry Andric double
2310b57cec5SDimitry Andric as_float(const string& func, const string& s, size_t* idx )
2320b57cec5SDimitry Andric {
2330b57cec5SDimitry Andric     return as_float_helper<double>( func, s, idx, strtod );
2340b57cec5SDimitry Andric }
2350b57cec5SDimitry Andric 
2360b57cec5SDimitry Andric template<>
2370b57cec5SDimitry Andric inline
2380b57cec5SDimitry Andric long double
2390b57cec5SDimitry Andric as_float( const string& func, const string& s, size_t* idx )
2400b57cec5SDimitry Andric {
2410b57cec5SDimitry Andric     return as_float_helper<long double>( func, s, idx, strtold );
2420b57cec5SDimitry Andric }
2430b57cec5SDimitry Andric 
244*349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2450b57cec5SDimitry Andric template<>
2460b57cec5SDimitry Andric inline
2470b57cec5SDimitry Andric float
2480b57cec5SDimitry Andric as_float( const string& func, const wstring& s, size_t* idx )
2490b57cec5SDimitry Andric {
2500b57cec5SDimitry Andric     return as_float_helper<float>( func, s, idx, wcstof );
2510b57cec5SDimitry Andric }
2520b57cec5SDimitry Andric 
2530b57cec5SDimitry Andric template<>
2540b57cec5SDimitry Andric inline
2550b57cec5SDimitry Andric double
2560b57cec5SDimitry Andric as_float( const string& func, const wstring& s, size_t* idx )
2570b57cec5SDimitry Andric {
2580b57cec5SDimitry Andric     return as_float_helper<double>( func, s, idx, wcstod );
2590b57cec5SDimitry Andric }
2600b57cec5SDimitry Andric 
2610b57cec5SDimitry Andric template<>
2620b57cec5SDimitry Andric inline
2630b57cec5SDimitry Andric long double
2640b57cec5SDimitry Andric as_float( const string& func, const wstring& s, size_t* idx )
2650b57cec5SDimitry Andric {
2660b57cec5SDimitry Andric     return as_float_helper<long double>( func, s, idx, wcstold );
2670b57cec5SDimitry Andric }
268*349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
2690b57cec5SDimitry Andric 
2700b57cec5SDimitry Andric }  // unnamed namespace
2710b57cec5SDimitry Andric 
2720b57cec5SDimitry Andric int
2730b57cec5SDimitry Andric stoi(const string& str, size_t* idx, int base)
2740b57cec5SDimitry Andric {
2750b57cec5SDimitry Andric     return as_integer<int>( "stoi", str, idx, base );
2760b57cec5SDimitry Andric }
2770b57cec5SDimitry Andric 
278*349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2790b57cec5SDimitry Andric int
2800b57cec5SDimitry Andric stoi(const wstring& str, size_t* idx, int base)
2810b57cec5SDimitry Andric {
2820b57cec5SDimitry Andric     return as_integer<int>( "stoi", str, idx, base );
2830b57cec5SDimitry Andric }
284*349cc55cSDimitry Andric #endif
2850b57cec5SDimitry Andric 
2860b57cec5SDimitry Andric long
2870b57cec5SDimitry Andric stol(const string& str, size_t* idx, int base)
2880b57cec5SDimitry Andric {
2890b57cec5SDimitry Andric     return as_integer<long>( "stol", str, idx, base );
2900b57cec5SDimitry Andric }
2910b57cec5SDimitry Andric 
292*349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
2930b57cec5SDimitry Andric long
2940b57cec5SDimitry Andric stol(const wstring& str, size_t* idx, int base)
2950b57cec5SDimitry Andric {
2960b57cec5SDimitry Andric     return as_integer<long>( "stol", str, idx, base );
2970b57cec5SDimitry Andric }
298*349cc55cSDimitry Andric #endif
2990b57cec5SDimitry Andric 
3000b57cec5SDimitry Andric unsigned long
3010b57cec5SDimitry Andric stoul(const string& str, size_t* idx, int base)
3020b57cec5SDimitry Andric {
3030b57cec5SDimitry Andric     return as_integer<unsigned long>( "stoul", str, idx, base );
3040b57cec5SDimitry Andric }
3050b57cec5SDimitry Andric 
306*349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3070b57cec5SDimitry Andric unsigned long
3080b57cec5SDimitry Andric stoul(const wstring& str, size_t* idx, int base)
3090b57cec5SDimitry Andric {
3100b57cec5SDimitry Andric     return as_integer<unsigned long>( "stoul", str, idx, base );
3110b57cec5SDimitry Andric }
312*349cc55cSDimitry Andric #endif
3130b57cec5SDimitry Andric 
3140b57cec5SDimitry Andric long long
3150b57cec5SDimitry Andric stoll(const string& str, size_t* idx, int base)
3160b57cec5SDimitry Andric {
3170b57cec5SDimitry Andric     return as_integer<long long>( "stoll", str, idx, base );
3180b57cec5SDimitry Andric }
3190b57cec5SDimitry Andric 
320*349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3210b57cec5SDimitry Andric long long
3220b57cec5SDimitry Andric stoll(const wstring& str, size_t* idx, int base)
3230b57cec5SDimitry Andric {
3240b57cec5SDimitry Andric     return as_integer<long long>( "stoll", str, idx, base );
3250b57cec5SDimitry Andric }
326*349cc55cSDimitry Andric #endif
3270b57cec5SDimitry Andric 
3280b57cec5SDimitry Andric unsigned long long
3290b57cec5SDimitry Andric stoull(const string& str, size_t* idx, int base)
3300b57cec5SDimitry Andric {
3310b57cec5SDimitry Andric     return as_integer<unsigned long long>( "stoull", str, idx, base );
3320b57cec5SDimitry Andric }
3330b57cec5SDimitry Andric 
334*349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3350b57cec5SDimitry Andric unsigned long long
3360b57cec5SDimitry Andric stoull(const wstring& str, size_t* idx, int base)
3370b57cec5SDimitry Andric {
3380b57cec5SDimitry Andric     return as_integer<unsigned long long>( "stoull", str, idx, base );
3390b57cec5SDimitry Andric }
340*349cc55cSDimitry Andric #endif
3410b57cec5SDimitry Andric 
3420b57cec5SDimitry Andric float
3430b57cec5SDimitry Andric stof(const string& str, size_t* idx)
3440b57cec5SDimitry Andric {
3450b57cec5SDimitry Andric     return as_float<float>( "stof", str, idx );
3460b57cec5SDimitry Andric }
3470b57cec5SDimitry Andric 
348*349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3490b57cec5SDimitry Andric float
3500b57cec5SDimitry Andric stof(const wstring& str, size_t* idx)
3510b57cec5SDimitry Andric {
3520b57cec5SDimitry Andric     return as_float<float>( "stof", str, idx );
3530b57cec5SDimitry Andric }
354*349cc55cSDimitry Andric #endif
3550b57cec5SDimitry Andric 
3560b57cec5SDimitry Andric double
3570b57cec5SDimitry Andric stod(const string& str, size_t* idx)
3580b57cec5SDimitry Andric {
3590b57cec5SDimitry Andric     return as_float<double>( "stod", str, idx );
3600b57cec5SDimitry Andric }
3610b57cec5SDimitry Andric 
362*349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3630b57cec5SDimitry Andric double
3640b57cec5SDimitry Andric stod(const wstring& str, size_t* idx)
3650b57cec5SDimitry Andric {
3660b57cec5SDimitry Andric     return as_float<double>( "stod", str, idx );
3670b57cec5SDimitry Andric }
368*349cc55cSDimitry Andric #endif
3690b57cec5SDimitry Andric 
3700b57cec5SDimitry Andric long double
3710b57cec5SDimitry Andric stold(const string& str, size_t* idx)
3720b57cec5SDimitry Andric {
3730b57cec5SDimitry Andric     return as_float<long double>( "stold", str, idx );
3740b57cec5SDimitry Andric }
3750b57cec5SDimitry Andric 
376*349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
3770b57cec5SDimitry Andric long double
3780b57cec5SDimitry Andric stold(const wstring& str, size_t* idx)
3790b57cec5SDimitry Andric {
3800b57cec5SDimitry Andric     return as_float<long double>( "stold", str, idx );
3810b57cec5SDimitry Andric }
382*349cc55cSDimitry Andric #endif
3830b57cec5SDimitry Andric 
3840b57cec5SDimitry Andric // to_string
3850b57cec5SDimitry Andric 
3860b57cec5SDimitry Andric namespace
3870b57cec5SDimitry Andric {
3880b57cec5SDimitry Andric 
3890b57cec5SDimitry Andric // as_string
3900b57cec5SDimitry Andric 
3910b57cec5SDimitry Andric template<typename S, typename P, typename V >
3920b57cec5SDimitry Andric inline
3930b57cec5SDimitry Andric S
3940b57cec5SDimitry Andric as_string(P sprintf_like, S s, const typename S::value_type* fmt, V a)
3950b57cec5SDimitry Andric {
3960b57cec5SDimitry Andric     typedef typename S::size_type size_type;
3970b57cec5SDimitry Andric     size_type available = s.size();
3980b57cec5SDimitry Andric     while (true)
3990b57cec5SDimitry Andric     {
4000b57cec5SDimitry Andric         int status = sprintf_like(&s[0], available + 1, fmt, a);
4010b57cec5SDimitry Andric         if ( status >= 0 )
4020b57cec5SDimitry Andric         {
4030b57cec5SDimitry Andric             size_type used = static_cast<size_type>(status);
4040b57cec5SDimitry Andric             if ( used <= available )
4050b57cec5SDimitry Andric             {
4060b57cec5SDimitry Andric                 s.resize( used );
4070b57cec5SDimitry Andric                 break;
4080b57cec5SDimitry Andric             }
4090b57cec5SDimitry Andric             available = used; // Assume this is advice of how much space we need.
4100b57cec5SDimitry Andric         }
4110b57cec5SDimitry Andric         else
4120b57cec5SDimitry Andric             available = available * 2 + 1;
4130b57cec5SDimitry Andric         s.resize(available);
4140b57cec5SDimitry Andric     }
4150b57cec5SDimitry Andric     return s;
4160b57cec5SDimitry Andric }
4170b57cec5SDimitry Andric 
4180b57cec5SDimitry Andric template <class S>
4190b57cec5SDimitry Andric struct initial_string;
4200b57cec5SDimitry Andric 
4210b57cec5SDimitry Andric template <>
4220b57cec5SDimitry Andric struct initial_string<string>
4230b57cec5SDimitry Andric {
4240b57cec5SDimitry Andric     string
4250b57cec5SDimitry Andric     operator()() const
4260b57cec5SDimitry Andric     {
4270b57cec5SDimitry Andric         string s;
4280b57cec5SDimitry Andric         s.resize(s.capacity());
4290b57cec5SDimitry Andric         return s;
4300b57cec5SDimitry Andric     }
4310b57cec5SDimitry Andric };
4320b57cec5SDimitry Andric 
433*349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4340b57cec5SDimitry Andric template <>
4350b57cec5SDimitry Andric struct initial_string<wstring>
4360b57cec5SDimitry Andric {
4370b57cec5SDimitry Andric     wstring
4380b57cec5SDimitry Andric     operator()() const
4390b57cec5SDimitry Andric     {
4400b57cec5SDimitry Andric         wstring s(20, wchar_t());
4410b57cec5SDimitry Andric         s.resize(s.capacity());
4420b57cec5SDimitry Andric         return s;
4430b57cec5SDimitry Andric     }
4440b57cec5SDimitry Andric };
4450b57cec5SDimitry Andric 
4460b57cec5SDimitry Andric typedef int (*wide_printf)(wchar_t* __restrict, size_t, const wchar_t*__restrict, ...);
4470b57cec5SDimitry Andric 
4480b57cec5SDimitry Andric inline
4490b57cec5SDimitry Andric wide_printf
4500b57cec5SDimitry Andric get_swprintf()
4510b57cec5SDimitry Andric {
4520b57cec5SDimitry Andric #ifndef _LIBCPP_MSVCRT
4530b57cec5SDimitry Andric     return swprintf;
4540b57cec5SDimitry Andric #else
4550b57cec5SDimitry Andric     return static_cast<int (__cdecl*)(wchar_t* __restrict, size_t, const wchar_t*__restrict, ...)>(_snwprintf);
4560b57cec5SDimitry Andric #endif
4570b57cec5SDimitry Andric }
458*349cc55cSDimitry Andric #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
4590b57cec5SDimitry Andric 
4600b57cec5SDimitry Andric template <typename S, typename V>
461fe6060f1SDimitry Andric S i_to_string(V v)
4620b57cec5SDimitry Andric {
4630b57cec5SDimitry Andric //  numeric_limits::digits10 returns value less on 1 than desired for unsigned numbers.
4640b57cec5SDimitry Andric //  For example, for 1-byte unsigned value digits10 is 2 (999 can not be represented),
4650b57cec5SDimitry Andric //  so we need +1 here.
4660b57cec5SDimitry Andric     constexpr size_t bufsize = numeric_limits<V>::digits10 + 2;  // +1 for minus, +1 for digits10
4670b57cec5SDimitry Andric     char buf[bufsize];
4680b57cec5SDimitry Andric     const auto res = to_chars(buf, buf + bufsize, v);
4690b57cec5SDimitry Andric     _LIBCPP_ASSERT(res.ec == errc(), "bufsize must be large enough to accomodate the value");
4700b57cec5SDimitry Andric     return S(buf, res.ptr);
4710b57cec5SDimitry Andric }
4720b57cec5SDimitry Andric 
4730b57cec5SDimitry Andric }  // unnamed namespace
4740b57cec5SDimitry Andric 
4750b57cec5SDimitry Andric string  to_string (int val)                { return i_to_string< string>(val); }
4760b57cec5SDimitry Andric string  to_string (long val)               { return i_to_string< string>(val); }
4770b57cec5SDimitry Andric string  to_string (long long val)          { return i_to_string< string>(val); }
4780b57cec5SDimitry Andric string  to_string (unsigned val)           { return i_to_string< string>(val); }
4790b57cec5SDimitry Andric string  to_string (unsigned long val)      { return i_to_string< string>(val); }
4800b57cec5SDimitry Andric string  to_string (unsigned long long val) { return i_to_string< string>(val); }
4810b57cec5SDimitry Andric 
482*349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4830b57cec5SDimitry Andric wstring to_wstring(int val)                { return i_to_string<wstring>(val); }
4840b57cec5SDimitry Andric wstring to_wstring(long val)               { return i_to_string<wstring>(val); }
4850b57cec5SDimitry Andric wstring to_wstring(long long val)          { return i_to_string<wstring>(val); }
4860b57cec5SDimitry Andric wstring to_wstring(unsigned val)           { return i_to_string<wstring>(val); }
4870b57cec5SDimitry Andric wstring to_wstring(unsigned long val)      { return i_to_string<wstring>(val); }
4880b57cec5SDimitry Andric wstring to_wstring(unsigned long long val) { return i_to_string<wstring>(val); }
489*349cc55cSDimitry Andric #endif
4900b57cec5SDimitry Andric 
4910b57cec5SDimitry Andric string  to_string (float val)       { return as_string(snprintf,       initial_string< string>()(),   "%f", val); }
4920b57cec5SDimitry Andric string  to_string (double val)      { return as_string(snprintf,       initial_string< string>()(),   "%f", val); }
4930b57cec5SDimitry Andric string  to_string (long double val) { return as_string(snprintf,       initial_string< string>()(),  "%Lf", val); }
4940b57cec5SDimitry Andric 
495*349cc55cSDimitry Andric #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
4960b57cec5SDimitry Andric wstring to_wstring(float val)       { return as_string(get_swprintf(), initial_string<wstring>()(),  L"%f", val); }
4970b57cec5SDimitry Andric wstring to_wstring(double val)      { return as_string(get_swprintf(), initial_string<wstring>()(),  L"%f", val); }
4980b57cec5SDimitry Andric wstring to_wstring(long double val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%Lf", val); }
499*349cc55cSDimitry Andric #endif
5000b57cec5SDimitry Andric 
5010b57cec5SDimitry Andric _LIBCPP_END_NAMESPACE_STD
502