Index: libcxx/src/string.cpp =================================================================== --- libcxx/src/string.cpp +++ libcxx/src/string.cpp @@ -348,15 +348,83 @@ // as_string -template +template +struct string_traits; + +template<> +struct string_traits +{ + static char zero() { return '0'; } + static char minus() { return '-'; } +}; + +template<> +struct string_traits +{ + static wchar_t zero() { return L'0'; } + static wchar_t minus() { return L'-'; } +}; + +// returns index of the last written digit +template +inline +int +write_positive_in_buffer_tail(V a, typename S::value_type* buf, const int size) +{ + const auto zero = string_traits::zero(); + int start = size; + do + { + buf[--start] = zero + static_cast(a % 10); + a /= 10; + } + while(a); + return start; +} + +template +inline +S +signed_to_string(V a) +{ + constexpr int size = 4 * sizeof(V); + typename S::value_type buf[size] = {}; + + int start = size; + + if (a < 0) + { + // std::numeric_limits::min() can not be converted to unsigned value + // of the same type, split off the last char for negative values. + // + // (a % 10) <= 0 according to "Multiplicative operators" paragraph of + // C++ standard with reference to "truncation towards zero" + const auto zero = string_traits::zero(); + buf[--start] = zero + static_cast(-(a % 10)); + a /= 10; + + if (a != 0) + start = write_positive_in_buffer_tail(-a, buf, start); + + buf[--start] = string_traits::minus(); + } + else + { + start = write_positive_in_buffer_tail(a, buf, start); + } + + return S(buf + start, buf + size); +} + +template inline S -i_to_string(P sprintf_like, const typename S::value_type* fmt, V a) +unsigned_to_string(const V a) { - constexpr size_t size = 4 * sizeof(V) + 1; // +1 for null char from swprintf + constexpr int size = 4 * sizeof(V); typename S::value_type buf[size] = {}; - const int len = sprintf_like(buf, size, fmt, a); - return S(buf, buf + len); + int start = write_positive_in_buffer_tail(a, buf, size); + return S(buf + start, buf + size); } template @@ -419,32 +487,32 @@ string to_string(int val) { - return i_to_string(snprintf, "%d", val); + return signed_to_string(val); } string to_string(unsigned val) { - return i_to_string(snprintf, "%u", val); + return unsigned_to_string(val); } string to_string(long val) { - return i_to_string(snprintf, "%ld", val); + return signed_to_string(val); } string to_string(unsigned long val) { - return i_to_string(snprintf, "%lu", val); + return unsigned_to_string(val); } string to_string(long long val) { - return i_to_string(snprintf, "%lld", val); + return signed_to_string(val); } string to_string(unsigned long long val) { - return i_to_string(snprintf, "%llu", val); + return unsigned_to_string(val); } string to_string(float val) @@ -464,32 +532,32 @@ wstring to_wstring(int val) { - return i_to_string(get_swprintf(), L"%d", val); + return signed_to_string(val); } wstring to_wstring(unsigned val) { - return i_to_string(get_swprintf(), L"%u", val); + return unsigned_to_string(val); } wstring to_wstring(long val) { - return i_to_string(get_swprintf(), L"%ld", val); + return signed_to_string(val); } wstring to_wstring(unsigned long val) { - return i_to_string(get_swprintf(), L"%lu", val); + return unsigned_to_string(val); } wstring to_wstring(long long val) { - return i_to_string(get_swprintf(), L"%lld", val); + return signed_to_string(val); } wstring to_wstring(unsigned long long val) { - return i_to_string(get_swprintf(), L"%llu", val); + return unsigned_to_string(val); } wstring to_wstring(float val) Index: libcxx/test/std/strings/string.conversions/to_string.pass.cpp =================================================================== --- libcxx/test/std/strings/string.conversions/to_string.pass.cpp +++ libcxx/test/std/strings/string.conversions/to_string.pass.cpp @@ -45,6 +45,12 @@ assert(s[s.size()] == 0); assert(s == "-12345"); } + { + std::string s = std::to_string(T(-2)); + assert(s.size() == 2); + assert(s[s.size()] == 0); + assert(s == "-2"); + } { std::string s = std::to_string(std::numeric_limits::max()); assert(s.size() == std::numeric_limits::digits10 + 1); Index: libcxx/test/std/strings/string.conversions/to_wstring.pass.cpp =================================================================== --- libcxx/test/std/strings/string.conversions/to_wstring.pass.cpp +++ libcxx/test/std/strings/string.conversions/to_wstring.pass.cpp @@ -45,6 +45,12 @@ assert(s[s.size()] == 0); assert(s == L"-12345"); } + { + std::wstring s = std::to_wstring(T(-2)); + assert(s.size() == 2); + assert(s[s.size()] == 0); + assert(s == L"-2"); + } { std::wstring s = std::to_wstring(std::numeric_limits::max()); assert(s.size() == std::numeric_limits::digits10 + 1);