summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authordeanm@google.com <deanm@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-08-13 11:09:33 +0000
committerdeanm@google.com <deanm@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-08-13 11:09:33 +0000
commit21d610fb26b275f489dacbd6c372ddf55323ea55 (patch)
tree473fb04cecdcefdfae175768d6e921210054275b /base
parentacd50f6a9719bd5dae5710ac24243c2898f5f853 (diff)
downloadchromium_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.cc101
-rw-r--r--base/string_util.h7
-rw-r--r--base/string_util_unittest.cc53
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) {