diff options
author | deanm@google.com <deanm@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-08-13 11:09:33 +0000 |
---|---|---|
committer | deanm@google.com <deanm@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-08-13 11:09:33 +0000 |
commit | 21d610fb26b275f489dacbd6c372ddf55323ea55 (patch) | |
tree | 473fb04cecdcefdfae175768d6e921210054275b /base | |
parent | acd50f6a9719bd5dae5710ac24243c2898f5f853 (diff) | |
download | chromium_src-21d610fb26b275f489dacbd6c372ddf55323ea55.zip chromium_src-21d610fb26b275f489dacbd6c372ddf55323ea55.tar.gz chromium_src-21d610fb26b275f489dacbd6c372ddf55323ea55.tar.bz2 |
Implement IntToString-type methods without using a format string. I'm not sure if this will actually be more efficient. Also will make Int64ToString work on other platforms, since the old code used msvc-only %I64. Added a bunch of methods to have the whole Int/Int64 String/WString suite.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@784 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r-- | base/string_util.cc | 101 | ||||
-rw-r--r-- | base/string_util.h | 7 | ||||
-rw-r--r-- | base/string_util_unittest.cc | 53 |
3 files changed, 137 insertions, 24 deletions
diff --git a/base/string_util.cc b/base/string_util.cc index bd02f3d..864612ae 100644 --- a/base/string_util.cc +++ b/base/string_util.cc @@ -852,24 +852,103 @@ static void StringAppendVT( } } -std::string Uint64ToString(uint64 value) { - return StringPrintf("%llu", value); -} +namespace { -std::string Int64ToString(int64 value) { - return StringPrintf("%I64d", value); -} +template <typename STR, typename INT, typename UINT, bool NEG> +struct IntToStringT { + + // This is to avoid a compiler warning about unary minus on unsigned type. + // For example, say you had the following code: + // template <typename INT> + // INT abs(INT value) { return value < 0 ? -value : value; } + // Even though if INT is unsigned, it's impossible for value < 0, so the + // unary minus will never be taken, the compiler will still generate a + // warning. We do a little specialization dance... + template <typename INT2, typename UINT2, bool NEG2> + struct ToUnsignedT { }; + + template <typename INT2, typename UINT2> + struct ToUnsignedT<INT2, UINT2, false> { + static UINT2 ToUnsigned(INT2 value) { + return static_cast<UINT2>(value); + } + }; + + template <typename INT2, typename UINT2> + struct ToUnsignedT<INT2, UINT2, true> { + static UINT2 ToUnsigned(INT2 value) { + return static_cast<UINT2>(value < 0 ? -value : value); + } + }; + + static STR IntToString(INT value) { + // log10(2) ~= 0.3 bytes needed per bit or per byte log10(2**8) ~= 2.4. + // So round up to allocate 3 output characters per byte, plus 1 for '-'. + const int kOutputBufSize = 3 * sizeof(INT) + 1; + + // Allocate the whole string right away, we will right back to front, and + // then return the substr of what we ended up using. + STR outbuf(kOutputBufSize, 0); + + bool is_neg = value < 0; + // Even though is_neg will never be true when INT is parameterized as + // unsigned, even the presence of the unary operation causes a warning. + UINT res = ToUnsignedT<INT, UINT, NEG>::ToUnsigned(value); + + for (typename STR::iterator it = outbuf.end();;) { + --it; + DCHECK(it != outbuf.begin()); + *it = static_cast<typename STR::value_type>((res % 10) + '0'); + res /= 10; + + // We're done.. + if (res == 0) { + if (is_neg) { + --it; + DCHECK(it != outbuf.begin()); + *it = static_cast<typename STR::value_type>('-'); + } + return STR(it, outbuf.end()); + } + } + NOTREACHED(); + return STR(); + } +}; -std::wstring Int64ToWString(int64 value) { - return StringPrintf(L"%I64d", value); } std::string IntToString(int value) { - return StringPrintf("%d", value); + return IntToStringT<std::string, int, unsigned int, true>:: + IntToString(value); } - std::wstring IntToWString(int value) { - return StringPrintf(L"%d", value); + return IntToStringT<std::wstring, int, unsigned int, true>:: + IntToString(value); +} +std::string UintToString(unsigned int value) { + return IntToStringT<std::string, unsigned int, unsigned int, false>:: + IntToString(value); +} +std::wstring UintToWString(unsigned int value) { + return IntToStringT<std::wstring, unsigned int, unsigned int, false>:: + IntToString(value); +} +std::string Int64ToString(int64 value) { + return IntToStringT<std::string, int64, uint64, true>:: + IntToString(value); +} +std::wstring Int64ToWString(int64 value) { + return IntToStringT<std::wstring, int64, uint64, true>:: + IntToString(value); +} +std::string Uint64ToString(uint64 value) { + return IntToStringT<std::string, uint64, uint64, false>:: + IntToString(value); +} +std::wstring Uint64ToWString(uint64 value) { + return IntToStringT<std::wstring, uint64, uint64, false>:: + IntToString(value); } inline void StringAppendV(std::string* dst, const char* format, va_list ap) { diff --git a/base/string_util.h b/base/string_util.h index 2f0f3d6..17c1793 100644 --- a/base/string_util.h +++ b/base/string_util.h @@ -326,11 +326,14 @@ void ReplaceSubstringsAfterOffset(std::string* str, const std::string& replace_with); // Specialized string-conversion functions. -std::string Uint64ToString(uint64 value); std::string IntToString(int value); +std::wstring IntToWString(int value); +std::string UintToString(unsigned int value); +std::wstring UintToWString(unsigned int value); std::string Int64ToString(int64 value); std::wstring Int64ToWString(int64 value); -std::wstring IntToWString(int value); +std::string Uint64ToString(uint64 value); +std::wstring Uint64ToWString(uint64 value); // Perform a best-effort conversion of the input string to a numeric type, // setting |*output| to the result of the conversion. Returns true for diff --git a/base/string_util_unittest.cc b/base/string_util_unittest.cc index d13107f..fb3681b5 100644 --- a/base/string_util_unittest.cc +++ b/base/string_util_unittest.cc @@ -30,6 +30,7 @@ #include <math.h> #include <stdarg.h> +#include <limits> #include <sstream> #include "base/basictypes.h" @@ -634,20 +635,50 @@ TEST(StringUtilTest, ReplaceSubstringsAfterOffset) { } } +namespace { + +template <typename INT> +struct IntToStringTest { + INT num; + const char* sexpected; + const char* uexpected; +}; + +} + TEST(StringUtilTest, IntToString) { - static const struct { - int input; - std::string output; - } cases[] = { - {0, "0"}, - {42, "42"}, - {-42, "-42"}, - {INT_MAX, "2147483647"}, - {INT_MIN, "-2147483648"}, + + static const IntToStringTest<int> int_tests[] = { + { 0, "0", "0" }, + { -1, "-1", "4294967295" }, + { std::numeric_limits<int>::max(), "2147483647", "2147483647" }, + { std::numeric_limits<int>::min(), "-2147483648", "2147483648" }, + }; + static const IntToStringTest<int64> int64_tests[] = { + { 0, "0", "0" }, + { -1, "-1", "18446744073709551615" }, + { std::numeric_limits<int64>::max(), + "9223372036854775807", + "9223372036854775807", }, + { std::numeric_limits<int64>::min(), + "-9223372036854775808", + "9223372036854775808" }, }; - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) - EXPECT_EQ(cases[i].output, IntToString(cases[i].input)); + for (int i = 0; i < arraysize(int_tests); ++i) { + const IntToStringTest<int>* test = &int_tests[i]; + EXPECT_EQ(IntToString(test->num), test->sexpected); + EXPECT_EQ(IntToWString(test->num), UTF8ToWide(test->sexpected)); + EXPECT_EQ(UintToString(test->num), test->uexpected); + EXPECT_EQ(UintToWString(test->num), UTF8ToWide(test->uexpected)); + } + for (int i = 0; i < arraysize(int64_tests); ++i) { + const IntToStringTest<int64>* test = &int64_tests[i]; + EXPECT_EQ(Int64ToString(test->num), test->sexpected); + EXPECT_EQ(Int64ToWString(test->num), UTF8ToWide(test->sexpected)); + EXPECT_EQ(Uint64ToString(test->num), test->uexpected); + EXPECT_EQ(Uint64ToWString(test->num), UTF8ToWide(test->uexpected)); + } } TEST(StringUtilTest, Uint64ToString) { |