summaryrefslogtreecommitdiff
path: root/src/mongo/platform
diff options
context:
space:
mode:
authorBilly Donahue <billy.donahue@mongodb.com>2019-09-04 03:09:54 +0000
committerevergreen <evergreen@mongodb.com>2019-09-04 03:09:54 +0000
commit947f837d67b4112dc3b4377bd01948a8e2f551b4 (patch)
tree86f6f7906a8523ff6c3254a1f8275b7109450131 /src/mongo/platform
parent6225782d0e720a0bde22a572a99cfcae1ada2ccf (diff)
downloadmongo-947f837d67b4112dc3b4377bd01948a8e2f551b4.tar.gz
SERVER-43032 Revise platform/overflow_arithmetic_test.cpp
Diffstat (limited to 'src/mongo/platform')
-rw-r--r--src/mongo/platform/overflow_arithmetic_test.cpp251
1 files changed, 128 insertions, 123 deletions
diff --git a/src/mongo/platform/overflow_arithmetic_test.cpp b/src/mongo/platform/overflow_arithmetic_test.cpp
index 95910832c86..e9fa705ed6d 100644
--- a/src/mongo/platform/overflow_arithmetic_test.cpp
+++ b/src/mongo/platform/overflow_arithmetic_test.cpp
@@ -32,152 +32,157 @@
#include <limits>
#include "mongo/platform/overflow_arithmetic.h"
+#include "mongo/stdx/type_traits.h"
#include "mongo/unittest/unittest.h"
namespace mongo {
namespace {
+template <typename T>
+constexpr T kMin = std::numeric_limits<T>::min();
+template <typename T>
+constexpr T kMax = std::numeric_limits<T>::max();
+
+template <typename T, typename F, typename A, typename B>
+bool runTest(bool oflow, F f, A a, B b, T r = {}) {
+ T result;
+ bool oflowed = f(a, b, &result);
+ if (oflowed != oflow)
+ return false;
+ if (oflow)
+ return true;
+ return result == r;
+}
+
+// Expect `f(a,b) == r`.
+template <typename T, typename F, typename A, typename B>
+auto test(F f, A a, B b, stdx::type_identity_t<T> r) {
+ return runTest<T>(false, f, a, b, r);
+};
+
+// Expect `f(a,b)` overflows.
+template <typename T, typename F, typename A, typename B>
+auto testOflow(F f, A a, B b) {
+ return runTest<T>(true, f, a, b);
+};
-#define assertArithOverflow(TYPE, FN, LHS, RHS, EXPECT_OVERFLOW, EXPECTED_RESULT) \
- do { \
- const bool expectOverflow = EXPECT_OVERFLOW; \
- TYPE result; \
- ASSERT_EQ(expectOverflow, FN(LHS, RHS, &result)) << #FN "(" #LHS ", " #RHS; \
- if (!expectOverflow) { \
- ASSERT_EQ(TYPE(EXPECTED_RESULT), TYPE(result)) << #FN "(" #LHS ", " #RHS " - >"; \
- } \
- } while (false)
-
-#define assertSignedMultiplyNoOverflow(LHS, RHS, EXPECTED) \
- assertArithOverflow(int64_t, overflow::mul, LHS, RHS, false, EXPECTED)
-#define assertSignedMultiplyWithOverflow(LHS, RHS) \
- assertArithOverflow(int64_t, overflow::mul, LHS, RHS, true, 0)
-
-#define assertUnsignedMultiplyNoOverflow(LHS, RHS, EXPECTED) \
- assertArithOverflow(uint64_t, overflow::mul, LHS, RHS, false, EXPECTED)
-#define assertUnsignedMultiplyWithOverflow(LHS, RHS) \
- assertArithOverflow(uint64_t, overflow::mul, LHS, RHS, true, 0)
-
-#define assertSignedAddNoOverflow(LHS, RHS, EXPECTED) \
- assertArithOverflow(int64_t, overflow::add, LHS, RHS, false, EXPECTED)
-#define assertSignedAddWithOverflow(LHS, RHS) \
- assertArithOverflow(int64_t, overflow::add, LHS, RHS, true, 0)
-
-#define assertUnsignedAddNoOverflow(LHS, RHS, EXPECTED) \
- assertArithOverflow(uint64_t, overflow::add, LHS, RHS, false, EXPECTED)
-#define assertUnsignedAddWithOverflow(LHS, RHS) \
- assertArithOverflow(uint64_t, overflow::add, LHS, RHS, true, 0)
-
-#define assertSignedSubtractNoOverflow(LHS, RHS, EXPECTED) \
- assertArithOverflow(int64_t, overflow::sub, LHS, RHS, false, EXPECTED)
-#define assertSignedSubtractWithOverflow(LHS, RHS) \
- assertArithOverflow(int64_t, overflow::sub, LHS, RHS, true, 0)
-
-#define assertUnsignedSubtractNoOverflow(LHS, RHS, EXPECTED) \
- assertArithOverflow(uint64_t, overflow::sub, LHS, RHS, false, EXPECTED)
-#define assertUnsignedSubtractWithOverflow(LHS, RHS) \
- assertArithOverflow(uint64_t, overflow::sub, LHS, RHS, true, 0)
+// Polymorphic lambdas to defer overload resolution until execution time.
+constexpr auto polyMul = [](auto&&... a) { return overflow::mul(a...); };
+constexpr auto polyAdd = [](auto&&... a) { return overflow::add(a...); };
+constexpr auto polySub = [](auto&&... a) { return overflow::sub(a...); };
TEST(OverflowArithmetic, SignedMultiplicationTests) {
- using limits = std::numeric_limits<int64_t>;
- assertSignedMultiplyNoOverflow(0, limits::max(), 0);
- assertSignedMultiplyNoOverflow(0, limits::min(), 0);
- assertSignedMultiplyNoOverflow(1, limits::max(), limits::max());
- assertSignedMultiplyNoOverflow(1, limits::min(), limits::min());
- assertSignedMultiplyNoOverflow(-1, limits::max(), limits::min() + 1);
- assertSignedMultiplyNoOverflow(1000, 57, 57000);
- assertSignedMultiplyNoOverflow(1000, -57, -57000);
- assertSignedMultiplyNoOverflow(-1000, -57, 57000);
- assertSignedMultiplyNoOverflow(0x3fffffffffffffff, 2, 0x7ffffffffffffffe);
- assertSignedMultiplyNoOverflow(0x3fffffffffffffff, -2, -0x7ffffffffffffffe);
- assertSignedMultiplyNoOverflow(-0x3fffffffffffffff, -2, 0x7ffffffffffffffe);
-
- assertSignedMultiplyWithOverflow(-1, limits::min());
- assertSignedMultiplyWithOverflow(2, limits::max());
- assertSignedMultiplyWithOverflow(-2, limits::max());
- assertSignedMultiplyWithOverflow(2, limits::min());
- assertSignedMultiplyWithOverflow(-2, limits::min());
- assertSignedMultiplyWithOverflow(limits::min(), limits::max());
- assertSignedMultiplyWithOverflow(limits::max(), limits::max());
- assertSignedMultiplyWithOverflow(limits::min(), limits::min());
- assertSignedMultiplyWithOverflow(1LL << 62, 8);
- assertSignedMultiplyWithOverflow(-(1LL << 62), 8);
- assertSignedMultiplyWithOverflow(-(1LL << 62), -8);
+ using T = int64_t;
+ static constexpr auto f = polyMul;
+ ASSERT(test<T>(f, 0, kMax<T>, 0));
+ ASSERT(test<T>(f, 0, kMin<T>, 0));
+ ASSERT(test<T>(f, 1, kMax<T>, kMax<T>));
+ ASSERT(test<T>(f, 1, kMin<T>, kMin<T>));
+ ASSERT(test<T>(f, -1, kMax<T>, kMin<T> + 1));
+ ASSERT(test<T>(f, 1000, 57, 57000));
+ ASSERT(test<T>(f, 1000, -57, -57000));
+ ASSERT(test<T>(f, -1000, -57, 57000));
+ ASSERT(test<T>(f, 0x3fffffffffffffff, 2, 0x7ffffffffffffffe));
+ ASSERT(test<T>(f, 0x3fffffffffffffff, -2, -0x7ffffffffffffffe));
+ ASSERT(test<T>(f, -0x3fffffffffffffff, -2, 0x7ffffffffffffffe));
+ ASSERT(testOflow<T>(f, -1, kMin<T>));
+ ASSERT(testOflow<T>(f, 2, kMax<T>));
+ ASSERT(testOflow<T>(f, -2, kMax<T>));
+ ASSERT(testOflow<T>(f, 2, kMin<T>));
+ ASSERT(testOflow<T>(f, -2, kMin<T>));
+ ASSERT(testOflow<T>(f, kMin<T>, kMax<T>));
+ ASSERT(testOflow<T>(f, kMax<T>, kMax<T>));
+ ASSERT(testOflow<T>(f, kMin<T>, kMin<T>));
+ ASSERT(testOflow<T>(f, 1LL << 62, 8));
+ ASSERT(testOflow<T>(f, -(1LL << 62), 8));
+ ASSERT(testOflow<T>(f, -(1LL << 62), -8));
}
TEST(OverflowArithmetic, UnignedMultiplicationTests) {
- using limits = std::numeric_limits<uint64_t>;
- assertUnsignedMultiplyNoOverflow(0, limits::max(), 0);
- assertUnsignedMultiplyNoOverflow(1, limits::max(), limits::max());
- assertUnsignedMultiplyNoOverflow(1000, 57, 57000);
- assertUnsignedMultiplyNoOverflow(0x3fffffffffffffff, 2, 0x7ffffffffffffffe);
- assertUnsignedMultiplyNoOverflow(0x7fffffffffffffff, 2, 0xfffffffffffffffe);
-
- assertUnsignedMultiplyWithOverflow(2, limits::max());
- assertUnsignedMultiplyWithOverflow(limits::max(), limits::max());
- assertUnsignedMultiplyWithOverflow(1LL << 62, 8);
- assertUnsignedMultiplyWithOverflow(0x7fffffffffffffff, 4);
+ using T = uint64_t;
+ static constexpr auto f = polyMul;
+ ASSERT(test<T>(f, 0, kMax<T>, 0));
+ ASSERT(test<T>(f, 1, kMax<T>, kMax<T>));
+ ASSERT(test<T>(f, 1000, 57, 57000));
+ ASSERT(test<T>(f, 0x3fffffffffffffff, 2, 0x7ffffffffffffffe));
+ ASSERT(test<T>(f, 0x7fffffffffffffff, 2, 0xfffffffffffffffe));
+ ASSERT(testOflow<T>(f, 2, kMax<T>));
+ ASSERT(testOflow<T>(f, kMax<T>, kMax<T>));
+ ASSERT(testOflow<T>(f, 1LL << 62, 8));
+ ASSERT(testOflow<T>(f, 0x7fffffffffffffff, 4));
}
TEST(OverflowArithmetic, SignedAdditionTests) {
- using limits = std::numeric_limits<int64_t>;
- assertSignedAddNoOverflow(0, limits::max(), limits::max());
- assertSignedAddNoOverflow(-1, limits::max(), limits::max() - 1);
- assertSignedAddNoOverflow(1, limits::max() - 1, limits::max());
- assertSignedAddNoOverflow(0, limits::min(), limits::min());
- assertSignedAddNoOverflow(1, limits::min(), limits::min() + 1);
- assertSignedAddNoOverflow(-1, limits::min() + 1, limits::min());
- assertSignedAddNoOverflow(limits::max(), limits::min(), -1);
- assertSignedAddNoOverflow(1, 1, 2);
- assertSignedAddNoOverflow(-1, -1, -2);
-
- assertSignedAddWithOverflow(limits::max(), 1);
- assertSignedAddWithOverflow(limits::max(), limits::max());
- assertSignedAddWithOverflow(limits::min(), -1);
- assertSignedAddWithOverflow(limits::min(), limits::min());
+ using T = int64_t;
+ static constexpr auto f = polyAdd;
+ ASSERT(test<T>(f, 0, kMax<T>, kMax<T>));
+ ASSERT(test<T>(f, -1, kMax<T>, kMax<T> - 1));
+ ASSERT(test<T>(f, 1, kMax<T> - 1, kMax<T>));
+ ASSERT(test<T>(f, 0, kMin<T>, kMin<T>));
+ ASSERT(test<T>(f, 1, kMin<T>, kMin<T> + 1));
+ ASSERT(test<T>(f, -1, kMin<T> + 1, kMin<T>));
+ ASSERT(test<T>(f, kMax<T>, kMin<T>, -1));
+ ASSERT(test<T>(f, 1, 1, 2));
+ ASSERT(test<T>(f, -1, -1, -2));
+ ASSERT(testOflow<T>(f, kMax<T>, 1));
+ ASSERT(testOflow<T>(f, kMax<T>, kMax<T>));
+ ASSERT(testOflow<T>(f, kMin<T>, -1));
+ ASSERT(testOflow<T>(f, kMin<T>, kMin<T>));
}
TEST(OverflowArithmetic, UnsignedAdditionTests) {
- using limits = std::numeric_limits<uint64_t>;
- assertUnsignedAddNoOverflow(0, limits::max(), limits::max());
- assertUnsignedAddNoOverflow(1, limits::max() - 1, limits::max());
- assertUnsignedAddNoOverflow(1, 1, 2);
-
- assertUnsignedAddWithOverflow(limits::max(), 1);
- assertUnsignedAddWithOverflow(limits::max(), limits::max());
+ using T = uint64_t;
+ static constexpr auto f = polyAdd;
+ ASSERT(test<T>(f, 0, kMax<T>, kMax<T>));
+ ASSERT(test<T>(f, 1, kMax<T> - 1, kMax<T>));
+ ASSERT(test<T>(f, 1, 1, 2));
+ ASSERT(testOflow<T>(f, kMax<T>, 1));
+ ASSERT(testOflow<T>(f, kMax<T>, kMax<T>));
}
TEST(OverflowArithmetic, SignedSubtractionTests) {
- using limits = std::numeric_limits<int64_t>;
- assertSignedSubtractNoOverflow(limits::max(), 0, limits::max());
- assertSignedSubtractNoOverflow(limits::max(), 1, limits::max() - 1);
- assertSignedSubtractNoOverflow(limits::max() - 1, -1, limits::max());
- assertSignedSubtractNoOverflow(limits::min(), 0, limits::min());
- assertSignedSubtractNoOverflow(limits::min(), -1, limits::min() + 1);
- assertSignedSubtractNoOverflow(limits::min() + 1, 1, limits::min());
- assertSignedSubtractNoOverflow(limits::max(), limits::max(), 0);
- assertSignedSubtractNoOverflow(limits::min(), limits::min(), 0);
- assertSignedSubtractNoOverflow(0, 0, 0);
- assertSignedSubtractNoOverflow(1, 1, 0);
- assertSignedSubtractNoOverflow(0, 1, -1);
-
- assertSignedSubtractWithOverflow(0, limits::min());
- assertSignedSubtractWithOverflow(limits::max(), -1);
- assertSignedSubtractWithOverflow(limits::max(), limits::min());
- assertSignedSubtractWithOverflow(limits::min(), 1);
- assertSignedSubtractWithOverflow(limits::min(), limits::max());
+ using T = int64_t;
+ static constexpr auto f = polySub;
+ ASSERT(test<T>(f, kMax<T>, 0, kMax<T>));
+ ASSERT(test<T>(f, kMax<T>, 1, kMax<T> - 1));
+ ASSERT(test<T>(f, kMax<T> - 1, -1, kMax<T>));
+ ASSERT(test<T>(f, kMin<T>, 0, kMin<T>));
+ ASSERT(test<T>(f, kMin<T>, -1, kMin<T> + 1));
+ ASSERT(test<T>(f, kMin<T> + 1, 1, kMin<T>));
+ ASSERT(test<T>(f, kMax<T>, kMax<T>, 0));
+ ASSERT(test<T>(f, kMin<T>, kMin<T>, 0));
+ ASSERT(test<T>(f, 0, 0, 0));
+ ASSERT(test<T>(f, 1, 1, 0));
+ ASSERT(test<T>(f, 0, 1, -1));
+ ASSERT(testOflow<T>(f, 0, kMin<T>));
+ ASSERT(testOflow<T>(f, kMax<T>, -1));
+ ASSERT(testOflow<T>(f, kMax<T>, kMin<T>));
+ ASSERT(testOflow<T>(f, kMin<T>, 1));
+ ASSERT(testOflow<T>(f, kMin<T>, kMax<T>));
}
TEST(OverflowArithmetic, UnsignedSubtractionTests) {
- using limits = std::numeric_limits<uint64_t>;
- assertUnsignedSubtractNoOverflow(limits::max(), 0, limits::max());
- assertUnsignedSubtractNoOverflow(limits::max(), 1, limits::max() - 1);
- assertUnsignedSubtractNoOverflow(limits::max(), limits::max(), 0);
- assertUnsignedSubtractNoOverflow(0, 0, 0);
- assertUnsignedSubtractNoOverflow(1, 1, 0);
-
- assertUnsignedSubtractWithOverflow(0, 1);
- assertUnsignedSubtractWithOverflow(0, limits::max());
+ using T = uint64_t;
+ static constexpr auto f = polySub;
+ ASSERT(test<T>(f, kMax<T>, 0, kMax<T>));
+ ASSERT(test<T>(f, kMax<T>, 1, kMax<T> - 1));
+ ASSERT(test<T>(f, kMax<T>, kMax<T>, 0));
+ ASSERT(test<T>(f, 0, 0, 0));
+ ASSERT(test<T>(f, 1, 1, 0));
+ ASSERT(testOflow<T>(f, 0, 1));
+ ASSERT(testOflow<T>(f, 0, kMax<T>));
+}
+
+TEST(OverflowArithmetic, HeterogeneousArguments) {
+ {
+ int r;
+ ASSERT_FALSE(overflow::mul(long{1}, (unsigned long long){2}, &r));
+ ASSERT_EQ(r, 2);
+ }
+ {
+ unsigned long long r;
+ ASSERT_TRUE(overflow::mul(-1, 2, &r));
+ }
}
} // namespace