summaryrefslogtreecommitdiff
path: root/src/mongo/bson
diff options
context:
space:
mode:
authorDavid Storch <david.storch@10gen.com>2016-08-12 15:58:56 -0400
committerDavid Storch <david.storch@10gen.com>2016-08-18 11:14:17 -0400
commit26543060c852aac22f26143a04bf7789ec8fec53 (patch)
treedf3ae49e5c4745058be29b7ec8a8e4b528b50a9a /src/mongo/bson
parent13fa28982d008568f7620d73ddec0c61fad7cbc8 (diff)
downloadmongo-26543060c852aac22f26143a04bf7789ec8fec53.tar.gz
SERVER-24508 BSONObj::ComparatorInterface
BSONObj instances should now be compared via the comparator interface's evaluate() method. This preferred over using BSONObj::woCompare() directly. If the comparison doesn't require any database semantics (e.g. there is no collation), there is a global instance of the SimpleBSONObjComparator which should be used for BSONObj comparisons. If the comparison requires special semantics, then callers must instantiate their own comparator object.
Diffstat (limited to 'src/mongo/bson')
-rw-r--r--src/mongo/bson/bson_field_test.cpp12
-rw-r--r--src/mongo/bson/bson_obj_test.cpp418
-rw-r--r--src/mongo/bson/bsonobj.h68
-rw-r--r--src/mongo/bson/bsonobj_comparator_interface.h195
-rw-r--r--src/mongo/bson/bsonobjbuilder_test.cpp26
-rw-r--r--src/mongo/bson/mutable/mutable_bson_test.cpp90
-rw-r--r--src/mongo/bson/simple_bsonobj_comparator.cpp38
-rw-r--r--src/mongo/bson/simple_bsonobj_comparator.h49
8 files changed, 617 insertions, 279 deletions
diff --git a/src/mongo/bson/bson_field_test.cpp b/src/mongo/bson/bson_field_test.cpp
index b6fbb0fd565..0a0b2d9aec2 100644
--- a/src/mongo/bson/bson_field_test.cpp
+++ b/src/mongo/bson/bson_field_test.cpp
@@ -36,31 +36,31 @@ using mongo::BSONObj;
TEST(Assignment, Simple) {
BSONField<int> x("x");
BSONObj o = BSON(x << 5);
- ASSERT_EQUALS(BSON("x" << 5), o);
+ ASSERT_BSONOBJ_EQ(BSON("x" << 5), o);
}
TEST(Make, Simple) {
BSONField<int> x("x");
BSONObj o = BSON(x.make(5));
- ASSERT_EQUALS(BSON("x" << 5), o);
+ ASSERT_BSONOBJ_EQ(BSON("x" << 5), o);
}
TEST(Query, GreaterThan) {
BSONField<int> x("x");
BSONObj o = BSON(x(5));
- ASSERT_EQUALS(BSON("x" << 5), o);
+ ASSERT_BSONOBJ_EQ(BSON("x" << 5), o);
o = BSON(x.gt(5));
- ASSERT_EQUALS(BSON("x" << BSON("$gt" << 5)), o);
+ ASSERT_BSONOBJ_EQ(BSON("x" << BSON("$gt" << 5)), o);
}
TEST(Query, NotEqual) {
BSONField<int> x("x");
BSONObj o = BSON(x(10));
- ASSERT_EQUALS(BSON("x" << 10), o);
+ ASSERT_BSONOBJ_EQ(BSON("x" << 10), o);
o = BSON(x.ne(5));
- ASSERT_EQUALS(BSON("x" << BSON("$ne" << 5)), o);
+ ASSERT_BSONOBJ_EQ(BSON("x" << BSON("$ne" << 5)), o);
}
} // unnamed namespace
diff --git a/src/mongo/bson/bson_obj_test.cpp b/src/mongo/bson/bson_obj_test.cpp
index f59f74ebd82..bf38662a321 100644
--- a/src/mongo/bson/bson_obj_test.cpp
+++ b/src/mongo/bson/bson_obj_test.cpp
@@ -42,92 +42,94 @@ TEST(BSONObjToString, EmptyArray) {
}
TEST(BSONObjCompare, Timestamp) {
- ASSERT_LT(BSON("" << Timestamp(0, 3)), BSON("" << Timestamp(~0U, 2)));
- ASSERT_GT(BSON("" << Timestamp(2, 3)), BSON("" << Timestamp(2, 2)));
- ASSERT_EQ(BSON("" << Timestamp(3ULL)), BSON("" << Timestamp(0, 3)));
+ ASSERT_BSONOBJ_LT(BSON("" << Timestamp(0, 3)), BSON("" << Timestamp(~0U, 2)));
+ ASSERT_BSONOBJ_GT(BSON("" << Timestamp(2, 3)), BSON("" << Timestamp(2, 2)));
+ ASSERT_BSONOBJ_EQ(BSON("" << Timestamp(3ULL)), BSON("" << Timestamp(0, 3)));
}
TEST(BSONObjCompare, NumberDouble) {
- ASSERT_LT(BSON("" << 0.0), BSON("" << 1.0));
- ASSERT_LT(BSON("" << -1.0), BSON("" << 0.0));
- ASSERT_LT(BSON("" << -1.0), BSON("" << 1.0));
-
- ASSERT_LT(BSON("" << 0.0), BSON("" << 0.1));
- ASSERT_LT(BSON("" << 0.1), BSON("" << 1.0));
- ASSERT_LT(BSON("" << -1.0), BSON("" << -0.1));
- ASSERT_LT(BSON("" << -0.1), BSON("" << 0.0));
- ASSERT_LT(BSON("" << -0.1), BSON("" << 0.1));
-
- ASSERT_LT(BSON("" << 0.0), BSON("" << std::numeric_limits<double>::denorm_min()));
- ASSERT_GT(BSON("" << 0.0), BSON("" << -std::numeric_limits<double>::denorm_min()));
-
- ASSERT_LT(BSON("" << 1.0), BSON("" << (1.0 + std::numeric_limits<double>::epsilon())));
- ASSERT_GT(BSON("" << -1.0), BSON("" << (-1.0 - std::numeric_limits<double>::epsilon())));
-
- ASSERT_EQ(BSON("" << 0.0), BSON("" << -0.0));
-
- ASSERT_GT(BSON("" << std::numeric_limits<double>::infinity()), BSON("" << 0.0));
- ASSERT_GT(BSON("" << std::numeric_limits<double>::infinity()),
- BSON("" << std::numeric_limits<double>::max())); // max is finite
- ASSERT_GT(BSON("" << std::numeric_limits<double>::infinity()),
- BSON("" << -std::numeric_limits<double>::infinity()));
-
- ASSERT_LT(BSON("" << -std::numeric_limits<double>::infinity()), BSON("" << 0.0));
- ASSERT_LT(BSON("" << -std::numeric_limits<double>::infinity()),
- BSON("" << -std::numeric_limits<double>::max()));
- ASSERT_LT(BSON("" << -std::numeric_limits<double>::infinity()),
- BSON("" << std::numeric_limits<double>::infinity()));
-
- ASSERT_LT(BSON("" << std::numeric_limits<double>::quiet_NaN()), BSON("" << 0.0));
- ASSERT_LT(BSON("" << std::numeric_limits<double>::quiet_NaN()),
- BSON("" << -std::numeric_limits<double>::max()));
- ASSERT_LT(BSON("" << std::numeric_limits<double>::quiet_NaN()),
- BSON("" << std::numeric_limits<double>::infinity()));
- ASSERT_LT(BSON("" << std::numeric_limits<double>::quiet_NaN()),
- BSON("" << -std::numeric_limits<double>::infinity()));
+ ASSERT_BSONOBJ_LT(BSON("" << 0.0), BSON("" << 1.0));
+ ASSERT_BSONOBJ_LT(BSON("" << -1.0), BSON("" << 0.0));
+ ASSERT_BSONOBJ_LT(BSON("" << -1.0), BSON("" << 1.0));
+
+ ASSERT_BSONOBJ_LT(BSON("" << 0.0), BSON("" << 0.1));
+ ASSERT_BSONOBJ_LT(BSON("" << 0.1), BSON("" << 1.0));
+ ASSERT_BSONOBJ_LT(BSON("" << -1.0), BSON("" << -0.1));
+ ASSERT_BSONOBJ_LT(BSON("" << -0.1), BSON("" << 0.0));
+ ASSERT_BSONOBJ_LT(BSON("" << -0.1), BSON("" << 0.1));
+
+ ASSERT_BSONOBJ_LT(BSON("" << 0.0), BSON("" << std::numeric_limits<double>::denorm_min()));
+ ASSERT_BSONOBJ_GT(BSON("" << 0.0), BSON("" << -std::numeric_limits<double>::denorm_min()));
+
+ ASSERT_BSONOBJ_LT(BSON("" << 1.0), BSON("" << (1.0 + std::numeric_limits<double>::epsilon())));
+ ASSERT_BSONOBJ_GT(BSON("" << -1.0),
+ BSON("" << (-1.0 - std::numeric_limits<double>::epsilon())));
+
+ ASSERT_BSONOBJ_EQ(BSON("" << 0.0), BSON("" << -0.0));
+
+ ASSERT_BSONOBJ_GT(BSON("" << std::numeric_limits<double>::infinity()), BSON("" << 0.0));
+ ASSERT_BSONOBJ_GT(BSON("" << std::numeric_limits<double>::infinity()),
+ BSON("" << std::numeric_limits<double>::max())); // max is finite
+ ASSERT_BSONOBJ_GT(BSON("" << std::numeric_limits<double>::infinity()),
+ BSON("" << -std::numeric_limits<double>::infinity()));
+
+ ASSERT_BSONOBJ_LT(BSON("" << -std::numeric_limits<double>::infinity()), BSON("" << 0.0));
+ ASSERT_BSONOBJ_LT(BSON("" << -std::numeric_limits<double>::infinity()),
+ BSON("" << -std::numeric_limits<double>::max()));
+ ASSERT_BSONOBJ_LT(BSON("" << -std::numeric_limits<double>::infinity()),
+ BSON("" << std::numeric_limits<double>::infinity()));
+
+ ASSERT_BSONOBJ_LT(BSON("" << std::numeric_limits<double>::quiet_NaN()), BSON("" << 0.0));
+ ASSERT_BSONOBJ_LT(BSON("" << std::numeric_limits<double>::quiet_NaN()),
+ BSON("" << -std::numeric_limits<double>::max()));
+ ASSERT_BSONOBJ_LT(BSON("" << std::numeric_limits<double>::quiet_NaN()),
+ BSON("" << std::numeric_limits<double>::infinity()));
+ ASSERT_BSONOBJ_LT(BSON("" << std::numeric_limits<double>::quiet_NaN()),
+ BSON("" << -std::numeric_limits<double>::infinity()));
// TODO in C++11 use hex floating point to test distinct NaN representations
- ASSERT_EQ(BSON("" << std::numeric_limits<double>::quiet_NaN()),
- BSON("" << std::numeric_limits<double>::signaling_NaN()));
+ ASSERT_BSONOBJ_EQ(BSON("" << std::numeric_limits<double>::quiet_NaN()),
+ BSON("" << std::numeric_limits<double>::signaling_NaN()));
}
TEST(BSONObjCompare, NumberLong_Double) {
- ASSERT_EQ(BSON("" << 0ll), BSON("" << 0.0));
- ASSERT_EQ(BSON("" << 0ll), BSON("" << -0.0));
+ ASSERT_BSONOBJ_EQ(BSON("" << 0ll), BSON("" << 0.0));
+ ASSERT_BSONOBJ_EQ(BSON("" << 0ll), BSON("" << -0.0));
- ASSERT_EQ(BSON("" << 1ll), BSON("" << 1.0));
- ASSERT_EQ(BSON("" << -1ll), BSON("" << -1.0));
+ ASSERT_BSONOBJ_EQ(BSON("" << 1ll), BSON("" << 1.0));
+ ASSERT_BSONOBJ_EQ(BSON("" << -1ll), BSON("" << -1.0));
- ASSERT_LT(BSON("" << 0ll), BSON("" << 1.0));
- ASSERT_LT(BSON("" << -1ll), BSON("" << 0.0));
- ASSERT_LT(BSON("" << -1ll), BSON("" << 1.0));
+ ASSERT_BSONOBJ_LT(BSON("" << 0ll), BSON("" << 1.0));
+ ASSERT_BSONOBJ_LT(BSON("" << -1ll), BSON("" << 0.0));
+ ASSERT_BSONOBJ_LT(BSON("" << -1ll), BSON("" << 1.0));
- ASSERT_LT(BSON("" << 0ll), BSON("" << 0.1));
- ASSERT_LT(BSON("" << 0.1), BSON("" << 1ll));
- ASSERT_LT(BSON("" << -1ll), BSON("" << -0.1));
- ASSERT_LT(BSON("" << -0.1), BSON("" << 0ll));
+ ASSERT_BSONOBJ_LT(BSON("" << 0ll), BSON("" << 0.1));
+ ASSERT_BSONOBJ_LT(BSON("" << 0.1), BSON("" << 1ll));
+ ASSERT_BSONOBJ_LT(BSON("" << -1ll), BSON("" << -0.1));
+ ASSERT_BSONOBJ_LT(BSON("" << -0.1), BSON("" << 0ll));
- ASSERT_LT(BSON("" << 0ll), BSON("" << std::numeric_limits<double>::denorm_min()));
- ASSERT_GT(BSON("" << 0ll), BSON("" << -std::numeric_limits<double>::denorm_min()));
+ ASSERT_BSONOBJ_LT(BSON("" << 0ll), BSON("" << std::numeric_limits<double>::denorm_min()));
+ ASSERT_BSONOBJ_GT(BSON("" << 0ll), BSON("" << -std::numeric_limits<double>::denorm_min()));
- ASSERT_LT(BSON("" << 1ll), BSON("" << (1.0 + std::numeric_limits<double>::epsilon())));
- ASSERT_GT(BSON("" << -1ll), BSON("" << (-1.0 - std::numeric_limits<double>::epsilon())));
+ ASSERT_BSONOBJ_LT(BSON("" << 1ll), BSON("" << (1.0 + std::numeric_limits<double>::epsilon())));
+ ASSERT_BSONOBJ_GT(BSON("" << -1ll),
+ BSON("" << (-1.0 - std::numeric_limits<double>::epsilon())));
- ASSERT_GT(BSON("" << std::numeric_limits<double>::infinity()), BSON("" << 0ll));
- ASSERT_GT(BSON("" << std::numeric_limits<double>::infinity()),
- BSON("" << std::numeric_limits<long long>::max()));
- ASSERT_GT(BSON("" << std::numeric_limits<double>::infinity()),
- BSON("" << std::numeric_limits<long long>::min()));
+ ASSERT_BSONOBJ_GT(BSON("" << std::numeric_limits<double>::infinity()), BSON("" << 0ll));
+ ASSERT_BSONOBJ_GT(BSON("" << std::numeric_limits<double>::infinity()),
+ BSON("" << std::numeric_limits<long long>::max()));
+ ASSERT_BSONOBJ_GT(BSON("" << std::numeric_limits<double>::infinity()),
+ BSON("" << std::numeric_limits<long long>::min()));
- ASSERT_LT(BSON("" << -std::numeric_limits<double>::infinity()), BSON("" << 0ll));
- ASSERT_LT(BSON("" << -std::numeric_limits<double>::infinity()),
- BSON("" << std::numeric_limits<long long>::max()));
- ASSERT_LT(BSON("" << -std::numeric_limits<double>::infinity()),
- BSON("" << std::numeric_limits<long long>::min()));
+ ASSERT_BSONOBJ_LT(BSON("" << -std::numeric_limits<double>::infinity()), BSON("" << 0ll));
+ ASSERT_BSONOBJ_LT(BSON("" << -std::numeric_limits<double>::infinity()),
+ BSON("" << std::numeric_limits<long long>::max()));
+ ASSERT_BSONOBJ_LT(BSON("" << -std::numeric_limits<double>::infinity()),
+ BSON("" << std::numeric_limits<long long>::min()));
- ASSERT_LT(BSON("" << std::numeric_limits<double>::quiet_NaN()), BSON("" << 0ll));
- ASSERT_LT(BSON("" << std::numeric_limits<double>::quiet_NaN()),
- BSON("" << std::numeric_limits<long long>::min()));
+ ASSERT_BSONOBJ_LT(BSON("" << std::numeric_limits<double>::quiet_NaN()), BSON("" << 0ll));
+ ASSERT_BSONOBJ_LT(BSON("" << std::numeric_limits<double>::quiet_NaN()),
+ BSON("" << std::numeric_limits<long long>::min()));
for (int powerOfTwo = 0; powerOfTwo < 63; powerOfTwo++) {
const long long lNum = 1ll << powerOfTwo;
@@ -136,22 +138,22 @@ TEST(BSONObjCompare, NumberLong_Double) {
// All powers of two in this range can be represented exactly as doubles.
invariant(lNum == static_cast<long long>(dNum));
- ASSERT_EQ(BSON("" << lNum), BSON("" << dNum));
- ASSERT_EQ(BSON("" << -lNum), BSON("" << -dNum));
+ ASSERT_BSONOBJ_EQ(BSON("" << lNum), BSON("" << dNum));
+ ASSERT_BSONOBJ_EQ(BSON("" << -lNum), BSON("" << -dNum));
- ASSERT_GT(BSON("" << (lNum + 1)), BSON("" << dNum));
- ASSERT_LT(BSON("" << (lNum - 1)), BSON("" << dNum));
- ASSERT_GT(BSON("" << (-lNum + 1)), BSON("" << -dNum));
- ASSERT_LT(BSON("" << (-lNum - 1)), BSON("" << -dNum));
+ ASSERT_BSONOBJ_GT(BSON("" << (lNum + 1)), BSON("" << dNum));
+ ASSERT_BSONOBJ_LT(BSON("" << (lNum - 1)), BSON("" << dNum));
+ ASSERT_BSONOBJ_GT(BSON("" << (-lNum + 1)), BSON("" << -dNum));
+ ASSERT_BSONOBJ_LT(BSON("" << (-lNum - 1)), BSON("" << -dNum));
if (powerOfTwo <= 52) { // is dNum - 0.5 representable?
- ASSERT_GT(BSON("" << lNum), BSON("" << (dNum - 0.5)));
- ASSERT_LT(BSON("" << -lNum), BSON("" << -(dNum - 0.5)));
+ ASSERT_BSONOBJ_GT(BSON("" << lNum), BSON("" << (dNum - 0.5)));
+ ASSERT_BSONOBJ_LT(BSON("" << -lNum), BSON("" << -(dNum - 0.5)));
}
if (powerOfTwo <= 51) { // is dNum + 0.5 representable?
- ASSERT_LT(BSON("" << lNum), BSON("" << (dNum + 0.5)));
- ASSERT_GT(BSON("" << -lNum), BSON("" << -(dNum + 0.5)));
+ ASSERT_BSONOBJ_LT(BSON("" << lNum), BSON("" << (dNum + 0.5)));
+ ASSERT_BSONOBJ_GT(BSON("" << -lNum), BSON("" << -(dNum + 0.5)));
}
}
@@ -162,13 +164,13 @@ TEST(BSONObjCompare, NumberLong_Double) {
const double closestAbove = 9223372036854775808.0; // 2**63
const double closestBelow = 9223372036854774784.0; // 2**63 - epsilon
- ASSERT_GT(BSON("" << maxLL), BSON("" << (maxLL - 1)));
- ASSERT_LT(BSON("" << maxLL), BSON("" << closestAbove));
- ASSERT_GT(BSON("" << maxLL), BSON("" << closestBelow));
+ ASSERT_BSONOBJ_GT(BSON("" << maxLL), BSON("" << (maxLL - 1)));
+ ASSERT_BSONOBJ_LT(BSON("" << maxLL), BSON("" << closestAbove));
+ ASSERT_BSONOBJ_GT(BSON("" << maxLL), BSON("" << closestBelow));
- ASSERT_LT(BSON("" << -maxLL), BSON("" << -(maxLL - 1)));
- ASSERT_GT(BSON("" << -maxLL), BSON("" << -closestAbove));
- ASSERT_LT(BSON("" << -maxLL), BSON("" << -closestBelow));
+ ASSERT_BSONOBJ_LT(BSON("" << -maxLL), BSON("" << -(maxLL - 1)));
+ ASSERT_BSONOBJ_GT(BSON("" << -maxLL), BSON("" << -closestAbove));
+ ASSERT_BSONOBJ_LT(BSON("" << -maxLL), BSON("" << -closestBelow));
}
{
@@ -182,122 +184,137 @@ TEST(BSONObjCompare, NumberLong_Double) {
invariant(static_cast<double>(minLL) == equal);
invariant(static_cast<long long>(equal) == minLL);
- ASSERT_LT(BSON("" << minLL), BSON("" << (minLL + 1)));
+ ASSERT_BSONOBJ_LT(BSON("" << minLL), BSON("" << (minLL + 1)));
- ASSERT_EQ(BSON("" << minLL), BSON("" << equal));
- ASSERT_LT(BSON("" << minLL), BSON("" << closestAbove));
- ASSERT_GT(BSON("" << minLL), BSON("" << closestBelow));
+ ASSERT_BSONOBJ_EQ(BSON("" << minLL), BSON("" << equal));
+ ASSERT_BSONOBJ_LT(BSON("" << minLL), BSON("" << closestAbove));
+ ASSERT_BSONOBJ_GT(BSON("" << minLL), BSON("" << closestBelow));
}
}
TEST(BSONObjCompare, NumberDecimalScaleAndZero) {
- ASSERT_LT(BSON("" << Decimal128(0.0)), BSON("" << Decimal128(1.0)));
- ASSERT_LT(BSON("" << Decimal128(-1.0)), BSON("" << Decimal128(0.0)));
- ASSERT_LT(BSON("" << Decimal128(-1.0)), BSON("" << Decimal128(1.0)));
-
- ASSERT_LT(BSON("" << Decimal128(0.0)), BSON("" << Decimal128(0.1)));
- ASSERT_LT(BSON("" << Decimal128(0.1)), BSON("" << Decimal128(1.0)));
- ASSERT_LT(BSON("" << Decimal128(-1.0)), BSON("" << Decimal128(-0.1)));
- ASSERT_LT(BSON("" << Decimal128(-0.1)), BSON("" << Decimal128(-0.0)));
- ASSERT_LT(BSON("" << Decimal128(-0.1)), BSON("" << Decimal128(0.1)));
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128(0.0)), BSON("" << Decimal128(1.0)));
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128(-1.0)), BSON("" << Decimal128(0.0)));
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128(-1.0)), BSON("" << Decimal128(1.0)));
+
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128(0.0)), BSON("" << Decimal128(0.1)));
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128(0.1)), BSON("" << Decimal128(1.0)));
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128(-1.0)), BSON("" << Decimal128(-0.1)));
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128(-0.1)), BSON("" << Decimal128(-0.0)));
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128(-0.1)), BSON("" << Decimal128(0.1)));
}
TEST(BSONObjCompare, NumberDecimalMaxAndMins) {
- ASSERT_LT(BSON("" << Decimal128(0.0)), BSON("" << Decimal128::kSmallestPositive));
- ASSERT_GT(BSON("" << Decimal128(0.0)), BSON("" << Decimal128::kLargestNegative));
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128(0.0)), BSON("" << Decimal128::kSmallestPositive));
+ ASSERT_BSONOBJ_GT(BSON("" << Decimal128(0.0)), BSON("" << Decimal128::kLargestNegative));
// over 34 digits of precision so it should be equal
- ASSERT_EQ(BSON("" << Decimal128(1.0)),
- BSON("" << Decimal128(1.0).add(Decimal128::kSmallestPositive)));
- ASSERT_EQ(BSON("" << Decimal128(0.0)), BSON("" << Decimal128(-0.0)));
-
- ASSERT_EQ(BSON("" << Decimal128(0)), BSON("" << Decimal128(0)));
- ASSERT_EQ(BSON("" << Decimal128::kSmallestPositive), BSON("" << Decimal128::kSmallestPositive));
- ASSERT_EQ(BSON("" << Decimal128::kLargestNegative), BSON("" << Decimal128::kLargestNegative));
+ ASSERT_BSONOBJ_EQ(BSON("" << Decimal128(1.0)),
+ BSON("" << Decimal128(1.0).add(Decimal128::kSmallestPositive)));
+ ASSERT_BSONOBJ_EQ(BSON("" << Decimal128(0.0)), BSON("" << Decimal128(-0.0)));
+
+ ASSERT_BSONOBJ_EQ(BSON("" << Decimal128(0)), BSON("" << Decimal128(0)));
+ ASSERT_BSONOBJ_EQ(BSON("" << Decimal128::kSmallestPositive),
+ BSON("" << Decimal128::kSmallestPositive));
+ ASSERT_BSONOBJ_EQ(BSON("" << Decimal128::kLargestNegative),
+ BSON("" << Decimal128::kLargestNegative));
}
TEST(BSONObjCompare, NumberDecimalInfinity) {
- ASSERT_GT(BSON("" << Decimal128::kPositiveInfinity), BSON("" << Decimal128(0.0)));
- ASSERT_GT(BSON("" << Decimal128::kPositiveInfinity), BSON("" << Decimal128::kLargestPositive));
- ASSERT_GT(BSON("" << Decimal128::kPositiveInfinity), BSON("" << Decimal128::kNegativeInfinity));
-
- ASSERT_EQ(BSON("" << Decimal128::kPositiveInfinity), BSON("" << Decimal128::kPositiveInfinity));
- ASSERT_EQ(BSON("" << Decimal128::kNegativeInfinity), BSON("" << Decimal128::kNegativeInfinity));
-
- ASSERT_LT(BSON("" << Decimal128::kNegativeInfinity), BSON("" << Decimal128(0.0)));
- ASSERT_LT(BSON("" << Decimal128::kNegativeInfinity), BSON("" << Decimal128::kSmallestNegative));
+ ASSERT_BSONOBJ_GT(BSON("" << Decimal128::kPositiveInfinity), BSON("" << Decimal128(0.0)));
+ ASSERT_BSONOBJ_GT(BSON("" << Decimal128::kPositiveInfinity),
+ BSON("" << Decimal128::kLargestPositive));
+ ASSERT_BSONOBJ_GT(BSON("" << Decimal128::kPositiveInfinity),
+ BSON("" << Decimal128::kNegativeInfinity));
+
+ ASSERT_BSONOBJ_EQ(BSON("" << Decimal128::kPositiveInfinity),
+ BSON("" << Decimal128::kPositiveInfinity));
+ ASSERT_BSONOBJ_EQ(BSON("" << Decimal128::kNegativeInfinity),
+ BSON("" << Decimal128::kNegativeInfinity));
+
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128::kNegativeInfinity), BSON("" << Decimal128(0.0)));
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128::kNegativeInfinity),
+ BSON("" << Decimal128::kSmallestNegative));
}
TEST(BSONObjCompare, NumberDecimalPosNaN) {
// +/-NaN is well ordered and compares smallest, so +NaN and -NaN should behave the same
- ASSERT_LT(BSON("" << Decimal128::kPositiveNaN), BSON("" << 0.0));
- ASSERT_LT(BSON("" << Decimal128::kPositiveNaN), BSON("" << Decimal128::kSmallestNegative));
- ASSERT_LT(BSON("" << Decimal128::kPositiveNaN), BSON("" << Decimal128::kPositiveInfinity));
- ASSERT_LT(BSON("" << Decimal128::kPositiveNaN), BSON("" << Decimal128::kNegativeInfinity));
-
- ASSERT_EQ(BSON("" << Decimal128::kPositiveNaN), BSON("" << Decimal128::kNegativeNaN));
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128::kPositiveNaN), BSON("" << 0.0));
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128::kPositiveNaN),
+ BSON("" << Decimal128::kSmallestNegative));
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128::kPositiveNaN),
+ BSON("" << Decimal128::kPositiveInfinity));
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128::kPositiveNaN),
+ BSON("" << Decimal128::kNegativeInfinity));
+
+ ASSERT_BSONOBJ_EQ(BSON("" << Decimal128::kPositiveNaN), BSON("" << Decimal128::kNegativeNaN));
}
TEST(BSONObjCompare, NumberDecimalNegNan) {
- ASSERT_LT(BSON("" << Decimal128::kNegativeNaN), BSON("" << 0.0));
- ASSERT_LT(BSON("" << Decimal128::kNegativeNaN), BSON("" << Decimal128::kSmallestNegative));
- ASSERT_LT(BSON("" << Decimal128::kNegativeNaN), BSON("" << Decimal128::kPositiveInfinity));
- ASSERT_LT(BSON("" << Decimal128::kNegativeNaN), BSON("" << Decimal128::kNegativeInfinity));
-
- ASSERT_EQ(BSON("" << Decimal128::kNegativeNaN), BSON("" << Decimal128::kPositiveNaN));
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128::kNegativeNaN), BSON("" << 0.0));
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128::kNegativeNaN),
+ BSON("" << Decimal128::kSmallestNegative));
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128::kNegativeNaN),
+ BSON("" << Decimal128::kPositiveInfinity));
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128::kNegativeNaN),
+ BSON("" << Decimal128::kNegativeInfinity));
+
+ ASSERT_BSONOBJ_EQ(BSON("" << Decimal128::kNegativeNaN), BSON("" << Decimal128::kPositiveNaN));
}
TEST(BSONObjCompare, NumberDecimalCompareInt) {
- ASSERT_EQ(BSON("" << Decimal128(0.0)), BSON("" << 0));
- ASSERT_EQ(BSON("" << Decimal128(502.0)), BSON("" << 502));
- ASSERT_EQ(BSON("" << Decimal128(std::numeric_limits<int>::max())),
- BSON("" << std::numeric_limits<int>::max()));
- ASSERT_EQ(BSON("" << Decimal128(-std::numeric_limits<int>::max())),
- BSON("" << -std::numeric_limits<int>::max()));
-
- ASSERT_LT(BSON("" << Decimal128::kNegativeNaN), BSON("" << -std::numeric_limits<int>::max()));
- ASSERT_LT(BSON("" << Decimal128::kPositiveNaN), BSON("" << -std::numeric_limits<int>::max()));
- ASSERT_LT(BSON("" << Decimal128::kNegativeInfinity),
- BSON("" << -std::numeric_limits<int>::max()));
- ASSERT_GT(BSON("" << Decimal128::kPositiveInfinity),
- BSON("" << std::numeric_limits<int>::max()));
-
- ASSERT_GT(BSON("" << Decimal128(1.0)), BSON("" << 0));
- ASSERT_LT(BSON("" << Decimal128(-1.0)), BSON("" << 0));
+ ASSERT_BSONOBJ_EQ(BSON("" << Decimal128(0.0)), BSON("" << 0));
+ ASSERT_BSONOBJ_EQ(BSON("" << Decimal128(502.0)), BSON("" << 502));
+ ASSERT_BSONOBJ_EQ(BSON("" << Decimal128(std::numeric_limits<int>::max())),
+ BSON("" << std::numeric_limits<int>::max()));
+ ASSERT_BSONOBJ_EQ(BSON("" << Decimal128(-std::numeric_limits<int>::max())),
+ BSON("" << -std::numeric_limits<int>::max()));
+
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128::kNegativeNaN),
+ BSON("" << -std::numeric_limits<int>::max()));
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128::kPositiveNaN),
+ BSON("" << -std::numeric_limits<int>::max()));
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128::kNegativeInfinity),
+ BSON("" << -std::numeric_limits<int>::max()));
+ ASSERT_BSONOBJ_GT(BSON("" << Decimal128::kPositiveInfinity),
+ BSON("" << std::numeric_limits<int>::max()));
+
+ ASSERT_BSONOBJ_GT(BSON("" << Decimal128(1.0)), BSON("" << 0));
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128(-1.0)), BSON("" << 0));
}
TEST(BSONObjCompare, NumberDecimalCompareLong) {
- ASSERT_EQ(BSON("" << Decimal128(0.0)), BSON("" << 0ll));
- ASSERT_EQ(BSON("" << Decimal128(502.0)), BSON("" << 502ll));
- ASSERT_EQ(BSON("" << Decimal128(std::numeric_limits<int64_t>::max())),
- BSON("" << std::numeric_limits<long long>::max()));
- ASSERT_EQ(BSON("" << Decimal128(-std::numeric_limits<int64_t>::max())),
- BSON("" << -std::numeric_limits<long long>::max()));
-
- ASSERT_LT(BSON("" << Decimal128::kNegativeNaN),
- BSON("" << -std::numeric_limits<long long>::max()));
- ASSERT_LT(BSON("" << Decimal128::kPositiveNaN),
- BSON("" << -std::numeric_limits<long long>::max()));
- ASSERT_LT(BSON("" << Decimal128::kNegativeInfinity),
- BSON("" << -std::numeric_limits<long long>::max()));
- ASSERT_GT(BSON("" << Decimal128::kPositiveInfinity),
- BSON("" << std::numeric_limits<long long>::max()));
-
- ASSERT_GT(BSON("" << Decimal128(1.0)), BSON("" << 0ll));
- ASSERT_LT(BSON("" << Decimal128(-1.0)), BSON("" << 0ll));
+ ASSERT_BSONOBJ_EQ(BSON("" << Decimal128(0.0)), BSON("" << 0ll));
+ ASSERT_BSONOBJ_EQ(BSON("" << Decimal128(502.0)), BSON("" << 502ll));
+ ASSERT_BSONOBJ_EQ(BSON("" << Decimal128(std::numeric_limits<int64_t>::max())),
+ BSON("" << std::numeric_limits<long long>::max()));
+ ASSERT_BSONOBJ_EQ(BSON("" << Decimal128(-std::numeric_limits<int64_t>::max())),
+ BSON("" << -std::numeric_limits<long long>::max()));
+
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128::kNegativeNaN),
+ BSON("" << -std::numeric_limits<long long>::max()));
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128::kPositiveNaN),
+ BSON("" << -std::numeric_limits<long long>::max()));
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128::kNegativeInfinity),
+ BSON("" << -std::numeric_limits<long long>::max()));
+ ASSERT_BSONOBJ_GT(BSON("" << Decimal128::kPositiveInfinity),
+ BSON("" << std::numeric_limits<long long>::max()));
+
+ ASSERT_BSONOBJ_GT(BSON("" << Decimal128(1.0)), BSON("" << 0ll));
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128(-1.0)), BSON("" << 0ll));
}
TEST(BSONObjCompare, NumberDecimalCompareDoubleExactRepresentations) {
- ASSERT_EQ(BSON("" << Decimal128(0.0)), BSON("" << 0.0));
- ASSERT_EQ(BSON("" << Decimal128(1.0)), BSON("" << 1.0));
- ASSERT_EQ(BSON("" << Decimal128(-1.0)), BSON("" << -1.0));
- ASSERT_EQ(BSON("" << Decimal128(0.125)), BSON("" << 0.125));
+ ASSERT_BSONOBJ_EQ(BSON("" << Decimal128(0.0)), BSON("" << 0.0));
+ ASSERT_BSONOBJ_EQ(BSON("" << Decimal128(1.0)), BSON("" << 1.0));
+ ASSERT_BSONOBJ_EQ(BSON("" << Decimal128(-1.0)), BSON("" << -1.0));
+ ASSERT_BSONOBJ_EQ(BSON("" << Decimal128(0.125)), BSON("" << 0.125));
- ASSERT_LT(BSON("" << Decimal128(0.0)), BSON("" << 0.125));
- ASSERT_LT(BSON("" << Decimal128(-1.0)), BSON("" << -0.125));
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128(0.0)), BSON("" << 0.125));
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128(-1.0)), BSON("" << -0.125));
- ASSERT_GT(BSON("" << Decimal128(1.0)), BSON("" << 0.125));
- ASSERT_GT(BSON("" << Decimal128(0.0)), BSON("" << -0.125));
+ ASSERT_BSONOBJ_GT(BSON("" << Decimal128(1.0)), BSON("" << 0.125));
+ ASSERT_BSONOBJ_GT(BSON("" << Decimal128(0.0)), BSON("" << -0.125));
}
TEST(BSONObjCompare, NumberDecimalCompareDoubleNoDoubleRepresentation) {
@@ -307,20 +324,21 @@ TEST(BSONObjCompare, NumberDecimalCompareDoubleNoDoubleRepresentation) {
// then compare equal to both double(0.10000000000000000555) and
// double(0.999999999999999876). The following test cases check that
// proper well ordering is applied to double and decimal comparisons.
- ASSERT_GT(BSON("" << Decimal128("0.3")), BSON("" << 0.1));
- ASSERT_LT(BSON("" << Decimal128("0.1")), BSON("" << 0.3));
- ASSERT_LT(BSON("" << Decimal128("-0.3")), BSON("" << -0.1));
- ASSERT_GT(BSON("" << Decimal128("-0.1")), BSON("" << -0.3));
- ASSERT_LT(BSON("" << Decimal128("0.1")), BSON("" << 0.1));
- ASSERT_GT(BSON("" << Decimal128("0.3")), BSON("" << 0.3));
- ASSERT_GT(BSON("" << Decimal128("-0.1")), BSON("" << -0.1));
- ASSERT_LT(BSON("" << Decimal128("-0.3")), BSON("" << -0.3));
- ASSERT_EQ(BSON("" << Decimal128("0.5")), BSON("" << 0.5));
- ASSERT_GT(BSON("" << Decimal128("0.5000000000000000000000000000000001")), BSON("" << 0.5));
+ ASSERT_BSONOBJ_GT(BSON("" << Decimal128("0.3")), BSON("" << 0.1));
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128("0.1")), BSON("" << 0.3));
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128("-0.3")), BSON("" << -0.1));
+ ASSERT_BSONOBJ_GT(BSON("" << Decimal128("-0.1")), BSON("" << -0.3));
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128("0.1")), BSON("" << 0.1));
+ ASSERT_BSONOBJ_GT(BSON("" << Decimal128("0.3")), BSON("" << 0.3));
+ ASSERT_BSONOBJ_GT(BSON("" << Decimal128("-0.1")), BSON("" << -0.1));
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128("-0.3")), BSON("" << -0.3));
+ ASSERT_BSONOBJ_EQ(BSON("" << Decimal128("0.5")), BSON("" << 0.5));
+ ASSERT_BSONOBJ_GT(BSON("" << Decimal128("0.5000000000000000000000000000000001")),
+ BSON("" << 0.5));
// Double 0.1 should compare well against significantly different decimals
- ASSERT_LT(BSON("" << Decimal128(0.0)), BSON("" << 0.1));
- ASSERT_GT(BSON("" << Decimal128(1.0)), BSON("" << 0.1));
+ ASSERT_BSONOBJ_LT(BSON("" << Decimal128(0.0)), BSON("" << 0.1));
+ ASSERT_BSONOBJ_GT(BSON("" << Decimal128(1.0)), BSON("" << 0.1));
}
TEST(BSONObjCompare, NumberDecimalCompareDoubleQuantize) {
@@ -332,29 +350,29 @@ TEST(BSONObjCompare, NumberDecimalCompareDoubleQuantize) {
Decimal128 roundedDoubleLargestNegValue("-179769313486232E294");
Decimal128 roundedDoubleOneAboveSmallestNegValue("-179769313486231E294");
- ASSERT_EQ(BSON("" << roundedDoubleLargestPosValue),
- BSON("" << Decimal128(std::numeric_limits<double>::max())));
- ASSERT_EQ(BSON("" << roundedDoubleLargestNegValue),
- BSON("" << Decimal128(-std::numeric_limits<double>::max())));
+ ASSERT_BSONOBJ_EQ(BSON("" << roundedDoubleLargestPosValue),
+ BSON("" << Decimal128(std::numeric_limits<double>::max())));
+ ASSERT_BSONOBJ_EQ(BSON("" << roundedDoubleLargestNegValue),
+ BSON("" << Decimal128(-std::numeric_limits<double>::max())));
- ASSERT_GT(BSON("" << roundedDoubleOneAboveLargestPosValue),
- BSON("" << Decimal128(std::numeric_limits<double>::max())));
- ASSERT_LT(BSON("" << roundedDoubleOneAboveSmallestNegValue),
- BSON("" << Decimal128(-std::numeric_limits<double>::min())));
+ ASSERT_BSONOBJ_GT(BSON("" << roundedDoubleOneAboveLargestPosValue),
+ BSON("" << Decimal128(std::numeric_limits<double>::max())));
+ ASSERT_BSONOBJ_LT(BSON("" << roundedDoubleOneAboveSmallestNegValue),
+ BSON("" << Decimal128(-std::numeric_limits<double>::min())));
}
TEST(BSONObjCompare, NumberDecimalCompareDoubleInfinity) {
- ASSERT_EQ(BSON("" << Decimal128::kPositiveInfinity),
- BSON("" << std::numeric_limits<double>::infinity()));
- ASSERT_EQ(BSON("" << Decimal128::kNegativeInfinity),
- BSON("" << -std::numeric_limits<double>::infinity()));
+ ASSERT_BSONOBJ_EQ(BSON("" << Decimal128::kPositiveInfinity),
+ BSON("" << std::numeric_limits<double>::infinity()));
+ ASSERT_BSONOBJ_EQ(BSON("" << Decimal128::kNegativeInfinity),
+ BSON("" << -std::numeric_limits<double>::infinity()));
}
TEST(BSONObjCompare, NumberDecimalCompareDoubleNaN) {
- ASSERT_EQ(BSON("" << Decimal128::kPositiveNaN),
- BSON("" << std::numeric_limits<double>::quiet_NaN()));
- ASSERT_EQ(BSON("" << Decimal128::kNegativeNaN),
- BSON("" << -std::numeric_limits<double>::quiet_NaN()));
+ ASSERT_BSONOBJ_EQ(BSON("" << Decimal128::kPositiveNaN),
+ BSON("" << std::numeric_limits<double>::quiet_NaN()));
+ ASSERT_BSONOBJ_EQ(BSON("" << Decimal128::kNegativeNaN),
+ BSON("" << -std::numeric_limits<double>::quiet_NaN()));
}
TEST(BSONObjCompare, StringSymbol) {
@@ -552,7 +570,7 @@ TEST(BSONObj, ShareOwnershipWith) {
// Now that tmp is out of scope, if obj didn't retain ownership, it would be accessing free'd
// memory which should error on ASAN and debug builds.
ASSERT(obj.isOwned());
- ASSERT_EQ(obj, BSON("a" << 1));
+ ASSERT_BSONOBJ_EQ(obj, BSON("a" << 1));
}
} // unnamed namespace
diff --git a/src/mongo/bson/bsonobj.h b/src/mongo/bson/bsonobj.h
index fa405e9f299..726a5f43be9 100644
--- a/src/mongo/bson/bsonobj.h
+++ b/src/mongo/bson/bsonobj.h
@@ -95,6 +95,31 @@ typedef std::multiset<BSONElement, BSONElementCmpWithoutField> BSONElementMSet;
*/
class BSONObj {
public:
+ // Declared in bsonobj_comparator_interface.h.
+ class ComparatorInterface;
+
+ /**
+ * Operator overloads for relops return a DeferredComparison which can subsequently be evaluated
+ * by a BSONObj::ComparatorInterface.
+ */
+ struct DeferredComparison {
+ enum class Type {
+ kLT,
+ kLTE,
+ kEQ,
+ kGT,
+ kGTE,
+ kNE,
+ };
+
+ DeferredComparison(Type type, const BSONObj& lhs, const BSONObj& rhs)
+ : type(type), lhs(lhs), rhs(rhs) {}
+
+ Type type;
+ const BSONObj& lhs;
+ const BSONObj& rhs;
+ };
+
static const char kMinBSONLength = 5;
/** Construct an empty BSONObj -- that is, {}. */
@@ -394,6 +419,15 @@ public:
/** Alternative output format */
std::string hexDump() const;
+ //
+ // Comparison API.
+ //
+ // BSONObj instances can be compared either using woCompare() or via operator overloads. Most
+ // callers should prefer operator overloads. Note that the operator overloads return a
+ // DeferredComparison, which must be subsequently evaluated by a BSONObj::ComparatorInterface.
+ // See bsonobj_comparator_interface.h for details.
+ //
+
/**wo='well ordered'. fields must be in same order in each object.
Ordering is with respect to the signs of the elements
and allows ascending / descending key mixing.
@@ -416,17 +450,28 @@ public:
bool considerFieldName = true,
const StringData::ComparatorInterface* comparator = nullptr) const;
- bool operator<(const BSONObj& other) const {
- return woCompare(other) < 0;
+ DeferredComparison operator<(const BSONObj& other) const {
+ return DeferredComparison(DeferredComparison::Type::kLT, *this, other);
+ }
+
+ DeferredComparison operator<=(const BSONObj& other) const {
+ return DeferredComparison(DeferredComparison::Type::kLTE, *this, other);
}
- bool operator<=(const BSONObj& other) const {
- return woCompare(other) <= 0;
+
+ DeferredComparison operator>(const BSONObj& other) const {
+ return DeferredComparison(DeferredComparison::Type::kGT, *this, other);
+ }
+
+ DeferredComparison operator>=(const BSONObj& other) const {
+ return DeferredComparison(DeferredComparison::Type::kGTE, *this, other);
}
- bool operator>(const BSONObj& other) const {
- return woCompare(other) > 0;
+
+ DeferredComparison operator==(const BSONObj& other) const {
+ return DeferredComparison(DeferredComparison::Type::kEQ, *this, other);
}
- bool operator>=(const BSONObj& other) const {
- return woCompare(other) >= 0;
+
+ DeferredComparison operator!=(const BSONObj& other) const {
+ return DeferredComparison(DeferredComparison::Type::kNE, *this, other);
}
bool equal(const BSONObj& r) const;
@@ -505,13 +550,6 @@ public:
/** true unless corrupt */
bool valid() const;
- bool operator==(const BSONObj& other) const {
- return equal(other);
- }
- bool operator!=(const BSONObj& other) const {
- return !operator==(other);
- }
-
enum MatchType {
Equality = 0,
LT = 0x1,
diff --git a/src/mongo/bson/bsonobj_comparator_interface.h b/src/mongo/bson/bsonobj_comparator_interface.h
new file mode 100644
index 00000000000..56fa736dab0
--- /dev/null
+++ b/src/mongo/bson/bsonobj_comparator_interface.h
@@ -0,0 +1,195 @@
+/**
+ * Copyright (C) 2016 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#pragma once
+
+#include <map>
+#include <set>
+#include <unordered_map>
+#include <unordered_set>
+
+#include "mongo/base/disallow_copying.h"
+#include "mongo/bson/bsonobj.h"
+#include "mongo/util/assert_util.h"
+
+namespace mongo {
+
+/**
+ * A BSONObj::ComparatorInterface is an abstract class for comparing BSONObj objects. Usage for
+ * comparing two BSON objects, 'lhs' and 'rhs', where 'comparator' is an instance of a class
+ * implementing this interface, is as shown below:
+ *
+ * bool lessThan = comparator.evaluate(lhs < rhs);
+ * bool lessThanOrEqual = comparator.evaluate(lhs <= rhs);
+ * bool equal = comparator.evaluate(lhs == rhs);
+ * bool greaterThanOrEqual = comparator.evaluate(lhs >= rhs);
+ * bool greaterThan = comparator.evaluate(lhs > rhs);
+ * bool notEqual = comparator.evaluate(lhs != rhs);
+ *
+ * Can also be used to obtain function objects compatible for use with standard library algorithms
+ * such as std::sort, and to construct STL sets and maps which respect this comparator.
+ *
+ * All methods are thread-safe.
+ */
+class BSONObj::ComparatorInterface {
+ MONGO_DISALLOW_COPYING(ComparatorInterface);
+
+public:
+ /**
+ * Functor compatible for use with ordered STL containers.
+ */
+ class LessThan {
+ public:
+ explicit LessThan(const ComparatorInterface* comparator) : _comparator(comparator) {}
+
+ bool operator()(const BSONObj& lhs, const BSONObj& rhs) const {
+ return _comparator->compare(lhs, rhs) < 0;
+ }
+
+ private:
+ const ComparatorInterface* _comparator;
+ };
+
+ /**
+ * Functor compatible for use with unordered STL containers.
+ */
+ class EqualTo {
+ public:
+ explicit EqualTo(const ComparatorInterface* comparator) : _comparator(comparator) {}
+
+ bool operator()(const BSONObj& lhs, const BSONObj& rhs) const {
+ return _comparator->compare(lhs, rhs) == 0;
+ }
+
+ private:
+ const ComparatorInterface* _comparator;
+ };
+
+ using BSONObjSet = std::set<BSONObj, BSONObj::ComparatorInterface::LessThan>;
+
+ // TODO SERVER-23990: Make the BSONObj hash collation-aware.
+ using BSONObjUnorderedSet =
+ std::unordered_set<BSONObj, BSONObj::Hasher, BSONObj::ComparatorInterface::EqualTo>;
+
+ template <typename T>
+ using BSONObjMap = std::map<BSONObj, T, BSONObj::ComparatorInterface::LessThan>;
+
+ // TODO SERVER-23990: Make the BSONObj hash collation-aware.
+ template <typename T>
+ using BSONObjIndexedMap =
+ std::unordered_map<BSONObj, T, BSONObj::Hasher, BSONObj::ComparatorInterface::EqualTo>;
+
+ virtual ~ComparatorInterface() = default;
+
+ /**
+ * Compares two BSONObj objects. Returns <0, 0, >0 if 'lhs' < 'rhs', 'lhs' == 'rhs', or 'lhs' >
+ * 'rhs' respectively.
+ */
+ virtual int compare(const BSONObj& lhs, const BSONObj& rhs) const = 0;
+
+ /**
+ * Evaluates a deferred comparison object generated by invocation of one of the BSONObj operator
+ * overloads for relops.
+ */
+ bool evaluate(BSONObj::DeferredComparison deferredComparison) const {
+ int cmp = compare(deferredComparison.lhs, deferredComparison.rhs);
+ switch (deferredComparison.type) {
+ case BSONObj::DeferredComparison::Type::kLT:
+ return cmp < 0;
+ case BSONObj::DeferredComparison::Type::kLTE:
+ return cmp <= 0;
+ case BSONObj::DeferredComparison::Type::kEQ:
+ return cmp == 0;
+ case BSONObj::DeferredComparison::Type::kGT:
+ return cmp > 0;
+ case BSONObj::DeferredComparison::Type::kGTE:
+ return cmp >= 0;
+ case BSONObj::DeferredComparison::Type::kNE:
+ return cmp != 0;
+ }
+
+ MONGO_UNREACHABLE;
+ }
+
+ /**
+ * Returns a function object which computes whether one BSONObj is less than another under this
+ * comparator. This comparator must outlive the returned function object.
+ */
+ LessThan makeLessThan() const {
+ return LessThan(this);
+ }
+
+ /**
+ * Returns a function object which computes whether one BSONObj is equal to another under this
+ * comparator. This comparator must outlive the returned function object.
+ */
+ EqualTo makeEqualTo() const {
+ return EqualTo(this);
+ }
+
+ /**
+ * Construct an empty BSONObjSet whose ordering is given by this comparator. This comparator
+ * must outlive the returned set.
+ */
+ BSONObjSet makeOrderedBSONObjSet() const {
+ return BSONObjSet(LessThan(this));
+ }
+
+ /**
+ * Construct an empty BSONObjUnorderedSet whose equivalence classes are given by this
+ * comparator. This comparator must outlive the returned set.
+ */
+ BSONObjUnorderedSet makeUnorderedBSONObjSet() const {
+ // TODO SERVER-23990: Make the BSONObj hash collation-aware.
+ return BSONObjUnorderedSet(0, BSONObj::Hasher(), EqualTo(this));
+ }
+
+ /**
+ * Construct an empty ordered map from BSONObj to type T whose ordering is given by this
+ * comparator. This comparator must outlive the returned map.
+ */
+ template <typename T>
+ BSONObjMap<T> makeOrderedBSONObjMap() const {
+ return BSONObjMap<T>(LessThan(this));
+ }
+
+ /**
+ * Construct an empty unordered map from BSONObj to type T whose ordering is given by this
+ * comparator. This comparator must outlive the returned map.
+ */
+ template <typename T>
+ BSONObjIndexedMap<T> makeBSONObjIndexedMap() const {
+ // TODO SERVER-23990: Make the BSONObj hash collation-aware.
+ return BSONObjIndexedMap<T>(0, BSONObj::Hasher(), EqualTo(this));
+ }
+
+protected:
+ constexpr ComparatorInterface() = default;
+};
+
+} // namespace mongo
diff --git a/src/mongo/bson/bsonobjbuilder_test.cpp b/src/mongo/bson/bsonobjbuilder_test.cpp
index 4f11df260bb..003f40c27dd 100644
--- a/src/mongo/bson/bsonobjbuilder_test.cpp
+++ b/src/mongo/bson/bsonobjbuilder_test.cpp
@@ -259,7 +259,7 @@ TEST(BSONObjBuilderTest, AppendNumberLongLongMinCompareObject) {
BSONObj o2 = BSON("a" << std::numeric_limits<long long>::min());
- ASSERT_EQUALS(o1, o2);
+ ASSERT_BSONOBJ_EQ(o1, o2);
}
TEST(BSONObjBuilderTest, AppendMaxTimestampConversion) {
@@ -285,11 +285,11 @@ TEST(BSONObjBuilderTest, ResumeBuilding) {
secondBuilder.append("c", "d");
}
auto obj = BSONObj(b.buf());
- ASSERT_EQ(obj,
- BSON("a"
- << "b"
- << "c"
- << "d"));
+ ASSERT_BSONOBJ_EQ(obj,
+ BSON("a"
+ << "b"
+ << "c"
+ << "d"));
}
TEST(BSONObjBuilderTest, ResumeBuildingWithNesting) {
@@ -307,18 +307,18 @@ TEST(BSONObjBuilderTest, ResumeBuildingWithNesting) {
secondBuilder.append("a", BSON("c" << 3));
}
auto obj = BSONObj(b.buf());
- ASSERT_EQ(obj,
- BSON("ll" << BSON("f" << BSON("cc"
- << "dd"))
- << "a"
- << BSON("c" << 3)));
+ ASSERT_BSONOBJ_EQ(obj,
+ BSON("ll" << BSON("f" << BSON("cc"
+ << "dd"))
+ << "a"
+ << BSON("c" << 3)));
}
TEST(BSONObjBuilderTest, ResetToEmptyResultsInEmptyObj) {
BSONObjBuilder bob;
bob.append("a", 3);
bob.resetToEmpty();
- ASSERT_EQ(BSONObj(), bob.obj());
+ ASSERT_BSONOBJ_EQ(BSONObj(), bob.obj());
}
TEST(BSONObjBuilderTest, ResetToEmptyForNestedBuilderOnlyResetsInnerObj) {
@@ -328,7 +328,7 @@ TEST(BSONObjBuilderTest, ResetToEmptyForNestedBuilderOnlyResetsInnerObj) {
innerObj.append("b", 4);
innerObj.resetToEmpty();
innerObj.done();
- ASSERT_EQ(BSON("a" << 3 << "nestedObj" << BSONObj()), bob.obj());
+ ASSERT_BSONOBJ_EQ(BSON("a" << 3 << "nestedObj" << BSONObj()), bob.obj());
}
} // unnamed namespace
diff --git a/src/mongo/bson/mutable/mutable_bson_test.cpp b/src/mongo/bson/mutable/mutable_bson_test.cpp
index 24629617926..d1584ff9714 100644
--- a/src/mongo/bson/mutable/mutable_bson_test.cpp
+++ b/src/mongo/bson/mutable/mutable_bson_test.cpp
@@ -807,13 +807,13 @@ TEST(Serialization, RoundTrip) {
obj = mongo::fromjson(jsonSampleWithDecimal);
mmb::Document doc(obj.copy());
mongo::BSONObj built = doc.getObject();
- ASSERT_EQUALS(obj, built);
+ ASSERT_BSONOBJ_EQ(obj, built);
}
TEST(Documentation, Example1) {
// Create a new document
mmb::Document doc;
- ASSERT_EQUALS(mongo::fromjson("{}"), doc.getObject());
+ ASSERT_BSONOBJ_EQ(mongo::fromjson("{}"), doc.getObject());
// Get the root of the document.
mmb::Element root = doc.root();
@@ -822,41 +822,41 @@ TEST(Documentation, Example1) {
// everything, then push that Element into the root object, making it a child of root.
mmb::Element e0 = doc.makeElementInt("ltuae", 42);
ASSERT_OK(root.pushBack(e0));
- ASSERT_EQUALS(mongo::fromjson("{ ltuae : 42 }"), doc.getObject());
+ ASSERT_BSONOBJ_EQ(mongo::fromjson("{ ltuae : 42 }"), doc.getObject());
// Create a new empty mongo::Object-typed Element named 'magic', and push it back as a
// child of the root, making it a sibling of e0.
mmb::Element e1 = doc.makeElementObject("magic");
ASSERT_OK(root.pushBack(e1));
- ASSERT_EQUALS(mongo::fromjson("{ ltuae : 42, magic : {} }"), doc.getObject());
+ ASSERT_BSONOBJ_EQ(mongo::fromjson("{ ltuae : 42, magic : {} }"), doc.getObject());
// Create a new mongo::NumberDouble typed Element to represent Pi, and insert it as child
// of the new object we just created.
mmb::Element e3 = doc.makeElementDouble("pi", 3.14);
ASSERT_OK(e1.pushBack(e3));
- ASSERT_EQUALS(mongo::fromjson("{ ltuae : 42, magic : { pi : 3.14 } }"), doc.getObject());
+ ASSERT_BSONOBJ_EQ(mongo::fromjson("{ ltuae : 42, magic : { pi : 3.14 } }"), doc.getObject());
// Create a new mongo::NumberDouble to represent Plancks constant in electrovolt
// micrometers, and add it as a child of the 'magic' object.
mmb::Element e4 = doc.makeElementDouble("hbar", 1.239);
ASSERT_OK(e1.pushBack(e4));
- ASSERT_EQUALS(mongo::fromjson("{ ltuae : 42, magic : { pi : 3.14, hbar : 1.239 } }"),
- doc.getObject());
+ ASSERT_BSONOBJ_EQ(mongo::fromjson("{ ltuae : 42, magic : { pi : 3.14, hbar : 1.239 } }"),
+ doc.getObject());
// Rename the parent element of 'hbar' to be 'constants'.
ASSERT_OK(e4.parent().rename("constants"));
- ASSERT_EQUALS(mongo::fromjson("{ ltuae : 42, constants : { pi : 3.14, hbar : 1.239 } }"),
- doc.getObject());
+ ASSERT_BSONOBJ_EQ(mongo::fromjson("{ ltuae : 42, constants : { pi : 3.14, hbar : 1.239 } }"),
+ doc.getObject());
// Rename 'ltuae' to 'answer' by accessing it as the root objects left child.
ASSERT_OK(doc.root().leftChild().rename("answer"));
- ASSERT_EQUALS(mongo::fromjson("{ answer : 42, constants : { pi : 3.14, hbar : 1.239 } }"),
- doc.getObject());
+ ASSERT_BSONOBJ_EQ(mongo::fromjson("{ answer : 42, constants : { pi : 3.14, hbar : 1.239 } }"),
+ doc.getObject());
// Sort the constants by name.
mmb::sortChildren(doc.root().rightChild(), mmb::FieldNameLessThan());
- ASSERT_EQUALS(mongo::fromjson("{ answer : 42, constants : { hbar : 1.239, pi : 3.14 } }"),
- doc.getObject());
+ ASSERT_BSONOBJ_EQ(mongo::fromjson("{ answer : 42, constants : { hbar : 1.239, pi : 3.14 } }"),
+ doc.getObject());
}
TEST(Documentation, Example2) {
@@ -919,7 +919,7 @@ TEST(Documentation, Example2) {
mongo::BSONObjBuilder builder;
doc.writeTo(&builder);
- ASSERT_EQUALS(mongo::fromjson(outJson), doc.getObject());
+ ASSERT_BSONOBJ_EQ(mongo::fromjson(outJson), doc.getObject());
}
namespace {
@@ -943,7 +943,7 @@ TEST(Documentation, Example2InPlaceWithDamageVector) {
// Make the object, and make a copy for reference.
mongo::BSONObj obj = mongo::fromjson(inJson);
const mongo::BSONObj copyOfObj = obj.getOwned();
- ASSERT_EQUALS(obj, copyOfObj);
+ ASSERT_BSONOBJ_EQ(obj, copyOfObj);
// Create a new document representing BSONObj with the above contents.
mmb::Document doc(obj, mmb::Document::kInPlaceEnabled);
@@ -984,7 +984,7 @@ TEST(Documentation, Example2InPlaceWithDamageVector) {
// Demonstrate that while the document has changed, the underlying BSONObj has not yet
// changed.
ASSERT_FALSE(obj == doc);
- ASSERT_EQUALS(copyOfObj, obj);
+ ASSERT_BSONOBJ_EQ(copyOfObj, obj);
// Ensure that in-place updates are still enabled.
ASSERT_EQUALS(mmb::Document::kInPlaceEnabled, doc.getCurrentInPlaceMode());
@@ -1011,7 +1011,7 @@ TEST(Documentation, Example2InPlaceWithDamageVector) {
mongo::BSONObjBuilder builder;
doc.writeTo(&builder);
- ASSERT_EQUALS(mongo::fromjson(outJson), doc.getObject());
+ ASSERT_BSONOBJ_EQ(mongo::fromjson(outJson), doc.getObject());
}
TEST(Documentation, Example3) {
@@ -1041,7 +1041,7 @@ TEST(Documentation, Example3) {
" 'xs': { 'x' : 'x', 'X' : 'X' },"
" 'ys': { 'y' : 'y', 'Y' : 'Y', 'why' : ['not'] }"
"}";
- ASSERT_EQUALS(mongo::fromjson(outJson), outObj);
+ ASSERT_BSONOBJ_EQ(mongo::fromjson(outJson), outObj);
}
TEST(Document, LifecycleConstructDefault) {
@@ -1159,7 +1159,7 @@ TEST(Document, RenameDeserialization) {
"{"
" 'a' : { 'b' : { 'C' : { 'd' : 4 } } }"
"}";
- ASSERT_EQUALS(mongo::fromjson(outJson), outObj);
+ ASSERT_BSONOBJ_EQ(mongo::fromjson(outJson), outObj);
}
TEST(Document, CantRenameRootElement) {
@@ -1189,7 +1189,7 @@ TEST(Document, RemoveElementWithOpaqueRightSibling) {
" 'b' : 2, 'c' : 3"
"}";
mongo::BSONObj outObj = doc.getObject();
- ASSERT_EQUALS(mongo::fromjson(outJson), outObj);
+ ASSERT_BSONOBJ_EQ(mongo::fromjson(outJson), outObj);
}
TEST(Document, AddRightSiblingToElementWithOpaqueRightSibling) {
@@ -1214,7 +1214,7 @@ TEST(Document, AddRightSiblingToElementWithOpaqueRightSibling) {
" 'a' : 1, 'X' : 'X', 'b' : 2, 'c' : 3"
"}";
mongo::BSONObj outObj = doc.getObject();
- ASSERT_EQUALS(mongo::fromjson(outJson), outObj);
+ ASSERT_BSONOBJ_EQ(mongo::fromjson(outJson), outObj);
}
TEST(Document, ArrayIndexedAccessFromJson) {
@@ -1422,7 +1422,7 @@ TEST(Document, ArraySerialization) {
"}";
const mongo::BSONObj outObj = doc.getObject();
- ASSERT_EQUALS(mongo::fromjson(outJson), outObj);
+ ASSERT_BSONOBJ_EQ(mongo::fromjson(outJson), outObj);
}
TEST(Document, SetValueBSONElementFieldNameHandling) {
@@ -1441,7 +1441,7 @@ TEST(Document, SetValueBSONElementFieldNameHandling) {
a.setValueBSONElement(b);
static const char outJson[] = "{ a : 5 }";
- ASSERT_EQUALS(mongo::fromjson(outJson), doc.getObject());
+ ASSERT_BSONOBJ_EQ(mongo::fromjson(outJson), doc.getObject());
}
TEST(Document, SetValueElementFromSeparateDocument) {
@@ -1455,10 +1455,10 @@ TEST(Document, SetValueElementFromSeparateDocument) {
auto setFrom = doc2.root().leftChild();
ASSERT_OK(setTo.setValueElement(setFrom));
- ASSERT_EQ(mongo::fromjson("{ a : 5 }"), doc1.getObject());
+ ASSERT_BSONOBJ_EQ(mongo::fromjson("{ a : 5 }"), doc1.getObject());
// Doc containing the 'setFrom' element should be unchanged.
- ASSERT_EQ(inObj2, doc2.getObject());
+ ASSERT_BSONOBJ_EQ(inObj2, doc2.getObject());
}
TEST(Document, SetValueElementIsNoopWhenSetToSelf) {
@@ -1468,7 +1468,7 @@ TEST(Document, SetValueElementIsNoopWhenSetToSelf) {
auto element = doc.root().leftChild();
ASSERT_OK(element.setValueElement(element));
- ASSERT_EQ(inObj, doc.getObject());
+ ASSERT_BSONOBJ_EQ(inObj, doc.getObject());
}
TEST(Document, SetValueElementIsNoopWhenSetToSelfFromCopy) {
@@ -1479,7 +1479,7 @@ TEST(Document, SetValueElementIsNoopWhenSetToSelfFromCopy) {
auto elementCopy = element;
ASSERT_OK(element.setValueElement(elementCopy));
- ASSERT_EQ(inObj, doc.getObject());
+ ASSERT_BSONOBJ_EQ(inObj, doc.getObject());
}
TEST(Document, SetValueElementIsNoopWhenSetToSelfNonRootElement) {
@@ -1490,7 +1490,7 @@ TEST(Document, SetValueElementIsNoopWhenSetToSelfNonRootElement) {
ASSERT_EQ("c", element.getFieldName());
ASSERT_OK(element.setValueElement(element));
- ASSERT_EQ(inObj, doc.getObject());
+ ASSERT_BSONOBJ_EQ(inObj, doc.getObject());
}
TEST(Document, SetValueElementSetToNestedObject) {
@@ -1504,10 +1504,10 @@ TEST(Document, SetValueElementSetToNestedObject) {
auto setFrom = doc2.root().leftChild();
ASSERT_OK(setTo.setValueElement(setFrom));
- ASSERT_EQ(mongo::fromjson("{ a : { c : 5, d : 6 } }"), doc1.getObject());
+ ASSERT_BSONOBJ_EQ(mongo::fromjson("{ a : { c : 5, d : 6 } }"), doc1.getObject());
// Doc containing the 'setFrom' element should be unchanged.
- ASSERT_EQ(inObj2, doc2.getObject());
+ ASSERT_BSONOBJ_EQ(inObj2, doc2.getObject());
}
TEST(Document, SetValueElementNonRootElements) {
@@ -1523,10 +1523,10 @@ TEST(Document, SetValueElementNonRootElements) {
ASSERT_EQ("e", setFrom.getFieldName());
ASSERT_OK(setTo.setValueElement(setFrom));
- ASSERT_EQ(mongo::fromjson("{ a : { b : 5, c : 8 } }"), doc1.getObject());
+ ASSERT_BSONOBJ_EQ(mongo::fromjson("{ a : { b : 5, c : 8 } }"), doc1.getObject());
// Doc containing the 'setFrom' element should be unchanged.
- ASSERT_EQ(inObj2, doc2.getObject());
+ ASSERT_BSONOBJ_EQ(inObj2, doc2.getObject());
}
TEST(Document, SetValueElementSetRootToSelfErrors) {
@@ -1535,7 +1535,7 @@ TEST(Document, SetValueElementSetRootToSelfErrors) {
auto element = doc.root();
ASSERT_NOT_OK(element.setValueElement(element));
- ASSERT_EQ(inObj, doc.getObject());
+ ASSERT_BSONOBJ_EQ(inObj, doc.getObject());
}
TEST(Document, SetValueElementSetRootToAnotherDocRootErrors) {
@@ -1549,8 +1549,8 @@ TEST(Document, SetValueElementSetRootToAnotherDocRootErrors) {
auto setFrom = doc2.root();
ASSERT_NOT_OK(setTo.setValueElement(setFrom));
- ASSERT_EQ(inObj, doc1.getObject());
- ASSERT_EQ(inObj2, doc2.getObject());
+ ASSERT_BSONOBJ_EQ(inObj, doc1.getObject());
+ ASSERT_BSONOBJ_EQ(inObj2, doc2.getObject());
}
TEST(Document, SetValueElementSetRootToNotRootInSelfErrors) {
@@ -1560,7 +1560,7 @@ TEST(Document, SetValueElementSetRootToNotRootInSelfErrors) {
auto setTo = doc.root();
auto setFrom = doc.root().leftChild();
ASSERT_NOT_OK(setTo.setValueElement(setFrom));
- ASSERT_EQ(inObj, doc.getObject());
+ ASSERT_BSONOBJ_EQ(inObj, doc.getObject());
}
TEST(Document, SetValueElementSetRootToNotRootInAnotherDocErrors) {
@@ -1574,8 +1574,8 @@ TEST(Document, SetValueElementSetRootToNotRootInAnotherDocErrors) {
auto setFrom = doc2.root().leftChild();
ASSERT_NOT_OK(setTo.setValueElement(setFrom));
- ASSERT_EQ(inObj, doc1.getObject());
- ASSERT_EQ(inObj2, doc2.getObject());
+ ASSERT_BSONOBJ_EQ(inObj, doc1.getObject());
+ ASSERT_BSONOBJ_EQ(inObj2, doc2.getObject());
}
TEST(Document, SetValueElementSetToOwnRootErrors) {
@@ -1587,7 +1587,7 @@ TEST(Document, SetValueElementSetToOwnRootErrors) {
auto setFrom = doc.root();
ASSERT_NOT_OK(setTo.setValueElement(setFrom));
- ASSERT_EQ(inObj, doc.getObject());
+ ASSERT_BSONOBJ_EQ(inObj, doc.getObject());
}
TEST(Document, SetValueElementSetToOtherDocRoot) {
@@ -1602,8 +1602,8 @@ TEST(Document, SetValueElementSetToOtherDocRoot) {
auto setFrom = doc2.root();
ASSERT_OK(setTo.setValueElement(setFrom));
- ASSERT_EQ(mongo::fromjson("{ a : { b : { c : 5 } } }"), doc1.getObject());
- ASSERT_EQ(inObj2, doc2.getObject());
+ ASSERT_BSONOBJ_EQ(mongo::fromjson("{ a : { b : { c : 5 } } }"), doc1.getObject());
+ ASSERT_BSONOBJ_EQ(inObj2, doc2.getObject());
}
TEST(Document, CreateElementWithEmptyFieldName) {
@@ -1921,7 +1921,7 @@ TEST(TypeSupport, EncodingEquivalenceObject) {
ASSERT_TRUE(a.ok());
ASSERT_EQUALS(a.getType(), mongo::Object);
ASSERT_TRUE(a.hasValue());
- ASSERT_EQUALS(value1, mmb::ConstElement(a).getValueObject());
+ ASSERT_BSONOBJ_EQ(value1, mmb::ConstElement(a).getValueObject());
// Construct via call passing BSON element
ASSERT_OK(doc.root().appendElement(thing));
@@ -1962,7 +1962,7 @@ TEST(TypeSupport, EncodingEquivalenceArray) {
ASSERT_TRUE(a.ok());
ASSERT_EQUALS(a.getType(), mongo::Array);
ASSERT_TRUE(a.hasValue());
- ASSERT_EQUALS(value1, mmb::ConstElement(a).getValueArray());
+ ASSERT_BSONOBJ_EQ(value1, mmb::ConstElement(a).getValueArray());
// Construct via call passing BSON element
ASSERT_OK(doc.root().appendElement(thing));
@@ -2714,7 +2714,7 @@ TEST(Document, ManipulateComplexObjInLeafHeap) {
static const char outJson[] =
"{ embedded: { a: 1, b: 2, c: 2.0, d : ['w', 'y', 'z'] }, free: {} }";
- ASSERT_EQUALS(mongo::fromjson(outJson), doc.getObject());
+ ASSERT_BSONOBJ_EQ(mongo::fromjson(outJson), doc.getObject());
}
TEST(DocumentInPlace, EphemeralDocumentsDoNotUseInPlaceMode) {
@@ -2889,7 +2889,7 @@ TEST(DocumentInPlace, DisablingInPlaceDoesNotDiscardUpdates) {
ASSERT_FALSE(doc.isInPlaceModeEnabled());
static const char outJson[] = "{ foo : true, bar : false, baz : 'baz' }";
- ASSERT_EQUALS(mongo::fromjson(outJson), doc.getObject());
+ ASSERT_BSONOBJ_EQ(mongo::fromjson(outJson), doc.getObject());
}
TEST(DocumentInPlace, StringLifecycle) {
diff --git a/src/mongo/bson/simple_bsonobj_comparator.cpp b/src/mongo/bson/simple_bsonobj_comparator.cpp
new file mode 100644
index 00000000000..38b04e70034
--- /dev/null
+++ b/src/mongo/bson/simple_bsonobj_comparator.cpp
@@ -0,0 +1,38 @@
+/**
+ * Copyright (C) 2016 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/bson/simple_bsonobj_comparator.h"
+
+namespace mongo {
+
+const SimpleBSONObjComparator SimpleBSONObjComparator::kInstance{};
+
+} // namespace mongo
diff --git a/src/mongo/bson/simple_bsonobj_comparator.h b/src/mongo/bson/simple_bsonobj_comparator.h
new file mode 100644
index 00000000000..76d4070f059
--- /dev/null
+++ b/src/mongo/bson/simple_bsonobj_comparator.h
@@ -0,0 +1,49 @@
+/**
+ * Copyright (C) 2016 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#pragma once
+
+#include "mongo/bson/bsonobj_comparator_interface.h"
+
+namespace mongo {
+
+/**
+ * A BSONObj comparator that has simple binary compare semantics.
+ */
+class SimpleBSONObjComparator final : public BSONObj::ComparatorInterface {
+public:
+ // Global simple comparator for stateless BSONObj comparisons. BSONObj comparisons that require
+ // database logic, such as collations, much instantiate their own comparator.
+ static const SimpleBSONObjComparator kInstance;
+
+ int compare(const BSONObj& lhs, const BSONObj& rhs) const final {
+ return lhs.woCompare(rhs, BSONObj(), true, nullptr);
+ }
+};
+
+} // namespace mongo