summaryrefslogtreecommitdiff
path: root/src/mongo/bson
diff options
context:
space:
mode:
authorMathias Stearn <mathias@10gen.com>2017-03-06 14:30:21 -0500
committerMathias Stearn <mathias@10gen.com>2017-06-13 17:15:28 -0400
commitc11900912d97df148a6970a3ec1e27d093923a0a (patch)
tree2dbfc3a1116e1b37cf793252ed3a6af0f1623cfc /src/mongo/bson
parent93d9e27c64b95d4ff601baaf84a3b10a565be778 (diff)
downloadmongo-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.h31
-rw-r--r--src/mongo/bson/util/builder_test.cpp41
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>();
+}
}