Merge pull request #127 from pah/feature/value-different-allocators
GenericValue: accept values with different allocators for read-only access
This commit is contained in:
commit
15d70d6a7b
@ -382,6 +382,22 @@ inline GenericStringRef<CharType> StringRef(const std::basic_string<CharType>& s
|
||||
}
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// GenericValue type traits
|
||||
namespace internal {
|
||||
|
||||
template <typename T, typename Encoding = void, typename Allocator = void>
|
||||
struct IsGenericValueImpl : FalseType {};
|
||||
|
||||
// select candidates according to nested encoding and allocator types
|
||||
template <typename T> struct IsGenericValueImpl<T, typename Void<typename T::EncodingType>::Type, typename Void<typename T::AllocatorType>::Type>
|
||||
: IsBaseOf<GenericValue<typename T::EncodingType, typename T::AllocatorType>, T>::Type {};
|
||||
|
||||
// helper to match arbitrary GenericValue instantiations, including derived classes
|
||||
template <typename T> struct IsGenericValue : IsGenericValueImpl<T>::Type {};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// GenericValue
|
||||
|
||||
@ -444,7 +460,7 @@ public:
|
||||
\see CopyFrom()
|
||||
*/
|
||||
template< typename SourceAllocator >
|
||||
GenericValue(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator & allocator);
|
||||
GenericValue(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator & allocator);
|
||||
|
||||
//! Constructor for boolean value.
|
||||
/*! \param b Boolean value
|
||||
@ -603,10 +619,10 @@ public:
|
||||
\param allocator Allocator to use for copying
|
||||
*/
|
||||
template <typename SourceAllocator>
|
||||
GenericValue& CopyFrom(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator) {
|
||||
GenericValue& CopyFrom(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator& allocator) {
|
||||
RAPIDJSON_ASSERT((void*)this != (void const*)&rhs);
|
||||
this->~GenericValue();
|
||||
new (this) GenericValue(rhs,allocator);
|
||||
new (this) GenericValue(rhs, allocator);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -635,7 +651,9 @@ public:
|
||||
\note If an object contains duplicated named member, comparing equality with any object is always \c false.
|
||||
\note Linear time complexity (number of all values in the subtree and total lengths of all strings).
|
||||
*/
|
||||
bool operator==(const GenericValue& rhs) const {
|
||||
template <typename SourceAllocator>
|
||||
bool operator==(const GenericValue<Encoding, SourceAllocator>& rhs) const {
|
||||
typedef GenericValue<Encoding, SourceAllocator> RhsType;
|
||||
if (GetType() != rhs.GetType())
|
||||
return false;
|
||||
|
||||
@ -644,7 +662,7 @@ public:
|
||||
if (data_.o.size != rhs.data_.o.size)
|
||||
return false;
|
||||
for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) {
|
||||
ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name);
|
||||
typename RhsType::ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name);
|
||||
if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value)
|
||||
return false;
|
||||
}
|
||||
@ -685,27 +703,31 @@ public:
|
||||
//! 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> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>,internal::IsBaseOf<GenericValue,T> >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); }
|
||||
template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>,internal::IsGenericValue<T> >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); }
|
||||
|
||||
//! Not-equal-to operator
|
||||
/*! \return !(*this == rhs)
|
||||
*/
|
||||
bool operator!=(const GenericValue& rhs) const { return !(*this == rhs); }
|
||||
template <typename SourceAllocator>
|
||||
bool operator!=(const GenericValue<Encoding, SourceAllocator>& rhs) const { return !(*this == rhs); }
|
||||
|
||||
//! Not-equal-to operator with const C-string pointer
|
||||
bool operator!=(const Ch* rhs) const { return !(*this == rhs); }
|
||||
|
||||
//! Not-equal-to operator with arbitrary types
|
||||
/*! \return !(*this == rhs)
|
||||
*/
|
||||
template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::IsBaseOf<GenericValue,T>), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); }
|
||||
template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); }
|
||||
|
||||
//! Equal-to operator with arbitrary types (symmetric version)
|
||||
/*! \return (rhs == lhs)
|
||||
*/
|
||||
template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsBaseOf<GenericValue,T>), (bool)) operator==(const T& lhs, const GenericValue& rhs) { return rhs == lhs; }
|
||||
template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator==(const T& lhs, const GenericValue& rhs) { return rhs == lhs; }
|
||||
|
||||
//! Not-Equal-to operator with arbitrary types (symmetric version)
|
||||
/*! \return !(rhs == lhs)
|
||||
*/
|
||||
template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsBaseOf<GenericValue,T>), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); }
|
||||
template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); }
|
||||
//@}
|
||||
|
||||
//!@name Type
|
||||
@ -774,7 +796,8 @@ public:
|
||||
|
||||
// This version is faster because it does not need a StrLen().
|
||||
// It can also handle string with null character.
|
||||
GenericValue& operator[](const GenericValue& name) {
|
||||
template <typename SourceAllocator>
|
||||
GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) {
|
||||
MemberIterator member = FindMember(name);
|
||||
if (member != MemberEnd())
|
||||
return member->value;
|
||||
@ -784,7 +807,8 @@ public:
|
||||
return NullValue;
|
||||
}
|
||||
}
|
||||
const GenericValue& operator[](const GenericValue& name) const { return const_cast<GenericValue&>(*this)[name]; }
|
||||
template <typename SourceAllocator>
|
||||
const GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this)[name]; }
|
||||
|
||||
//! Const member iterator
|
||||
/*! \pre IsObject() == true */
|
||||
@ -818,7 +842,8 @@ public:
|
||||
\note It is better to use FindMember() directly if you need the obtain the value as well.
|
||||
\note Linear time complexity.
|
||||
*/
|
||||
bool HasMember(const GenericValue& name) const { return FindMember(name) != MemberEnd(); }
|
||||
template <typename SourceAllocator>
|
||||
bool HasMember(const GenericValue<Encoding, SourceAllocator>& name) const { return FindMember(name) != MemberEnd(); }
|
||||
|
||||
//! Find member by name.
|
||||
/*!
|
||||
@ -852,7 +877,8 @@ public:
|
||||
\c std::map, this has been changed to MemberEnd() now.
|
||||
\note Linear time complexity.
|
||||
*/
|
||||
MemberIterator FindMember(const GenericValue& name) {
|
||||
template <typename SourceAllocator>
|
||||
MemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) {
|
||||
RAPIDJSON_ASSERT(IsObject());
|
||||
RAPIDJSON_ASSERT(name.IsString());
|
||||
MemberIterator member = MemberBegin();
|
||||
@ -861,7 +887,7 @@ public:
|
||||
break;
|
||||
return member;
|
||||
}
|
||||
ConstMemberIterator FindMember(const GenericValue& name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
|
||||
template <typename SourceAllocator> ConstMemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
|
||||
|
||||
//! Add a member (name-value pair) to the object.
|
||||
/*! \param name A string value as name of member.
|
||||
@ -942,7 +968,7 @@ public:
|
||||
\note Amortized Constant time complexity.
|
||||
*/
|
||||
template <typename T>
|
||||
RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer<T>), (GenericValue&))
|
||||
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))
|
||||
AddMember(StringRefType name, T value, Allocator& allocator) {
|
||||
GenericValue n(name);
|
||||
GenericValue v(value);
|
||||
@ -971,7 +997,8 @@ public:
|
||||
return RemoveMember(n);
|
||||
}
|
||||
|
||||
bool RemoveMember(const GenericValue& name) {
|
||||
template <typename SourceAllocator>
|
||||
bool RemoveMember(const GenericValue<Encoding, SourceAllocator>& name) {
|
||||
MemberIterator m = FindMember(name);
|
||||
if (m != MemberEnd()) {
|
||||
RemoveMember(m);
|
||||
@ -1166,7 +1193,7 @@ int z = a[0u].GetInt(); // This works too.
|
||||
\note Amortized constant time complexity.
|
||||
*/
|
||||
template <typename T>
|
||||
RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer<T>), (GenericValue&))
|
||||
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))
|
||||
PushBack(T value, Allocator& allocator) {
|
||||
GenericValue v(value);
|
||||
return PushBack(v, allocator);
|
||||
@ -1352,8 +1379,8 @@ int z = a[0u].GetInt(); // This works too.
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename, typename, typename>
|
||||
friend class GenericDocument;
|
||||
template <typename, typename> friend class GenericValue;
|
||||
template <typename, typename, typename> friend class GenericDocument;
|
||||
|
||||
enum {
|
||||
kBoolFlag = 0x100,
|
||||
@ -1505,7 +1532,8 @@ private:
|
||||
rhs.flags_ = kNullFlag;
|
||||
}
|
||||
|
||||
bool StringEqual(const GenericValue& rhs) const {
|
||||
template <typename SourceAllocator>
|
||||
bool StringEqual(const GenericValue<Encoding, SourceAllocator>& rhs) const {
|
||||
RAPIDJSON_ASSERT(IsString());
|
||||
RAPIDJSON_ASSERT(rhs.IsString());
|
||||
|
||||
@ -1706,7 +1734,7 @@ private:
|
||||
|
||||
// callers of the following private Handler functions
|
||||
template <typename,typename,typename> friend class GenericReader; // for parsing
|
||||
friend class GenericValue<Encoding,Allocator>; // for deep copying
|
||||
template <typename, typename> friend class GenericValue; // for deep copying
|
||||
|
||||
// Implementation of Handler
|
||||
bool Null() { new (stack_.template Push<ValueType>()) ValueType(); return true; }
|
||||
|
@ -38,6 +38,8 @@ RAPIDJSON_DIAG_OFF(6334)
|
||||
namespace rapidjson {
|
||||
namespace internal {
|
||||
|
||||
// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching
|
||||
template <typename T> struct Void { typedef void Type; };
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BoolType, TrueType, FalseType
|
||||
|
@ -89,15 +89,9 @@ inline FILE* TempFile(char *filename) {
|
||||
#pragma warning(disable : 4127)
|
||||
#endif
|
||||
|
||||
class AssertException : public std::exception {
|
||||
class AssertException : public std::logic_error {
|
||||
public:
|
||||
AssertException(const char* w) : what_(w) {}
|
||||
AssertException(const AssertException& other) : what_(other.what_) {}
|
||||
AssertException& operator=(const AssertException& rhs) { what_ = rhs.what_; return *this; }
|
||||
virtual const char* what() const throw() { return what_; }
|
||||
|
||||
private:
|
||||
const char* what_;
|
||||
AssertException(const char* w) : std::logic_error(w) {}
|
||||
};
|
||||
|
||||
#define RAPIDJSON_ASSERT(x) if (!(x)) throw AssertException(RAPIDJSON_STRINGIFY(x))
|
||||
|
@ -105,20 +105,12 @@ TEST(Value, equalto_operator) {
|
||||
TestEqual(x["i"], 123);
|
||||
TestEqual(x["pi"], 3.14);
|
||||
|
||||
// Test operator==()
|
||||
#ifdef RAPIDJSON_COMPARE_DIFFERENT_ALLOCATORS
|
||||
// Test operator==() (including different allocators)
|
||||
CrtAllocator crtAllocator;
|
||||
GenericValue<UTF8<>, CrtAllocator> y;
|
||||
GenericDocument<UTF8<>, CrtAllocator> z(&crtAllocator);
|
||||
CrtAllocator& yAllocator = crtAllocator;
|
||||
#else
|
||||
Value::AllocatorType& yAllocator = allocator;
|
||||
Value y;
|
||||
Document z;
|
||||
#endif // RAPIDJSON_COMPARE_DIFFERENT_ALLOCATORS
|
||||
y.CopyFrom(x, yAllocator);
|
||||
y.CopyFrom(x, crtAllocator);
|
||||
z.CopyFrom(y, z.GetAllocator());
|
||||
|
||||
TestEqual(x, y);
|
||||
TestEqual(y, z);
|
||||
TestEqual(z, x);
|
||||
@ -130,7 +122,7 @@ TEST(Value, equalto_operator) {
|
||||
EXPECT_TRUE(z.RemoveMember("t"));
|
||||
TestUnequal(x, z);
|
||||
TestEqual(y, z);
|
||||
y.AddMember("t", true, yAllocator);
|
||||
y.AddMember("t", true, crtAllocator);
|
||||
z.AddMember("t", true, z.GetAllocator());
|
||||
TestEqual(x, y);
|
||||
TestEqual(y, z);
|
||||
@ -843,10 +835,18 @@ TEST(Value, Object) {
|
||||
EXPECT_TRUE(x.HasMember(name));
|
||||
EXPECT_TRUE(y.HasMember(name));
|
||||
|
||||
GenericValue<UTF8<>, CrtAllocator> othername("A");
|
||||
EXPECT_TRUE(x.HasMember(othername));
|
||||
EXPECT_TRUE(y.HasMember(othername));
|
||||
othername.SetString("C\0D");
|
||||
EXPECT_TRUE(x.HasMember(othername));
|
||||
EXPECT_TRUE(y.HasMember(othername));
|
||||
|
||||
// operator[]
|
||||
EXPECT_STREQ("Apple", x["A"].GetString());
|
||||
EXPECT_STREQ("Banana", x["B"].GetString());
|
||||
EXPECT_STREQ("CherryD", x[C0D].GetString());
|
||||
EXPECT_STREQ("CherryD", x[othername].GetString());
|
||||
|
||||
// const operator[]
|
||||
EXPECT_STREQ("Apple", y["A"].GetString());
|
||||
@ -917,7 +917,7 @@ TEST(Value, Object) {
|
||||
x.RemoveMember("B");
|
||||
EXPECT_FALSE(x.HasMember("B"));
|
||||
|
||||
x.RemoveMember(name);
|
||||
x.RemoveMember(othername);
|
||||
EXPECT_FALSE(x.HasMember(name));
|
||||
|
||||
EXPECT_TRUE(x.MemberBegin() == x.MemberEnd());
|
||||
@ -930,11 +930,14 @@ TEST(Value, Object) {
|
||||
for (int i = 0; i < 10; i++)
|
||||
x.AddMember(keys[i], Value(kArrayType).PushBack(i, allocator), allocator);
|
||||
|
||||
// MemberCount, iterator difference
|
||||
EXPECT_EQ(x.MemberCount(), SizeType(x.MemberEnd() - x.MemberBegin()));
|
||||
|
||||
// Erase the first
|
||||
itr = x.EraseMember(x.MemberBegin());
|
||||
EXPECT_FALSE(x.HasMember(keys[0]));
|
||||
EXPECT_EQ(x.MemberBegin(), itr);
|
||||
EXPECT_EQ(9, x.MemberEnd() - x.MemberBegin());
|
||||
EXPECT_EQ(9u, x.MemberCount());
|
||||
for (; itr != x.MemberEnd(); ++itr) {
|
||||
int i = (itr - x.MemberBegin()) + 1;
|
||||
EXPECT_STREQ(itr->name.GetString(), keys[i]);
|
||||
@ -945,7 +948,7 @@ TEST(Value, Object) {
|
||||
itr = x.EraseMember(x.MemberEnd() - 1);
|
||||
EXPECT_FALSE(x.HasMember(keys[9]));
|
||||
EXPECT_EQ(x.MemberEnd(), itr);
|
||||
EXPECT_EQ(8, x.MemberEnd() - x.MemberBegin());
|
||||
EXPECT_EQ(8u, x.MemberCount());
|
||||
for (; itr != x.MemberEnd(); ++itr) {
|
||||
int i = (itr - x.MemberBegin()) + 1;
|
||||
EXPECT_STREQ(itr->name.GetString(), keys[i]);
|
||||
@ -956,7 +959,7 @@ TEST(Value, Object) {
|
||||
itr = x.EraseMember(x.MemberBegin() + 4);
|
||||
EXPECT_FALSE(x.HasMember(keys[5]));
|
||||
EXPECT_EQ(x.MemberBegin() + 4, itr);
|
||||
EXPECT_EQ(7, x.MemberEnd() - x.MemberBegin());
|
||||
EXPECT_EQ(7u, x.MemberCount());
|
||||
for (; itr != x.MemberEnd(); ++itr) {
|
||||
int i = (itr - x.MemberBegin());
|
||||
i += (i<4) ? 1 : 2;
|
||||
@ -980,7 +983,7 @@ TEST(Value, Object) {
|
||||
EXPECT_EQ(x.MemberBegin() + first, itr);
|
||||
|
||||
size_t removeCount = last - first;
|
||||
EXPECT_EQ(n - removeCount, size_t(x.MemberEnd() - x.MemberBegin()));
|
||||
EXPECT_EQ(n - removeCount, x.MemberCount());
|
||||
for (unsigned i = 0; i < first; i++)
|
||||
EXPECT_EQ(i, x[keys[i]][0u].GetUint());
|
||||
for (unsigned i = first; i < n - removeCount; i++)
|
||||
|
Loading…
x
Reference in New Issue
Block a user