Add equal-to and non-equal-to operators
This commit is contained in:
parent
0f7d2dad51
commit
71c8402549
@ -556,6 +556,71 @@ public:
|
|||||||
GenericValue& Move() { return *this; }
|
GenericValue& Move() { return *this; }
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
//!@name Equal-to and not-equal-to operators
|
||||||
|
//@{
|
||||||
|
//! Equal-to operator
|
||||||
|
bool operator==(const GenericValue& rhs) const {
|
||||||
|
if (GetType() != rhs.GetType())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch (GetType()) {
|
||||||
|
case kObjectType: // Warning: O(n^2) inner-loop
|
||||||
|
if (data_.o.size != rhs.data_.o.size)
|
||||||
|
return false;
|
||||||
|
for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) {
|
||||||
|
ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name);
|
||||||
|
if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
|
||||||
|
case kArrayType:
|
||||||
|
if (data_.a.size != rhs.data_.a.size)
|
||||||
|
return false;
|
||||||
|
for (size_t i = 0; i < data_.a.size; i++)
|
||||||
|
if ((*this)[i] != rhs[i])
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case kStringType:
|
||||||
|
return StringEqual(rhs);
|
||||||
|
|
||||||
|
case kNumberType:
|
||||||
|
if (IsDouble() || rhs.GetDouble())
|
||||||
|
return GetDouble() == rhs.GetDouble(); // May convert one operand from integer to double.
|
||||||
|
else
|
||||||
|
return data_.n.u64 == rhs.data_.n.u64;
|
||||||
|
|
||||||
|
default: // kTrueType, kFalseType, kNullType
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Not-equal-to operator
|
||||||
|
bool operator!=(const GenericValue& rhs) const { return !(*this == rhs); }
|
||||||
|
|
||||||
|
//! (Not-)Equal-to operator with const C-string pointer.
|
||||||
|
friend bool operator==(const GenericValue& lhs, const Ch* rhs) { return lhs == GenericValue(StringRef(rhs)); }
|
||||||
|
friend bool operator!=(const GenericValue& lhs, const Ch* rhs) { return !(lhs == rhs); }
|
||||||
|
friend bool operator==(const Ch* lhs, const GenericValue& rhs) { return GenericValue(StringRef(lhs)) == rhs; }
|
||||||
|
friend bool operator!=(const Ch* lhs, const GenericValue& rhs) { return !(lhs == rhs); }
|
||||||
|
|
||||||
|
//! (Not-)Equal-to operator with non-const C-string pointer.
|
||||||
|
friend bool operator==(const GenericValue& lhs, Ch* rhs) { return lhs == GenericValue(StringRef(rhs)); }
|
||||||
|
friend bool operator!=(const GenericValue& lhs, Ch* rhs) { return !(lhs == rhs); }
|
||||||
|
friend bool operator==(Ch* lhs, const GenericValue& rhs) { return GenericValue(StringRef(lhs)) == rhs; }
|
||||||
|
friend bool operator!=(Ch* lhs, const GenericValue& rhs) { return !(lhs == rhs); }
|
||||||
|
|
||||||
|
//! (Not-)Equal-to operator with primitive types.
|
||||||
|
/*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c true, \c false
|
||||||
|
*/
|
||||||
|
template <typename T> friend bool operator==(const GenericValue& lhs, const T& rhs) { return lhs == GenericValue(rhs); }
|
||||||
|
template <typename T> friend bool operator!=(const GenericValue& lhs, const T& rhs) { return !(lhs == rhs); }
|
||||||
|
template <typename T> friend bool operator==(const T& lhs, const GenericValue& rhs) { return GenericValue(lhs) == rhs; }
|
||||||
|
template <typename T> friend bool operator!=(const T& lhs, const GenericValue& rhs) { return !(lhs == rhs); }
|
||||||
|
//@}
|
||||||
|
|
||||||
//!@name Type
|
//!@name Type
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
@ -672,10 +737,9 @@ public:
|
|||||||
MemberIterator FindMember(const GenericValue& name) {
|
MemberIterator FindMember(const GenericValue& name) {
|
||||||
RAPIDJSON_ASSERT(IsObject());
|
RAPIDJSON_ASSERT(IsObject());
|
||||||
RAPIDJSON_ASSERT(name.IsString());
|
RAPIDJSON_ASSERT(name.IsString());
|
||||||
SizeType len = name.data_.s.length;
|
|
||||||
MemberIterator member = MemberBegin();
|
MemberIterator member = MemberBegin();
|
||||||
for ( ; member != MemberEnd(); ++member)
|
for ( ; member != MemberEnd(); ++member)
|
||||||
if (member->name.data_.s.length == len && memcmp(member->name.data_.s.str, name.data_.s.str, len * sizeof(Ch)) == 0)
|
if (name.StringEqual(member->name))
|
||||||
break;
|
break;
|
||||||
return member;
|
return member;
|
||||||
}
|
}
|
||||||
@ -1214,6 +1278,13 @@ private:
|
|||||||
rhs.flags_ = kNullFlag;
|
rhs.flags_ = kNullFlag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool StringEqual(const GenericValue& rhs) const {
|
||||||
|
RAPIDJSON_ASSERT(IsString());
|
||||||
|
RAPIDJSON_ASSERT(rhs.IsString());
|
||||||
|
return data_.s.str == rhs.data_.s.str || // fast path for constant string
|
||||||
|
((data_.s.length == rhs.data_.s.length) && memcmp(data_.s.str, rhs.data_.s.str, sizeof(Ch) * data_.s.length) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
Data data_;
|
Data data_;
|
||||||
unsigned flags_;
|
unsigned flags_;
|
||||||
};
|
};
|
||||||
|
@ -44,6 +44,58 @@ TEST(Value, assignment_operator) {
|
|||||||
EXPECT_EQ(y.GetString(),mstr);
|
EXPECT_EQ(y.GetString(),mstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename A, typename B>
|
||||||
|
void TestEqual(const A& a, const B& b) {
|
||||||
|
EXPECT_TRUE (a == b);
|
||||||
|
EXPECT_FALSE(a != b);
|
||||||
|
EXPECT_TRUE (b == a);
|
||||||
|
EXPECT_FALSE(b != a);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A, typename B>
|
||||||
|
void TestUnequal(const A& a, const B& b) {
|
||||||
|
EXPECT_FALSE(a == b);
|
||||||
|
EXPECT_TRUE (a != b);
|
||||||
|
EXPECT_FALSE(b == a);
|
||||||
|
EXPECT_TRUE (b != a);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Value, equalto_operator) {
|
||||||
|
Value::AllocatorType allocator;
|
||||||
|
Value x(kObjectType);
|
||||||
|
x.AddMember("hello", "world", allocator)
|
||||||
|
.AddMember("t", Value(true).Move(), allocator)
|
||||||
|
.AddMember("f", Value(false).Move(), allocator)
|
||||||
|
.AddMember("n", Value(kNullType).Move(), allocator)
|
||||||
|
.AddMember("i", 123, allocator)
|
||||||
|
.AddMember("pi", 3.14, allocator)
|
||||||
|
.AddMember("a", Value(kArrayType).Move().PushBack(1, allocator).PushBack(2, allocator).PushBack(3, allocator), allocator);
|
||||||
|
|
||||||
|
// Test templated operator==() and operator!=()
|
||||||
|
TestEqual(x["hello"], "world");
|
||||||
|
const char* cc = "world";
|
||||||
|
TestEqual(x["hello"], cc);
|
||||||
|
char* c = strdup("world");
|
||||||
|
TestEqual(x["hello"], c);
|
||||||
|
free(c);
|
||||||
|
|
||||||
|
TestEqual(x["t"], true);
|
||||||
|
TestEqual(x["f"], false);
|
||||||
|
TestEqual(x["i"], 123);
|
||||||
|
TestEqual(x["pi"], 3.14);
|
||||||
|
|
||||||
|
// Test operator==()
|
||||||
|
Value y;
|
||||||
|
y.CopyFrom(x, allocator);
|
||||||
|
TestEqual(x, y);
|
||||||
|
|
||||||
|
// Swapping member order should be fine.
|
||||||
|
y.RemoveMember("t");
|
||||||
|
TestUnequal(x, y);
|
||||||
|
y.AddMember("t", Value(true).Move(), allocator);
|
||||||
|
TestEqual(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Value>
|
template <typename Value>
|
||||||
void TestCopyFrom() {
|
void TestCopyFrom() {
|
||||||
typename Value::AllocatorType a;
|
typename Value::AllocatorType a;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user