From 9e98b34a8c03460dacab05068d900dd424e45e53 Mon Sep 17 00:00:00 2001 From: Howard Hinnant Date: Thu, 16 May 2013 17:13:40 +0000 Subject: [PATCH] Glen: This patch gets the string conversion functions working on Windows. It also refactors repetitive code in string.cpp do greatly reduce the repetitiveness, increasing maintainability. git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@182026 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/support/win32/support.h | 17 +- src/string.cpp | 853 ++++++++++++----------------- src/support/win32/locale_win32.cpp | 4 +- src/support/win32/support.cpp | 57 +- 4 files changed, 393 insertions(+), 538 deletions(-) diff --git a/include/support/win32/support.h b/include/support/win32/support.h index 0b8a912a..81cb13a9 100644 --- a/include/support/win32/support.h +++ b/include/support/win32/support.h @@ -15,26 +15,23 @@ Functions and constants used in libc++ that are missing from the Windows C library. */ -#include <__config> -#include // mbstate_t -#include // _snwprintf +#include // mbstate_t +#include // va_ macros #define swprintf _snwprintf #define vswprintf _vsnwprintf -#define vfscnaf fscanf -int vasprintf( char **sptr, const char *__restrict fmt , va_list ap ); +extern "C" { + +int vasprintf( char **sptr, const char *__restrict fmt, va_list ap ); int asprintf( char **sptr, const char *__restrict fmt, ...); -//int vfscanf( FILE *__restrict stream, const char *__restrict format, -// va_list arg); - size_t mbsnrtowcs( wchar_t *__restrict dst, const char **__restrict src, size_t nmc, size_t len, mbstate_t *__restrict ps ); size_t wcsnrtombs( char *__restrict dst, const wchar_t **__restrict src, size_t nwc, size_t len, mbstate_t *__restrict ps ); +} #if defined(_MSC_VER) #define snprintf _snprintf - #include #define atoll _atoi64 #define strtoll _strtoi64 @@ -85,9 +82,11 @@ _LIBCPP_ALWAYS_INLINE int __builtin_ctz( unsigned int x ) _BitScanReverse(&r, x); return static_cast(r); } + // sizeof(long) == sizeof(int) on Windows _LIBCPP_ALWAYS_INLINE int __builtin_ctzl( unsigned long x ) { return __builtin_ctz( static_cast(x) ); } + _LIBCPP_ALWAYS_INLINE int __builtin_ctzll( unsigned long long x ) { DWORD r = 0; diff --git a/src/string.cpp b/src/string.cpp index c71af4fe..c6fe408c 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -11,6 +11,8 @@ #include "cstdlib" #include "cwchar" #include "cerrno" +#include "limits" +#include "stdexcept" #ifdef _WIN32 #include "support/win32/support.h" #endif // _WIN32 @@ -26,662 +28,499 @@ template string operator+, allocator >(char const*, string const&); +namespace +{ + +template +inline +void throw_helper( const string& msg ) +{ +#ifndef _LIBCPP_NO_EXCEPTIONS + throw T( msg ); +#else + abort(); +#endif +} + +inline +void throw_from_string_out_of_range( const string& func ) +{ + throw_helper(func + ": out of range"); +} + +inline +void throw_from_string_invalid_arg( const string& func ) +{ + throw_helper(func + ": no conversion"); +} + +// as_integer + +template +inline +V +as_integer_helper(const string& func, const S& str, size_t* idx, int base, F f) +{ + typename S::value_type* ptr; + const typename S::value_type* const p = str.c_str(); + typename remove_reference::type errno_save = errno; + errno = 0; + V r = f(p, &ptr, base); + swap(errno, errno_save); + if (errno_save == ERANGE) + throw_from_string_out_of_range(func); + if (ptr == p) + throw_from_string_invalid_arg(func); + if (idx) + *idx = static_cast(ptr - p); + return r; +} + +template +inline +V +as_integer(const string& func, const S& s, size_t* idx, int base); + +// string +template<> +inline +int +as_integer(const string& func, const string& s, size_t* idx, int base ) +{ + // Use long as no Stantard string to integer exists. + long r = as_integer_helper( func, s, idx, base, strtol ); + if (r < numeric_limits::min() || numeric_limits::max() < r) + throw_from_string_out_of_range(func); + return static_cast(r); +} + +template<> +inline +long +as_integer(const string& func, const string& s, size_t* idx, int base ) +{ + return as_integer_helper( func, s, idx, base, strtol ); +} + +template<> +inline +unsigned long +as_integer( const string& func, const string& s, size_t* idx, int base ) +{ + return as_integer_helper( func, s, idx, base, strtoul ); +} + +template<> +inline +long long +as_integer( const string& func, const string& s, size_t* idx, int base ) +{ + return as_integer_helper( func, s, idx, base, strtoll ); +} + +template<> +inline +unsigned long long +as_integer( const string& func, const string& s, size_t* idx, int base ) +{ + return as_integer_helper( func, s, idx, base, strtoull ); +} + +// wstring +template<> +inline +int +as_integer( const string& func, const wstring& s, size_t* idx, int base ) +{ + // Use long as no Stantard string to integer exists. + long r = as_integer_helper( func, s, idx, base, wcstol ); + if (r < numeric_limits::min() || numeric_limits::max() < r) + throw_from_string_out_of_range(func); + return static_cast(r); +} + +template<> +inline +long +as_integer( const string& func, const wstring& s, size_t* idx, int base ) +{ + return as_integer_helper( func, s, idx, base, wcstol ); +} + +template<> +inline +unsigned long +as_integer( const string& func, const wstring& s, size_t* idx, int base ) +{ + return as_integer_helper( func, s, idx, base, wcstoul ); +} + +template<> +inline +long long +as_integer( const string& func, const wstring& s, size_t* idx, int base ) +{ + return as_integer_helper( func, s, idx, base, wcstoll ); +} + +template<> +inline +unsigned long long +as_integer( const string& func, const wstring& s, size_t* idx, int base ) +{ + return as_integer_helper( func, s, idx, base, wcstoull ); +} + +// as_float + +template +inline +V +as_float_helper(const string& func, const S& str, size_t* idx, F f ) +{ + typename S::value_type* ptr; + const typename S::value_type* const p = str.c_str(); + typename remove_reference::type errno_save = errno; + errno = 0; + V r = f(p, &ptr); + swap(errno, errno_save); + if (errno_save == ERANGE) + throw_from_string_out_of_range(func); + if (ptr == p) + throw_from_string_invalid_arg(func); + if (idx) + *idx = static_cast(ptr - p); + return r; +} + +template +inline +V as_float( const string& func, const S& s, size_t* idx = nullptr ); + +template<> +inline +float +as_float( const string& func, const string& s, size_t* idx ) +{ + return as_float_helper( func, s, idx, strtof ); +} + +template<> +inline +double +as_float(const string& func, const string& s, size_t* idx ) +{ + return as_float_helper( func, s, idx, strtod ); +} + +template<> +inline +long double +as_float( const string& func, const string& s, size_t* idx ) +{ + return as_float_helper( func, s, idx, strtold ); +} + +template<> +inline +float +as_float( const string& func, const wstring& s, size_t* idx ) +{ + return as_float_helper( func, s, idx, wcstof ); +} + +template<> +inline +double +as_float( const string& func, const wstring& s, size_t* idx ) +{ + return as_float_helper( func, s, idx, wcstod ); +} + +template<> +inline +long double +as_float( const string& func, const wstring& s, size_t* idx ) +{ + return as_float_helper( func, s, idx, wcstold ); +} + +} // unnamed namespace + int stoi(const string& str, size_t* idx, int base) { - char* ptr; - const char* const p = str.c_str(); - typename remove_reference::type errno_save = errno; - errno = 0; - long r = strtol(p, &ptr, base); - swap(errno, errno_save); -#ifndef _LIBCPP_NO_EXCEPTIONS - if (errno_save == ERANGE || r < numeric_limits::min() || - numeric_limits::max() < r) - throw out_of_range("stoi: out of range"); - if (ptr == p) - throw invalid_argument("stoi: no conversion"); -#endif // _LIBCPP_NO_EXCEPTIONS - if (idx) - *idx = static_cast(ptr - p); - return static_cast(r); + return as_integer( "stoi", str, idx, base ); } int stoi(const wstring& str, size_t* idx, int base) { - wchar_t* ptr; - const wchar_t* const p = str.c_str(); - typename remove_reference::type errno_save = errno; - errno = 0; - long r = wcstol(p, &ptr, base); - swap(errno, errno_save); -#ifndef _LIBCPP_NO_EXCEPTIONS - if (errno_save == ERANGE || r < numeric_limits::min() || - numeric_limits::max() < r) - throw out_of_range("stoi: out of range"); - if (ptr == p) - throw invalid_argument("stoi: no conversion"); -#endif // _LIBCPP_NO_EXCEPTIONS - if (idx) - *idx = static_cast(ptr - p); - return static_cast(r); + return as_integer( "stoi", str, idx, base ); } long stol(const string& str, size_t* idx, int base) { - char* ptr; - const char* const p = str.c_str(); - typename remove_reference::type errno_save = errno; - errno = 0; - long r = strtol(p, &ptr, base); - swap(errno, errno_save); -#ifndef _LIBCPP_NO_EXCEPTIONS - if (errno_save == ERANGE) - throw out_of_range("stol: out of range"); - if (ptr == p) - throw invalid_argument("stol: no conversion"); -#endif // _LIBCPP_NO_EXCEPTIONS - if (idx) - *idx = static_cast(ptr - p); - return r; + return as_integer( "stol", str, idx, base ); } long stol(const wstring& str, size_t* idx, int base) { - wchar_t* ptr; - const wchar_t* const p = str.c_str(); - typename remove_reference::type errno_save = errno; - errno = 0; - long r = wcstol(p, &ptr, base); - swap(errno, errno_save); -#ifndef _LIBCPP_NO_EXCEPTIONS - if (errno_save == ERANGE) - throw out_of_range("stol: out of range"); - if (ptr == p) - throw invalid_argument("stol: no conversion"); -#endif // _LIBCPP_NO_EXCEPTIONS - if (idx) - *idx = static_cast(ptr - p); - return r; + return as_integer( "stol", str, idx, base ); } unsigned long stoul(const string& str, size_t* idx, int base) { - char* ptr; - const char* const p = str.c_str(); - typename remove_reference::type errno_save = errno; - errno = 0; - unsigned long r = strtoul(p, &ptr, base); - swap(errno, errno_save); -#ifndef _LIBCPP_NO_EXCEPTIONS - if (errno_save == ERANGE) - throw out_of_range("stoul: out of range"); - if (ptr == p) - throw invalid_argument("stoul: no conversion"); -#endif // _LIBCPP_NO_EXCEPTIONS - if (idx) - *idx = static_cast(ptr - p); - return r; + return as_integer( "stoul", str, idx, base ); } unsigned long stoul(const wstring& str, size_t* idx, int base) { - wchar_t* ptr; - const wchar_t* const p = str.c_str(); - typename remove_reference::type errno_save = errno; - errno = 0; - unsigned long r = wcstoul(p, &ptr, base); - swap(errno, errno_save); -#ifndef _LIBCPP_NO_EXCEPTIONS - if (errno_save == ERANGE) - throw out_of_range("stoul: out of range"); - if (ptr == p) - throw invalid_argument("stoul: no conversion"); -#endif // _LIBCPP_NO_EXCEPTIONS - if (idx) - *idx = static_cast(ptr - p); - return r; + return as_integer( "stoul", str, idx, base ); } long long stoll(const string& str, size_t* idx, int base) { - char* ptr; - const char* const p = str.c_str(); - typename remove_reference::type errno_save = errno; - errno = 0; - long long r = strtoll(p, &ptr, base); - swap(errno, errno_save); -#ifndef _LIBCPP_NO_EXCEPTIONS - if (errno_save == ERANGE) - throw out_of_range("stoll: out of range"); - if (ptr == p) - throw invalid_argument("stoll: no conversion"); -#endif // _LIBCPP_NO_EXCEPTIONS - if (idx) - *idx = static_cast(ptr - p); - return r; + return as_integer( "stoll", str, idx, base ); } long long stoll(const wstring& str, size_t* idx, int base) { - wchar_t* ptr; - const wchar_t* const p = str.c_str(); - typename remove_reference::type errno_save = errno; - errno = 0; - long long r = wcstoll(p, &ptr, base); - swap(errno, errno_save); -#ifndef _LIBCPP_NO_EXCEPTIONS - if (errno_save == ERANGE) - throw out_of_range("stoll: out of range"); - if (ptr == p) - throw invalid_argument("stoll: no conversion"); -#endif // _LIBCPP_NO_EXCEPTIONS - if (idx) - *idx = static_cast(ptr - p); - return r; + return as_integer( "stoll", str, idx, base ); } unsigned long long stoull(const string& str, size_t* idx, int base) { - char* ptr; - const char* const p = str.c_str(); - typename remove_reference::type errno_save = errno; - errno = 0; - unsigned long long r = strtoull(p, &ptr, base); - swap(errno, errno_save); -#ifndef _LIBCPP_NO_EXCEPTIONS - if (errno_save == ERANGE) - throw out_of_range("stoull: out of range"); - if (ptr == p) - throw invalid_argument("stoull: no conversion"); -#endif // _LIBCPP_NO_EXCEPTIONS - if (idx) - *idx = static_cast(ptr - p); - return r; + return as_integer( "stoull", str, idx, base ); } unsigned long long stoull(const wstring& str, size_t* idx, int base) { - wchar_t* ptr; - const wchar_t* const p = str.c_str(); - typename remove_reference::type errno_save = errno; - errno = 0; - unsigned long long r = wcstoull(p, &ptr, base); - swap(errno, errno_save); -#ifndef _LIBCPP_NO_EXCEPTIONS - if (errno_save == ERANGE) - throw out_of_range("stoull: out of range"); - if (ptr == p) - throw invalid_argument("stoull: no conversion"); -#endif // _LIBCPP_NO_EXCEPTIONS - if (idx) - *idx = static_cast(ptr - p); - return r; + return as_integer( "stoull", str, idx, base ); } float stof(const string& str, size_t* idx) { - char* ptr; - const char* const p = str.c_str(); - typename remove_reference::type errno_save = errno; - errno = 0; - float r = strtof(p, &ptr); - swap(errno, errno_save); -#ifndef _LIBCPP_NO_EXCEPTIONS - if (errno_save == ERANGE) - throw out_of_range("stof: out of range"); - if (ptr == p) - throw invalid_argument("stof: no conversion"); -#endif // _LIBCPP_NO_EXCEPTIONS - if (idx) - *idx = static_cast(ptr - p); - return r; + return as_float( "stof", str, idx ); } float stof(const wstring& str, size_t* idx) { - wchar_t* ptr; - const wchar_t* const p = str.c_str(); - typename remove_reference::type errno_save = errno; - errno = 0; - float r = wcstof(p, &ptr); - swap(errno, errno_save); -#ifndef _LIBCPP_NO_EXCEPTIONS - if (errno_save == ERANGE) - throw out_of_range("stof: out of range"); - if (ptr == p) - throw invalid_argument("stof: no conversion"); -#endif // _LIBCPP_NO_EXCEPTIONS - if (idx) - *idx = static_cast(ptr - p); - return r; + return as_float( "stof", str, idx ); } double stod(const string& str, size_t* idx) { - char* ptr; - const char* const p = str.c_str(); - typename remove_reference::type errno_save = errno; - errno = 0; - double r = strtod(p, &ptr); - swap(errno, errno_save); -#ifndef _LIBCPP_NO_EXCEPTIONS - if (errno_save == ERANGE) - throw out_of_range("stod: out of range"); - if (ptr == p) - throw invalid_argument("stod: no conversion"); -#endif // _LIBCPP_NO_EXCEPTIONS - if (idx) - *idx = static_cast(ptr - p); - return r; + return as_float( "stod", str, idx ); } double stod(const wstring& str, size_t* idx) { - wchar_t* ptr; - const wchar_t* const p = str.c_str(); - typename remove_reference::type errno_save = errno; - errno = 0; - double r = wcstod(p, &ptr); - swap(errno, errno_save); -#ifndef _LIBCPP_NO_EXCEPTIONS - if (errno_save == ERANGE) - throw out_of_range("stod: out of range"); - if (ptr == p) - throw invalid_argument("stod: no conversion"); -#endif // _LIBCPP_NO_EXCEPTIONS - if (idx) - *idx = static_cast(ptr - p); - return r; + return as_float( "stod", str, idx ); } long double stold(const string& str, size_t* idx) { - char* ptr; - const char* const p = str.c_str(); - typename remove_reference::type errno_save = errno; - errno = 0; - long double r = strtold(p, &ptr); - swap(errno, errno_save); -#ifndef _LIBCPP_NO_EXCEPTIONS - if (errno_save == ERANGE) - throw out_of_range("stold: out of range"); - if (ptr == p) - throw invalid_argument("stold: no conversion"); -#endif // _LIBCPP_NO_EXCEPTIONS - if (idx) - *idx = static_cast(ptr - p); - return r; + return as_float( "stold", str, idx ); } long double stold(const wstring& str, size_t* idx) { - wchar_t* ptr; - const wchar_t* const p = str.c_str(); - typename remove_reference::type errno_save = errno; - errno = 0; - long double r = wcstold(p, &ptr); - swap(errno, errno_save); -#ifndef _LIBCPP_NO_EXCEPTIONS - if (errno_save == ERANGE) - throw out_of_range("stold: out of range"); - if (ptr == p) - throw invalid_argument("stold: no conversion"); -#endif // _LIBCPP_NO_EXCEPTIONS - if (idx) - *idx = static_cast(ptr - p); - return r; + return as_float( "stold", str, idx ); } +// to_string + +namespace +{ + +// as_string + +template +inline +S +as_string(P sprintf_like, S s, const typename S::value_type* fmt, V a) +{ + typedef typename S::size_type size_type; + size_type available = s.size(); + while (true) + { + int status = sprintf_like(&s[0], available + 1, fmt, a); + if ( status >= 0 ) + { + size_type used = static_cast(status); + if ( used <= available ) + { + s.resize( used ); + break; + } + available = used; // Assume this is advice of how much space we need. + } + else + available = available * 2 + 1; + s.resize(available); + } + return s; +} + +template ::value> +struct initial_string; + +template +struct initial_string +{ + string + operator()() const + { + string s; + s.resize(s.capacity()); + return s; + } +}; + +template +struct initial_string +{ + wstring + operator()() const + { + const size_t n = (numeric_limits::digits / 3) + + ((numeric_limits::digits % 3) != 0) + + 1; + wstring s(n, wchar_t()); + s.resize(s.capacity()); + return s; + } +}; + +template +struct initial_string +{ + wstring + operator()() const + { + wstring s(20, wchar_t()); + s.resize(s.capacity()); + return s; + } +}; + +typedef int (*wide_printf)(wchar_t* __restrict, size_t, const wchar_t*__restrict, ...); + +inline +wide_printf +get_swprintf() +{ +#ifndef _WIN32 + return swprintf; +#else + return static_cast(swprintf); +#endif +} + +} // unnamed namespace + string to_string(int val) { - string s; - s.resize(s.capacity()); - while (true) - { - size_t n2 = static_cast(snprintf(&s[0], s.size()+1, "%d", val)); - if (n2 <= s.size()) - { - s.resize(n2); - break; - } - s.resize(n2); - } - return s; + return as_string(snprintf, initial_string()(), "%d", val); } string to_string(unsigned val) { - string s; - s.resize(s.capacity()); - while (true) - { - size_t n2 = static_cast(snprintf(&s[0], s.size()+1, "%u", val)); - if (n2 <= s.size()) - { - s.resize(n2); - break; - } - s.resize(n2); - } - return s; + return as_string(snprintf, initial_string()(), "%u", val); } string to_string(long val) { - string s; - s.resize(s.capacity()); - while (true) - { - size_t n2 = static_cast(snprintf(&s[0], s.size()+1, "%ld", val)); - if (n2 <= s.size()) - { - s.resize(n2); - break; - } - s.resize(n2); - } - return s; + return as_string(snprintf, initial_string()(), "%ld", val); } string to_string(unsigned long val) { - string s; - s.resize(s.capacity()); - while (true) - { - size_t n2 = static_cast(snprintf(&s[0], s.size()+1, "%lu", val)); - if (n2 <= s.size()) - { - s.resize(n2); - break; - } - s.resize(n2); - } - return s; + return as_string(snprintf, initial_string()(), "%lu", val); } string to_string(long long val) { - string s; - s.resize(s.capacity()); - while (true) - { - size_t n2 = static_cast(snprintf(&s[0], s.size()+1, "%lld", val)); - if (n2 <= s.size()) - { - s.resize(n2); - break; - } - s.resize(n2); - } - return s; + return as_string(snprintf, initial_string()(), "%lld", val); } string to_string(unsigned long long val) { - string s; - s.resize(s.capacity()); - while (true) - { - size_t n2 = static_cast(snprintf(&s[0], s.size()+1, "%llu", val)); - if (n2 <= s.size()) - { - s.resize(n2); - break; - } - s.resize(n2); - } - return s; + return as_string(snprintf, initial_string()(), "%llu", val); } string to_string(float val) { - string s; - s.resize(s.capacity()); - while (true) - { - size_t n2 = static_cast(snprintf(&s[0], s.size()+1, "%f", val)); - if (n2 <= s.size()) - { - s.resize(n2); - break; - } - s.resize(n2); - } - return s; + return as_string(snprintf, initial_string()(), "%f", val); } string to_string(double val) { - string s; - s.resize(s.capacity()); - while (true) - { - size_t n2 = static_cast(snprintf(&s[0], s.size()+1, "%f", val)); - if (n2 <= s.size()) - { - s.resize(n2); - break; - } - s.resize(n2); - } - return s; + return as_string(snprintf, initial_string()(), "%f", val); } string to_string(long double val) { - string s; - s.resize(s.capacity()); - while (true) - { - size_t n2 = static_cast(snprintf(&s[0], s.size()+1, "%Lf", val)); - if (n2 <= s.size()) - { - s.resize(n2); - break; - } - s.resize(n2); - } - return s; + return as_string(snprintf, initial_string()(), "%Lf", val); } wstring to_wstring(int val) { - const size_t n = (numeric_limits::digits / 3) - + ((numeric_limits::digits % 3) != 0) - + 1; - wstring s(n, wchar_t()); - s.resize(s.capacity()); - while (true) - { - int n2 = swprintf(&s[0], s.size()+1, L"%d", val); - if (n2 > 0) - { - s.resize(static_cast(n2)); - break; - } - s.resize(2*s.size()); - s.resize(s.capacity()); - } - return s; + return as_string(get_swprintf(), initial_string()(), L"%d", val); } wstring to_wstring(unsigned val) { - const size_t n = (numeric_limits::digits / 3) - + ((numeric_limits::digits % 3) != 0) - + 1; - wstring s(n, wchar_t()); - s.resize(s.capacity()); - while (true) - { - int n2 = swprintf(&s[0], s.size()+1, L"%u", val); - if (n2 > 0) - { - s.resize(static_cast(n2)); - break; - } - s.resize(2*s.size()); - s.resize(s.capacity()); - } - return s; + return as_string(get_swprintf(), initial_string()(), L"%u", val); } wstring to_wstring(long val) { - const size_t n = (numeric_limits::digits / 3) - + ((numeric_limits::digits % 3) != 0) - + 1; - wstring s(n, wchar_t()); - s.resize(s.capacity()); - while (true) - { - int n2 = swprintf(&s[0], s.size()+1, L"%ld", val); - if (n2 > 0) - { - s.resize(static_cast(n2)); - break; - } - s.resize(2*s.size()); - s.resize(s.capacity()); - } - return s; + return as_string(get_swprintf(), initial_string()(), L"%ld", val); } wstring to_wstring(unsigned long val) { - const size_t n = (numeric_limits::digits / 3) - + ((numeric_limits::digits % 3) != 0) - + 1; - wstring s(n, wchar_t()); - s.resize(s.capacity()); - while (true) - { - int n2 = swprintf(&s[0], s.size()+1, L"%lu", val); - if (n2 > 0) - { - s.resize(static_cast(n2)); - break; - } - s.resize(2*s.size()); - s.resize(s.capacity()); - } - return s; + return as_string(get_swprintf(), initial_string()(), L"%lu", val); } wstring to_wstring(long long val) { - const size_t n = (numeric_limits::digits / 3) - + ((numeric_limits::digits % 3) != 0) - + 1; - wstring s(n, wchar_t()); - s.resize(s.capacity()); - while (true) - { - int n2 = swprintf(&s[0], s.size()+1, L"%lld", val); - if (n2 > 0) - { - s.resize(static_cast(n2)); - break; - } - s.resize(2*s.size()); - s.resize(s.capacity()); - } - return s; + return as_string(get_swprintf(), initial_string()(), L"%lld", val); } wstring to_wstring(unsigned long long val) { - const size_t n = (numeric_limits::digits / 3) - + ((numeric_limits::digits % 3) != 0) - + 1; - wstring s(n, wchar_t()); - s.resize(s.capacity()); - while (true) - { - int n2 = swprintf(&s[0], s.size()+1, L"%llu", val); - if (n2 > 0) - { - s.resize(static_cast(n2)); - break; - } - s.resize(2*s.size()); - s.resize(s.capacity()); - } - return s; + return as_string(get_swprintf(), initial_string()(), L"%llu", val); } wstring to_wstring(float val) { - const size_t n = 20; - wstring s(n, wchar_t()); - s.resize(s.capacity()); - while (true) - { - int n2 = swprintf(&s[0], s.size()+1, L"%f", val); - if (n2 > 0) - { - s.resize(static_cast(n2)); - break; - } - s.resize(2*s.size()); - s.resize(s.capacity()); - } - return s; + return as_string(get_swprintf(), initial_string()(), L"%f", val); } wstring to_wstring(double val) { - const size_t n = 20; - wstring s(n, wchar_t()); - s.resize(s.capacity()); - while (true) - { - int n2 = swprintf(&s[0], s.size()+1, L"%f", val); - if (n2 > 0) - { - s.resize(static_cast(n2)); - break; - } - s.resize(2*s.size()); - s.resize(s.capacity()); - } - return s; + return as_string(get_swprintf(), initial_string()(), L"%f", val); } wstring to_wstring(long double val) { - const size_t n = 20; - wstring s(n, wchar_t()); - s.resize(s.capacity()); - while (true) - { - int n2 = swprintf(&s[0], s.size()+1, L"%Lf", val); - if (n2 > 0) - { - s.resize(static_cast(n2)); - break; - } - s.resize(2*s.size()); - s.resize(s.capacity()); - } - return s; + return as_string(get_swprintf(), initial_string()(), L"%Lf", val); } - _LIBCPP_END_NAMESPACE_STD diff --git a/src/support/win32/locale_win32.cpp b/src/support/win32/locale_win32.cpp index e8c630c1..a639ade4 100644 --- a/src/support/win32/locale_win32.cpp +++ b/src/support/win32/locale_win32.cpp @@ -9,8 +9,8 @@ //===----------------------------------------------------------------------===// #include "support/win32/locale_win32.h" - -#include // va_start, va_end +#include // va_start, va_end +#include // mbstate_t // FIXME: base currently unused. Needs manual work to construct the new locale locale_t newlocale( int mask, const char * locale, locale_t /*base*/ ) diff --git a/src/support/win32/support.cpp b/src/support/win32/support.cpp index 75f63919..1a8bcf62 100644 --- a/src/support/win32/support.cpp +++ b/src/support/win32/support.cpp @@ -8,38 +8,55 @@ // //===----------------------------------------------------------------------===// -#include -#include // va_start, va_end -#include // size_t -#include // malloc -#include // vsprintf, vsnprintf -#include // strcpy, wcsncpy +#include // va_start, va_end +#include // size_t +#include // malloc +#include // vsprintf, vsnprintf +#include // strcpy, wcsncpy +#include // mbstate_t +#include // unique_ptr -int asprintf(char **sptr, const char *__restrict fmt, ...) +namespace { // Private + + struct free_deleter { + inline void operator()(char* p) { free(p); } + }; +} +// Some of these functions aren't standard or if they conform, the name does not. + +int asprintf(char **sptr, const char *__restrict format, ...) { va_list ap; - va_start(ap, fmt); - int result = vasprintf(sptr, fmt, ap); + va_start(ap, format); + int result; +#ifndef _LIBCPP_NO_EXCEPTIONS + try { +#endif + result = vasprintf(sptr, format, ap); +#ifndef _LIBCPP_NO_EXCEPTIONS + } catch( ... ) { + va_end(ap); + throw; + } +#endif va_end(ap); return result; } // Like sprintf, but when return value >= 0 it returns a pointer to a malloc'd string in *sptr. // If return >= 0, use free to delete *sptr. -int vasprintf( char **sptr, const char *__restrict fmt, va_list ap ) +int vasprintf( char **sptr, const char *__restrict format, va_list ap ) { *sptr = NULL; - int count = vsnprintf( NULL, 0, fmt, ap ); // Query the buffer size required. + int count = _vsnprintf( NULL, 0, format, ap ); // Query the buffer size required. if( count >= 0 ) { - char* p = static_cast(malloc(count+1)); // Allocate memory for it and the terminator. - if ( p == NULL ) + std::unique_ptr p( static_cast(malloc(count+1)) ); + if ( ! p ) return -1; - if ( vsnprintf( p, count+1, fmt, ap ) == count ) // We should have used exactly what was required. - *sptr = p; - else { // Otherwise something is wrong, likely a bug in vsnprintf. If so free the memory and report the error. - free(p); - return -1; - } + if ( vsnprintf( p.get(), count+1, format, ap ) == count ) // We should have used exactly what was required. + *sptr = p.release(); + else // Otherwise something is wrong, likely a bug in vsnprintf. If so free the memory and report the error. + return -1; // Pointer will get automaticlaly deleted. } return count; @@ -120,7 +137,7 @@ size_t wcsnrtombs( char *__restrict dst, const wchar_t **__restrict src, if ( dst ) result = wcrtomb_s( &char_size, dst + dest_converted, dest_remaining, c, ps); else - result = wcrtomb_s( &char_size, NULL, 0, c, ps); + result = wcrtomb_s( &char_size, NULL, 0, c, ps); // If result is zero there is no error and char_size contains the size of the multi-byte-sequence converted. // Otherwise result indicates an errno type error. if ( result == no_error ) {