summaryrefslogtreecommitdiff
path: root/src/mongo/platform
diff options
context:
space:
mode:
authorBilly Donahue <billy.donahue@mongodb.com>2019-06-16 14:43:09 -0400
committerBilly Donahue <billy.donahue@mongodb.com>2019-06-16 14:43:09 -0400
commit58df54d9c73b28bddfb2d83014f653f0c06ef44e (patch)
tree172189ec94c58019f531adaf731cfe31c2ea5346 /src/mongo/platform
parente039271638d6dba34e5b64834e3f12e87aeb6455 (diff)
downloadmongo-58df54d9c73b28bddfb2d83014f653f0c06ef44e.tar.gz
Revert "SERVER-24374 Make Decimal128 integer ctors constexpr"
This reverts commit e039271638d6dba34e5b64834e3f12e87aeb6455.
Diffstat (limited to 'src/mongo/platform')
-rw-r--r--src/mongo/platform/decimal128.cpp31
-rw-r--r--src/mongo/platform/decimal128.h99
-rw-r--r--src/mongo/platform/decimal128_test.cpp125
3 files changed, 122 insertions, 133 deletions
diff --git a/src/mongo/platform/decimal128.cpp b/src/mongo/platform/decimal128.cpp
index a48a310bf74..18d59af7490 100644
--- a/src/mongo/platform/decimal128.cpp
+++ b/src/mongo/platform/decimal128.cpp
@@ -187,6 +187,15 @@ BID_UINT128 decimal128ToLibraryType(Decimal128::Value value) {
}
} // namespace
+Decimal128::Decimal128(std::int32_t int32Value)
+ : _value(libraryTypeToValue(bid128_from_int32(int32Value))) {}
+
+Decimal128::Decimal128(std::int64_t int64Value)
+ : _value(libraryTypeToValue(bid128_from_int64(int64Value))) {}
+
+Decimal128::Decimal128(std::uint64_t uint64Value)
+ : _value(libraryTypeToValue(bid128_from_uint64(uint64Value))) {}
+
/**
* Quantize a doubleValue argument to a Decimal128 with exactly 15 digits
* of precision.
@@ -283,8 +292,8 @@ Decimal128::Decimal128(double doubleValue,
// Check if the quantization was done correctly: _value stores exactly 15
// decimal digits of precision (15 digits can fit into the low 64 bits of the decimal)
- std::uint64_t kSmallest15DigitInt = 1E14; // A 1 with 14 zeros
- std::uint64_t kLargest15DigitInt = 1E15 - 1; // 15 nines
+ uint64_t kSmallest15DigitInt = 1E14; // A 1 with 14 zeros
+ uint64_t kLargest15DigitInt = 1E15 - 1; // 15 nines
if (getCoefficientLow() > kLargest15DigitInt) {
// If we didn't precisely get 15 digits of precision, the original base 10 exponent
// guess was 1 off, so quantize once more with base10Exp + 1
@@ -315,6 +324,10 @@ Decimal128::Decimal128(std::string stringValue,
_value = libraryTypeToValue(dec128);
}
+Decimal128::Value Decimal128::getValue() const {
+ return _value;
+}
+
Decimal128 Decimal128::toAbs() const {
BID_UINT128 dec128 = decimal128ToLibraryType(_value);
dec128 = bid128_abs(dec128);
@@ -448,12 +461,12 @@ std::int32_t Decimal128::toInt(std::uint32_t* signalingFlags, RoundingMode round
}
}
-std::int64_t Decimal128::toLong(RoundingMode roundMode) const {
+int64_t Decimal128::toLong(RoundingMode roundMode) const {
std::uint32_t throwAwayFlag = 0;
return toLong(&throwAwayFlag, roundMode);
}
-std::int64_t Decimal128::toLong(std::uint32_t* signalingFlags, RoundingMode roundMode) const {
+int64_t Decimal128::toLong(std::uint32_t* signalingFlags, RoundingMode roundMode) const {
BID_UINT128 dec128 = decimal128ToLibraryType(_value);
switch (roundMode) {
case kRoundTiesToEven:
@@ -900,10 +913,10 @@ Decimal128 Decimal128::quantize(const Decimal128& reference,
auto normalizedThis = this->normalize();
auto normalizedReferenceExponent =
- static_cast<std::int32_t>(reference.normalize().getBiasedExponent());
+ static_cast<int32_t>(reference.normalize().getBiasedExponent());
if (normalizedReferenceExponent != 0 &&
- (static_cast<std::int32_t>(normalizedThis.getBiasedExponent()) -
- normalizedReferenceExponent) > 33) {
+ (static_cast<int32_t>(normalizedThis.getBiasedExponent()) - normalizedReferenceExponent) >
+ 33) {
return normalizedThis;
}
return nonNormalizingQuantize(reference, signalingFlags, roundMode);
@@ -976,7 +989,7 @@ const std::uint64_t t17 = 100ull * 1000 * 1000 * 1000 * 1000 * 1000;
// Computed by running the calculations in Python, and verified with static_assert.
const std::uint64_t t34lo64 = 4003012203950112767ULL;
#if defined(__GNUC__)
-MONGO_STATIC_ASSERT(t34lo64 == t17 * t17 - 1);
+static_assert(t34lo64 == t17 * t17 - 1, "precomputed constant is wrong");
#endif
// Mod t17 by 2^32 to get the low 32 bits of t17's binary representation
const std::uint64_t t17lo32 = t17 % (1ull << 32);
@@ -1001,7 +1014,7 @@ const Decimal128 Decimal128::kSmallestNegative(1, 0, 0, 1);
// Get the representation of 0 (0E0).
const Decimal128 Decimal128::kNormalizedZero(Decimal128::Value(
- {0, static_cast<std::uint64_t>(Decimal128::kExponentBias) << Decimal128::kExponentFieldPos}));
+ {0, static_cast<uint64_t>(Decimal128::kExponentBias) << Decimal128::kExponentFieldPos}));
// Shift the format of the combination bits to the right position to get Inf and NaN
// +Inf = 0111 1000 ... ... = 0x78 ... ..., -Inf = 1111 1000 ... ... = 0xf8 ... ...
diff --git a/src/mongo/platform/decimal128.h b/src/mongo/platform/decimal128.h
index 3295e28a2b9..7b96d8e2611 100644
--- a/src/mongo/platform/decimal128.h
+++ b/src/mongo/platform/decimal128.h
@@ -33,13 +33,11 @@
#include <cstdint>
#include <iostream>
#include <string>
-#include <type_traits>
#include <utility>
#include "mongo/config.h"
#include "mongo/util/assert_util.h"
-#include "mongo/util/if_constexpr.h"
namespace mongo {
@@ -77,11 +75,10 @@ public:
static const Decimal128 kPiOver180;
static const Decimal128 k180OverPi;
- static constexpr std::uint32_t kMaxBiasedExponent = 6143 + 6144;
+ static const uint32_t kMaxBiasedExponent = 6143 + 6144;
// Biased exponent of a Decimal128 with least significant digit in the units place
- static constexpr std::int32_t kExponentBias = 6143 + 33;
- static constexpr std::uint32_t kInfinityExponent =
- kMaxBiasedExponent + 1; // internal convention only
+ static const int32_t kExponentBias = 6143 + 33;
+ static const uint32_t kInfinityExponent = kMaxBiasedExponent + 1; // internal convention only
/**
* This struct holds the raw data for IEEE 754-2008 data types
@@ -127,17 +124,17 @@ public:
kInexact = 0x20,
};
- constexpr static bool hasFlag(std::uint32_t signalingFlags, SignalingFlag f) {
+ static bool hasFlag(std::uint32_t signalingFlags, SignalingFlag f) {
return ((signalingFlags & f) != 0u);
}
/**
* Returns true if a valid Decimal can be constructed from the given arguments.
*/
- constexpr static bool isValid(std::uint64_t sign,
- std::uint64_t exponent,
- std::uint64_t coefficientHigh,
- std::uint64_t coefficientLow) {
+ static bool isValid(uint64_t sign,
+ uint64_t exponent,
+ uint64_t coefficientHigh,
+ uint64_t coefficientLow) {
if (coefficientHigh >= 0x1ed09bead87c0 &&
(coefficientHigh != 0x1ed09bead87c0 || coefficientLow != 0x378d8e63ffffffff)) {
return false;
@@ -152,10 +149,7 @@ public:
/**
* Construct a 0E0 valued Decimal128.
*/
- constexpr Decimal128()
- : _value{0,
- static_cast<std::uint64_t>(Decimal128::kExponentBias)
- << Decimal128::kExponentFieldPos} {}
+ Decimal128() : _value(kNormalizedZero._value) {}
/**
* This constructor takes in a raw decimal128 type, which consists of two
@@ -168,15 +162,16 @@ public:
* Constructs a Decimal128 from parts, dealing with proper encoding of the combination field.
* Assumes that the value will be inside the valid range of finite values. (No NaN/Inf, etc.)
*/
- constexpr Decimal128(std::uint64_t sign,
- std::uint64_t exponent,
- std::uint64_t coefficientHigh,
- std::uint64_t coefficientLow)
- : _value(_valueFromParts(sign, exponent, coefficientHigh, coefficientLow)) {}
+ Decimal128(uint64_t sign, uint64_t exponent, uint64_t coefficientHigh, uint64_t coefficientLow)
+ : _value(
+ Value{coefficientLow,
+ (sign << kSignFieldPos) | (exponent << kExponentFieldPos) | coefficientHigh}) {
+ dassert(isValid(sign, exponent, coefficientHigh, coefficientLow));
+ }
- template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
- constexpr explicit Decimal128(T v)
- : Decimal128(v < 0 ? 1 : 0, kExponentBias, 0, _makeCoefficientLow(v)) {}
+ explicit Decimal128(std::int32_t int32Value);
+ explicit Decimal128(std::int64_t int64Value);
+ explicit Decimal128(std::uint64_t uint64Value);
/**
* This constructor takes a double and constructs a Decimal128 object given a roundMode, either
@@ -212,15 +207,13 @@ public:
/**
* This function gets the inner Value struct storing a Decimal128 value.
*/
- constexpr Value getValue() const {
- return _value;
- }
+ Value getValue() const;
/**
* Extracts the biased exponent from the combination field.
*/
- constexpr std::uint32_t getBiasedExponent() const {
- const std::uint64_t combo = _getCombinationField();
+ uint32_t getBiasedExponent() const {
+ const uint64_t combo = _getCombinationField();
if (combo < kCombinationNonCanonical)
return combo >> 3;
@@ -233,7 +226,7 @@ public:
* Returns the high 49 bits of the 113-bit binary encoded coefficient. Returns 0 for
* non-canonical or non-finite numbers.
*/
- constexpr std::uint64_t getCoefficientHigh() const {
+ uint64_t getCoefficientHigh() const {
return _getCombinationField() < kCombinationNonCanonical
? _value.high64 & kCanonicalCoefficientHighFieldMask
: 0;
@@ -243,7 +236,7 @@ public:
* Returns the low 64 bits of the 113-bit binary encoded coefficient. Returns 0 for
* non-canonical or non-finite numbers.
*/
- constexpr std::uint64_t getCoefficientLow() const {
+ uint64_t getCoefficientLow() const {
return _getCombinationField() < kCombinationNonCanonical ? _value.low64 : 0;
}
@@ -526,16 +519,15 @@ public:
}
private:
- constexpr static std::uint8_t kSignFieldPos = 64 - 1;
- constexpr static std::uint8_t kCombinationFieldPos = kSignFieldPos - 17;
- constexpr static std::uint64_t kCombinationFieldMask = (1 << 17) - 1;
- constexpr static std::uint64_t kExponentFieldPos = kCombinationFieldPos + 3;
- constexpr static std::uint64_t kCoefficientContinuationFieldMask =
- (1ull << kCombinationFieldPos) - 1;
- constexpr static std::uint64_t kCombinationNonCanonical = 3 << 15;
- constexpr static std::uint64_t kCombinationInfinity = 0x1e << 12;
- constexpr static std::uint64_t kCombinationNaN = 0x1f << 12;
- constexpr static std::uint64_t kCanonicalCoefficientHighFieldMask = (1ull << 49) - 1;
+ static const uint8_t kSignFieldPos = 64 - 1;
+ static const uint8_t kCombinationFieldPos = kSignFieldPos - 17;
+ static const uint64_t kCombinationFieldMask = (1 << 17) - 1;
+ static const uint64_t kExponentFieldPos = kCombinationFieldPos + 3;
+ static const uint64_t kCoefficientContinuationFieldMask = (1ull << kCombinationFieldPos) - 1;
+ static const uint64_t kCombinationNonCanonical = 3 << 15;
+ static const uint64_t kCombinationInfinity = 0x1e << 12;
+ static const uint64_t kCombinationNaN = 0x1f << 12;
+ static const uint64_t kCanonicalCoefficientHighFieldMask = (1ull << 49) - 1;
std::string _convertToScientificNotation(StringData coefficient, int adjustedExponent) const;
std::string _convertToStandardDecimalNotation(StringData coefficient, int exponent) const;
@@ -550,35 +542,10 @@ private:
std::uint32_t* signalingFlags,
RoundingMode roundMode = kRoundTiesToEven) const;
- constexpr std::uint64_t _getCombinationField() const {
+ uint64_t _getCombinationField() const {
return (_value.high64 >> kCombinationFieldPos) & kCombinationFieldMask;
}
- constexpr static Value _valueFromParts(std::uint64_t sign,
- std::uint64_t exponent,
- std::uint64_t coefficientHigh,
- std::uint64_t coefficientLow) {
- // For constexpr's sake the invariant must be compiled only if !isValid().
- if (!isValid(sign, exponent, coefficientHigh, coefficientLow)) {
- invariant(false, "invalid arguments to Decimal128()");
- }
-
- return Value{coefficientLow,
- (sign << kSignFieldPos) | (exponent << kExponentFieldPos) | coefficientHigh};
- }
-
- // Constructs the absolute value of v as a uint64_t in a constexpr-permitted way.
- template <typename T>
- constexpr std::uint64_t _makeCoefficientLow(T i) {
- // if constexpr to avoid MSVC warnings.
- IF_CONSTEXPR(std::is_signed_v<T>) {
- return i < 0 ? static_cast<std::uint64_t>(-i) : static_cast<std::uint64_t>(i);
- }
- else {
- return static_cast<std::uint64_t>(i);
- }
- }
-
Value _value;
};
} // namespace mongo
diff --git a/src/mongo/platform/decimal128_test.cpp b/src/mongo/platform/decimal128_test.cpp
index 4881c369216..1f0362e6a3a 100644
--- a/src/mongo/platform/decimal128_test.cpp
+++ b/src/mongo/platform/decimal128_test.cpp
@@ -31,7 +31,6 @@
#include <array>
#include <cmath>
-#include <fmt/format.h>
#include <memory>
#include <string>
#include <utility>
@@ -41,68 +40,80 @@
namespace mongo {
-using namespace fmt::literals;
-
// Tests for Decimal128 constructors
TEST(Decimal128Test, TestDefaultConstructor) {
Decimal128 d;
ASSERT_TRUE(d.isBinaryEqual(Decimal128(0)));
}
-template <typename T>
-using Lim = std::numeric_limits<T>;
-
-TEST(Decimal128Test, TestConstructor) {
- // High bits of a positive Decimal128 with exponent 1.
- constexpr uint64_t posHigh = 0x3040000000000000;
- // High bits of a negative Decimal128 with exponent 1.
- constexpr uint64_t negHigh = 0xb040000000000000;
-
-#define TEST_CTOR(N, HIGH64, LOW64) \
- ASSERT_EQ(Decimal128{N}.getValue().high64, static_cast<uint64_t>(HIGH64)); \
- ASSERT_EQ(Decimal128{N}.getValue().low64, static_cast<uint64_t>(LOW64));
-
- TEST_CTOR(int8_t{0}, posHigh, 0); // +0E+0
- TEST_CTOR(Lim<int8_t>::lowest(), negHigh, uint64_t{1} << 7);
- TEST_CTOR(Lim<int8_t>::max(), posHigh, (uint64_t{1} << 7) - 1);
- TEST_CTOR(int8_t{5}, posHigh, 0x5);
-
- TEST_CTOR(uint8_t{0}, posHigh, 0);
- TEST_CTOR(Lim<uint8_t>::max(), posHigh, (uint64_t{1} << 8) - 1);
- TEST_CTOR(uint8_t{5}, posHigh, 0x5);
-
- TEST_CTOR(int16_t{0}, posHigh, 0);
- TEST_CTOR(Lim<int16_t>::lowest(), negHigh, uint64_t{1} << 15);
- TEST_CTOR(Lim<int16_t>::max(), posHigh, (uint64_t{1} << 15) - 1);
- TEST_CTOR(int16_t{5}, posHigh, 0x5);
-
- TEST_CTOR(uint16_t{0}, posHigh, 0);
- TEST_CTOR(Lim<uint16_t>::max(), posHigh, (uint64_t{1} << 16) - 1);
- TEST_CTOR(uint16_t{5}, posHigh, 0x5);
+TEST(Decimal128Test, TestInt32ConstructorZero) {
+ int32_t intZero = 0;
+ Decimal128 d(intZero);
+ Decimal128::Value val = d.getValue();
+ // 0x3040000000000000 0000000000000000 = +0E+0
+ uint64_t highBytes = 0x3040000000000000ull;
+ uint64_t lowBytes = 0x0000000000000000ull;
+ ASSERT_EQUALS(val.high64, highBytes);
+ ASSERT_EQUALS(val.low64, lowBytes);
+}
- TEST_CTOR(int32_t{0}, posHigh, 0);
- TEST_CTOR(Lim<int32_t>::lowest(), negHigh, uint64_t{1} << 31);
- TEST_CTOR(Lim<int32_t>::max(), posHigh, (uint64_t{1} << 31) - 1);
- TEST_CTOR(int32_t{5}, posHigh, 0x5);
+TEST(Decimal128Test, TestInt32ConstructorMax) {
+ int32_t intMax = std::numeric_limits<int32_t>::max();
+ Decimal128 d(intMax);
+ Decimal128::Value val = d.getValue();
+ // 0x3040000000000000 000000007fffffff = +2147483647E+0
+ uint64_t highBytes = 0x3040000000000000ull;
+ uint64_t lowBytes = 0x000000007fffffffull;
+ ASSERT_EQUALS(val.high64, highBytes);
+ ASSERT_EQUALS(val.low64, lowBytes);
+}
- TEST_CTOR(uint32_t{0}, posHigh, 0);
- TEST_CTOR(Lim<uint32_t>::max(), posHigh, (uint64_t{1} << 32) - 1);
- TEST_CTOR(uint32_t{5}, posHigh, 0x5);
+TEST(Decimal128Test, TestInt32ConstructorMin) {
+ int32_t intMin = std::numeric_limits<int32_t>::lowest();
+ Decimal128 d(intMin);
+ Decimal128::Value val = d.getValue();
+ // 0xb040000000000000 000000007fffffff = -2147483648E+0
+ uint64_t highBytes = 0xb040000000000000ull;
+ uint64_t lowBytes = 0x0000000080000000ull;
+ ASSERT_EQUALS(val.high64, highBytes);
+ ASSERT_EQUALS(val.low64, lowBytes);
+}
- TEST_CTOR(int64_t{0}, posHigh, 0);
- TEST_CTOR(Lim<int64_t>::lowest(), negHigh, uint64_t{1} << 63);
- TEST_CTOR(Lim<int64_t>::max(), posHigh, (uint64_t{1} << 63) - 1);
- TEST_CTOR(int64_t{5}, posHigh, 0x5);
+TEST(Decimal128Test, TestInt64ConstructorZero) {
+ int64_t longZero = 0;
+ Decimal128 d(longZero);
+ Decimal128::Value val = d.getValue();
+ // 0x3040000000000000 0000000000000000 = +0E+0
+ uint64_t highBytes = 0x3040000000000000ull;
+ uint64_t lowBytes = 0x0000000000000000ull;
+ ASSERT_EQUALS(val.high64, highBytes);
+ ASSERT_EQUALS(val.low64, lowBytes);
+}
- TEST_CTOR(uint64_t{0}, posHigh, 0);
- TEST_CTOR(Lim<uint64_t>::max(), posHigh, Lim<uint64_t>::max());
- TEST_CTOR(uint64_t{5}, posHigh, 0x5);
+TEST(Decimal128Test, TestInt64ConstructorMax) {
+ int64_t longMax = std::numeric_limits<long long>::max();
+ Decimal128 d(longMax);
+ Decimal128::Value val = d.getValue();
+ // 0x3040000000000000 7fffffffffffffff = +9223372036854775807E+0
+ uint64_t highBytes = 0x3040000000000000ull;
+ uint64_t lowBytes = 0x7fffffffffffffffull;
+ ASSERT_EQUALS(val.high64, highBytes);
+ ASSERT_EQUALS(val.low64, lowBytes);
+}
-#undef TEST_CTOR
+TEST(Decimal128Test, TestInt64ConstructorMin) {
+ int64_t longMin = std::numeric_limits<long long>::lowest();
+ Decimal128 d(longMin);
+ Decimal128::Value val = d.getValue();
+ // 0xb040000000000000 8000000000000000 = -9223372036854775808E+0
+ uint64_t highBytes = 0xb040000000000000;
+ uint64_t lowBytes = 0x8000000000000000;
+ ASSERT_EQUALS(val.high64, highBytes);
+ ASSERT_EQUALS(val.low64, lowBytes);
}
TEST(Decimal128Test, TestPartsConstructor) {
- constexpr Decimal128 expected(10);
+ Decimal128 expected(10);
Decimal128 val(0LL, Decimal128::kExponentBias, 0LL, 10LL);
ASSERT_EQUALS(val.getValue().low64, expected.getValue().low64);
ASSERT_EQUALS(val.getValue().low64, expected.getValue().low64);
@@ -287,19 +298,17 @@ TEST(Decimal128Test, TestNonCanonicalDecimal) {
// when encountered. However, the exponent and sign still matter.
// 0x6c10000000000000 0000000000000000 = non-canonical 0, all ignored bits clear
- constexpr Decimal128 nonCanonical0E0(Decimal128::Value{0, 0x6c10000000000000ull});
+ Decimal128 nonCanonical0E0(Decimal128::Value{0, 0x6c10000000000000ull});
std::string zeroE0 = nonCanonical0E0.toString();
ASSERT_EQUALS(zeroE0, "0");
// 0xec100000deadbeef 0123456789abcdef = non-canonical -0, random stuff in ignored bits
- constexpr Decimal128 nonCanonicalM0E0(
- Decimal128::Value{0x0123456789abcdefull, 0xec100000deadbeefull});
+ Decimal128 nonCanonicalM0E0(Decimal128::Value{0x0123456789abcdefull, 0xec100000deadbeefull});
std::string minusZeroE0 = nonCanonicalM0E0.toString();
ASSERT_EQUALS(minusZeroE0, "-0");
// 0x6c11fffffffffffff ffffffffffffffff = non-canonical 0.000, all ignored bits set
- constexpr Decimal128 nonCanonical0E3(
- Decimal128::Value{0xffffffffffffffffull, 0x6c11ffffffffffffull});
+ Decimal128 nonCanonical0E3(Decimal128::Value{0xffffffffffffffffull, 0x6c11ffffffffffffull});
std::string zeroE3 = nonCanonical0E3.toString();
ASSERT_EQUALS(zeroE3, "0E+3");
@@ -318,13 +327,13 @@ TEST(Decimal128Test, TestNonCanonicalDecimal) {
// Tests for absolute value function
TEST(Decimal128Test, TestAbsValuePos) {
- constexpr Decimal128 d(25);
+ Decimal128 d(25);
Decimal128 dAbs = d.toAbs();
ASSERT_TRUE(dAbs.isEqual(d));
}
TEST(Decimal128Test, TestAbsValueNeg) {
- constexpr Decimal128 d(-25);
+ Decimal128 d(-25);
Decimal128 dAbs = d.toAbs();
ASSERT_TRUE(dAbs.isEqual(Decimal128(25)));
}
@@ -949,8 +958,8 @@ TEST(Decimal128Test, TestDecimal128DivideSignaling) {
// Test Decimal128 special comparisons
TEST(Decimal128Test, TestDecimal128IsZero) {
- constexpr Decimal128 d1(0);
- constexpr Decimal128 d2(500);
+ Decimal128 d1(0);
+ Decimal128 d2(500);
ASSERT_TRUE(d1.isZero());
ASSERT_FALSE(d2.isZero());
}