diff options
author | Mathias Stearn <mathias@10gen.com> | 2017-03-06 14:30:21 -0500 |
---|---|---|
committer | Mathias Stearn <mathias@10gen.com> | 2017-06-13 17:15:28 -0400 |
commit | c11900912d97df148a6970a3ec1e27d093923a0a (patch) | |
tree | 2dbfc3a1116e1b37cf793252ed3a6af0f1623cfc /src/mongo/bson | |
parent | 93d9e27c64b95d4ff601baaf84a3b10a565be778 (diff) | |
download | mongo-c11900912d97df148a6970a3ec1e27d093923a0a.tar.gz |
SERVER-27193 Use ItoA to handle integer cases in StringBuilder
Diffstat (limited to 'src/mongo/bson')
-rw-r--r-- | src/mongo/bson/util/builder.h | 31 | ||||
-rw-r--r-- | src/mongo/bson/util/builder_test.cpp | 41 |
2 files changed, 65 insertions, 7 deletions
diff --git a/src/mongo/bson/util/builder.h b/src/mongo/bson/util/builder.h index 3a0c02d3258..e40238ca28f 100644 --- a/src/mongo/bson/util/builder.h +++ b/src/mongo/bson/util/builder.h @@ -30,6 +30,7 @@ #pragma once #include <cfloat> +#include <cinttypes> #include <cstdint> #include <sstream> #include <stdio.h> @@ -48,6 +49,7 @@ #include "mongo/stdx/type_traits.h" #include "mongo/util/allocator.h" #include "mongo/util/assert_util.h" +#include "mongo/util/itoa.h" #include "mongo/util/shared_buffer.h" namespace mongo { @@ -380,25 +382,25 @@ public: return SBNUM(x, MONGO_DBL_SIZE, "%g"); } StringBuilderImpl& operator<<(int x) { - return SBNUM(x, MONGO_S32_SIZE, "%d"); + return appendIntegral(x, MONGO_S32_SIZE); } StringBuilderImpl& operator<<(unsigned x) { - return SBNUM(x, MONGO_U32_SIZE, "%u"); + return appendIntegral(x, MONGO_U32_SIZE); } StringBuilderImpl& operator<<(long x) { - return SBNUM(x, MONGO_S64_SIZE, "%ld"); + return appendIntegral(x, MONGO_S64_SIZE); } StringBuilderImpl& operator<<(unsigned long x) { - return SBNUM(x, MONGO_U64_SIZE, "%lu"); + return appendIntegral(x, MONGO_U64_SIZE); } StringBuilderImpl& operator<<(long long x) { - return SBNUM(x, MONGO_S64_SIZE, "%lld"); + return appendIntegral(x, MONGO_S64_SIZE); } StringBuilderImpl& operator<<(unsigned long long x) { - return SBNUM(x, MONGO_U64_SIZE, "%llu"); + return appendIntegral(x, MONGO_U64_SIZE); } StringBuilderImpl& operator<<(short x) { - return SBNUM(x, MONGO_S16_SIZE, "%hd"); + return appendIntegral(x, MONGO_S16_SIZE); } StringBuilderImpl& operator<<(const void* x) { if (sizeof(x) == 8) { @@ -472,6 +474,21 @@ public: private: _BufBuilder<Allocator> _buf; + template <typename T> + StringBuilderImpl& appendIntegral(T val, int maxSize) { + MONGO_STATIC_ASSERT(!std::is_same<T, char>()); // char shouldn't append as number. + MONGO_STATIC_ASSERT(std::is_integral<T>()); + MONGO_STATIC_ASSERT(std::numeric_limits<T>::max() <= std::numeric_limits<uint64_t>::max()); + + if (val < 0) { + *this << '-'; + append(StringData(ItoA(-uint64_t(val)))); // Send the magnitude to ItoA. + } else { + append(StringData(ItoA(uint64_t(val)))); + } + + return *this; + } template <typename T> StringBuilderImpl& SBNUM(T val, int maxSize, const char* macro) { diff --git a/src/mongo/bson/util/builder_test.cpp b/src/mongo/bson/util/builder_test.cpp index f56ba5999c8..b45a0dcf5aa 100644 --- a/src/mongo/bson/util/builder_test.cpp +++ b/src/mongo/bson/util/builder_test.cpp @@ -82,4 +82,45 @@ TEST(Builder, StackAllocatorShouldNotLeak) { stackAlloc.malloc(StackAllocator::SZ + 1); // Force heap allocation. // Let the builder go out of scope. If this leaks, it will trip the ASAN leak detector. } + +template <typename T> +void testStringBuilderIntegral() { + auto check = [](T num) { ASSERT_EQ(std::string(str::stream() << num), std::to_string(num)); }; + + // Do some simple sanity checks. + check(0); + check(1); + check(-1); + check(std::numeric_limits<T>::min()); + check(std::numeric_limits<T>::max()); + + // Check the full range of int16_t. Using int32_t as loop variable to detect when we are done. + for (int32_t num = std::numeric_limits<int16_t>::min(); + num <= std::numeric_limits<int16_t>::max(); + num++) { + check(num); + } +} + +TEST(Builder, AppendInt) { + testStringBuilderIntegral<int>(); +} +TEST(Builder, AppendUnsigned) { + testStringBuilderIntegral<unsigned>(); +} +TEST(Builder, AppendLong) { + testStringBuilderIntegral<long>(); +} +TEST(Builder, AppendUnsignedLong) { + testStringBuilderIntegral<unsigned long>(); +} +TEST(Builder, AppendLongLong) { + testStringBuilderIntegral<long long>(); +} +TEST(Builder, AppendUnsignedLongLong) { + testStringBuilderIntegral<unsigned long long>(); +} +TEST(Builder, AppendShort) { + testStringBuilderIntegral<short>(); +} } |