diff --git a/base/base_tests/string_utils_test.cpp b/base/base_tests/string_utils_test.cpp index b42d9bf70d..be6d3cbfef 100644 --- a/base/base_tests/string_utils_test.cpp +++ b/base/base_tests/string_utils_test.cpp @@ -218,10 +218,23 @@ UNIT_TEST(to_int64) UNIT_TEST(to_string) { + TEST_EQUAL(strings::to_string(0), "0", ()); + TEST_EQUAL(strings::to_string(-0), "0", ()); + TEST_EQUAL(strings::to_string(1), "1", ()); TEST_EQUAL(strings::to_string(-1), "-1", ()); TEST_EQUAL(strings::to_string(1234567890), "1234567890", ()); + TEST_EQUAL(strings::to_string(-987654321), "-987654321", ()); TEST_EQUAL(strings::to_string(0.56), "0.56", ()); TEST_EQUAL(strings::to_string(-100.2), "-100.2", ()); + + // 6 digits after the comma with rounding - it's a default behavior + TEST_EQUAL(strings::to_string(-0.66666666), "-0.666667", ()); + + TEST_EQUAL(strings::to_string(-1.0E2), "-100", ()); + TEST_EQUAL(strings::to_string(1.0E-2), "0.01", ()); + + TEST_EQUAL(strings::to_string(123456789123456789ULL), "123456789123456789", ()); + TEST_EQUAL(strings::to_string(-987654321987654321LL), "-987654321987654321", ()); } struct FunctorTester diff --git a/base/string_utils.hpp b/base/string_utils.hpp index 474b186cb9..98dd14544e 100644 --- a/base/string_utils.hpp +++ b/base/string_utils.hpp @@ -5,6 +5,7 @@ #include "../std/string.hpp" #include "../std/stdint.hpp" #include "../std/sstream.hpp" +#include "../std/limits.hpp" #include "../3party/utfcpp/source/utf8/unchecked.h" @@ -154,23 +155,88 @@ template bool IsInArray(T (&arr) [N], TT const & t return false; } +/// @name From string to numeric. +//@{ bool to_int(char const * s, int & i); bool to_uint64(char const * s, uint64_t & i); bool to_int64(char const * s, int64_t & i); bool to_double(char const * s, double & d); -template -string to_string(T i) -{ - ostringstream ss; - ss << i; - return ss.str(); -} - inline bool to_int(string const & s, int & i) { return to_int(s.c_str(), i); } inline bool to_uint64(string const & s, uint64_t & i) { return to_uint64(s.c_str(), i); } inline bool to_int64(string const & s, int64_t & i) { return to_int64(s.c_str(), i); } inline bool to_double(string const & s, double & d) { return to_double(s.c_str(), d); } +//@} + +/// @name From numeric to string. +//@{ +inline string to_string(string const & s) +{ + return s; +} + +inline string to_string(char const * s) +{ + return s; +} + +template string to_string(T t) +{ + ostringstream ss; + ss << t; + return ss.str(); +} + +namespace impl +{ + +template char * to_string_digits(char * buf, T i) +{ + do + { + --buf; + *buf = static_cast(i % 10) + '0'; + i = i / 10; + } while (i != 0); + return buf; +} + +template string to_string_signed(T i) +{ + bool const negative = i < 0; + int const sz = numeric_limits::digits10 + 1; + char buf[sz]; + char * end = buf + sz; + char * beg = to_string_digits(end, negative ? -i : i); + if (negative) + { + --beg; + *beg = '-'; + } + return string(beg, end - beg); +} + +template string to_string_unsigned(T i) +{ + int const sz = numeric_limits::digits10; + char buf[sz]; + char * end = buf + sz; + char * beg = to_string_digits(end, i); + return string(beg, end - beg); +} + +} + +inline string to_string(int64_t i) +{ + return impl::to_string_signed(i); +} + +inline string to_string(uint64_t i) +{ + return impl::to_string_unsigned(i); +} +//@} /* template