Commit 15d70d6a authored by Milo Yip's avatar Milo Yip

Merge pull request #127 from pah/feature/value-different-allocators

GenericValue: accept values with different allocators for read-only access
parents c6e6bca2 a2a0d161
...@@ -382,6 +382,22 @@ inline GenericStringRef<CharType> StringRef(const std::basic_string<CharType>& s ...@@ -382,6 +382,22 @@ inline GenericStringRef<CharType> StringRef(const std::basic_string<CharType>& s
} }
#endif #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 // GenericValue
...@@ -444,7 +460,7 @@ public: ...@@ -444,7 +460,7 @@ public:
\see CopyFrom() \see CopyFrom()
*/ */
template< typename SourceAllocator > template< typename SourceAllocator >
GenericValue(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator & allocator); GenericValue(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator & allocator);
//! Constructor for boolean value. //! Constructor for boolean value.
/*! \param b Boolean value /*! \param b Boolean value
...@@ -603,10 +619,10 @@ public: ...@@ -603,10 +619,10 @@ public:
\param allocator Allocator to use for copying \param allocator Allocator to use for copying
*/ */
template <typename SourceAllocator> 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); RAPIDJSON_ASSERT((void*)this != (void const*)&rhs);
this->~GenericValue(); this->~GenericValue();
new (this) GenericValue(rhs,allocator); new (this) GenericValue(rhs, allocator);
return *this; return *this;
} }
...@@ -635,7 +651,9 @@ public: ...@@ -635,7 +651,9 @@ public:
\note If an object contains duplicated named member, comparing equality with any object is always \c false. \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). \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()) if (GetType() != rhs.GetType())
return false; return false;
...@@ -644,7 +662,7 @@ public: ...@@ -644,7 +662,7 @@ public:
if (data_.o.size != rhs.data_.o.size) if (data_.o.size != rhs.data_.o.size)
return false; return false;
for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) { 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) if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value)
return false; return false;
} }
...@@ -685,27 +703,31 @@ public: ...@@ -685,27 +703,31 @@ public:
//! Equal-to operator with primitive types //! 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 /*! \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 //! Not-equal-to operator
/*! \return !(*this == rhs) /*! \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 //! Not-equal-to operator with arbitrary types
/*! \return !(*this == rhs) /*! \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) //! Equal-to operator with arbitrary types (symmetric version)
/*! \return (rhs == lhs) /*! \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) //! Not-Equal-to operator with arbitrary types (symmetric version)
/*! \return !(rhs == lhs) /*! \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 //!@name Type
...@@ -774,7 +796,8 @@ public: ...@@ -774,7 +796,8 @@ public:
// This version is faster because it does not need a StrLen(). // This version is faster because it does not need a StrLen().
// It can also handle string with null character. // 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); MemberIterator member = FindMember(name);
if (member != MemberEnd()) if (member != MemberEnd())
return member->value; return member->value;
...@@ -784,7 +807,8 @@ public: ...@@ -784,7 +807,8 @@ public:
return NullValue; 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 //! Const member iterator
/*! \pre IsObject() == true */ /*! \pre IsObject() == true */
...@@ -818,7 +842,8 @@ public: ...@@ -818,7 +842,8 @@ public:
\note It is better to use FindMember() directly if you need the obtain the value as well. \note It is better to use FindMember() directly if you need the obtain the value as well.
\note Linear time complexity. \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. //! Find member by name.
/*! /*!
...@@ -852,7 +877,8 @@ public: ...@@ -852,7 +877,8 @@ public:
\c std::map, this has been changed to MemberEnd() now. \c std::map, this has been changed to MemberEnd() now.
\note Linear time complexity. \note Linear time complexity.
*/ */
MemberIterator FindMember(const GenericValue& name) { template <typename SourceAllocator>
MemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) {
RAPIDJSON_ASSERT(IsObject()); RAPIDJSON_ASSERT(IsObject());
RAPIDJSON_ASSERT(name.IsString()); RAPIDJSON_ASSERT(name.IsString());
MemberIterator member = MemberBegin(); MemberIterator member = MemberBegin();
...@@ -861,7 +887,7 @@ public: ...@@ -861,7 +887,7 @@ public:
break; break;
return member; 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. //! Add a member (name-value pair) to the object.
/*! \param name A string value as name of member. /*! \param name A string value as name of member.
...@@ -942,7 +968,7 @@ public: ...@@ -942,7 +968,7 @@ public:
\note Amortized Constant time complexity. \note Amortized Constant time complexity.
*/ */
template <typename T> 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) { AddMember(StringRefType name, T value, Allocator& allocator) {
GenericValue n(name); GenericValue n(name);
GenericValue v(value); GenericValue v(value);
...@@ -971,7 +997,8 @@ public: ...@@ -971,7 +997,8 @@ public:
return RemoveMember(n); return RemoveMember(n);
} }
bool RemoveMember(const GenericValue& name) { template <typename SourceAllocator>
bool RemoveMember(const GenericValue<Encoding, SourceAllocator>& name) {
MemberIterator m = FindMember(name); MemberIterator m = FindMember(name);
if (m != MemberEnd()) { if (m != MemberEnd()) {
RemoveMember(m); RemoveMember(m);
...@@ -1166,7 +1193,7 @@ int z = a[0u].GetInt(); // This works too. ...@@ -1166,7 +1193,7 @@ int z = a[0u].GetInt(); // This works too.
\note Amortized constant time complexity. \note Amortized constant time complexity.
*/ */
template <typename T> 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) { PushBack(T value, Allocator& allocator) {
GenericValue v(value); GenericValue v(value);
return PushBack(v, allocator); return PushBack(v, allocator);
...@@ -1352,8 +1379,8 @@ int z = a[0u].GetInt(); // This works too. ...@@ -1352,8 +1379,8 @@ int z = a[0u].GetInt(); // This works too.
} }
private: private:
template <typename, typename, typename> template <typename, typename> friend class GenericValue;
friend class GenericDocument; template <typename, typename, typename> friend class GenericDocument;
enum { enum {
kBoolFlag = 0x100, kBoolFlag = 0x100,
...@@ -1505,7 +1532,8 @@ private: ...@@ -1505,7 +1532,8 @@ private:
rhs.flags_ = kNullFlag; 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(IsString());
RAPIDJSON_ASSERT(rhs.IsString()); RAPIDJSON_ASSERT(rhs.IsString());
...@@ -1706,7 +1734,7 @@ private: ...@@ -1706,7 +1734,7 @@ private:
// callers of the following private Handler functions // callers of the following private Handler functions
template <typename,typename,typename> friend class GenericReader; // for parsing 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 // Implementation of Handler
bool Null() { new (stack_.template Push<ValueType>()) ValueType(); return true; } bool Null() { new (stack_.template Push<ValueType>()) ValueType(); return true; }
......
...@@ -38,6 +38,8 @@ RAPIDJSON_DIAG_OFF(6334) ...@@ -38,6 +38,8 @@ RAPIDJSON_DIAG_OFF(6334)
namespace rapidjson { namespace rapidjson {
namespace internal { 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 // BoolType, TrueType, FalseType
......
...@@ -89,15 +89,9 @@ inline FILE* TempFile(char *filename) { ...@@ -89,15 +89,9 @@ inline FILE* TempFile(char *filename) {
#pragma warning(disable : 4127) #pragma warning(disable : 4127)
#endif #endif
class AssertException : public std::exception { class AssertException : public std::logic_error {
public: public:
AssertException(const char* w) : what_(w) {} AssertException(const char* w) : std::logic_error(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_;
}; };
#define RAPIDJSON_ASSERT(x) if (!(x)) throw AssertException(RAPIDJSON_STRINGIFY(x)) #define RAPIDJSON_ASSERT(x) if (!(x)) throw AssertException(RAPIDJSON_STRINGIFY(x))
......
...@@ -105,20 +105,12 @@ TEST(Value, equalto_operator) { ...@@ -105,20 +105,12 @@ TEST(Value, equalto_operator) {
TestEqual(x["i"], 123); TestEqual(x["i"], 123);
TestEqual(x["pi"], 3.14); TestEqual(x["pi"], 3.14);
// Test operator==() // Test operator==() (including different allocators)
#ifdef RAPIDJSON_COMPARE_DIFFERENT_ALLOCATORS
CrtAllocator crtAllocator; CrtAllocator crtAllocator;
GenericValue<UTF8<>, CrtAllocator> y; GenericValue<UTF8<>, CrtAllocator> y;
GenericDocument<UTF8<>, CrtAllocator> z(&crtAllocator); GenericDocument<UTF8<>, CrtAllocator> z(&crtAllocator);
CrtAllocator& yAllocator = crtAllocator; y.CopyFrom(x, crtAllocator);
#else
Value::AllocatorType& yAllocator = allocator;
Value y;
Document z;
#endif // RAPIDJSON_COMPARE_DIFFERENT_ALLOCATORS
y.CopyFrom(x, yAllocator);
z.CopyFrom(y, z.GetAllocator()); z.CopyFrom(y, z.GetAllocator());
TestEqual(x, y); TestEqual(x, y);
TestEqual(y, z); TestEqual(y, z);
TestEqual(z, x); TestEqual(z, x);
...@@ -130,7 +122,7 @@ TEST(Value, equalto_operator) { ...@@ -130,7 +122,7 @@ TEST(Value, equalto_operator) {
EXPECT_TRUE(z.RemoveMember("t")); EXPECT_TRUE(z.RemoveMember("t"));
TestUnequal(x, z); TestUnequal(x, z);
TestEqual(y, z); TestEqual(y, z);
y.AddMember("t", true, yAllocator); y.AddMember("t", true, crtAllocator);
z.AddMember("t", true, z.GetAllocator()); z.AddMember("t", true, z.GetAllocator());
TestEqual(x, y); TestEqual(x, y);
TestEqual(y, z); TestEqual(y, z);
...@@ -843,10 +835,18 @@ TEST(Value, Object) { ...@@ -843,10 +835,18 @@ TEST(Value, Object) {
EXPECT_TRUE(x.HasMember(name)); EXPECT_TRUE(x.HasMember(name));
EXPECT_TRUE(y.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[] // operator[]
EXPECT_STREQ("Apple", x["A"].GetString()); EXPECT_STREQ("Apple", x["A"].GetString());
EXPECT_STREQ("Banana", x["B"].GetString()); EXPECT_STREQ("Banana", x["B"].GetString());
EXPECT_STREQ("CherryD", x[C0D].GetString()); EXPECT_STREQ("CherryD", x[C0D].GetString());
EXPECT_STREQ("CherryD", x[othername].GetString());
// const operator[] // const operator[]
EXPECT_STREQ("Apple", y["A"].GetString()); EXPECT_STREQ("Apple", y["A"].GetString());
...@@ -917,7 +917,7 @@ TEST(Value, Object) { ...@@ -917,7 +917,7 @@ TEST(Value, Object) {
x.RemoveMember("B"); x.RemoveMember("B");
EXPECT_FALSE(x.HasMember("B")); EXPECT_FALSE(x.HasMember("B"));
x.RemoveMember(name); x.RemoveMember(othername);
EXPECT_FALSE(x.HasMember(name)); EXPECT_FALSE(x.HasMember(name));
EXPECT_TRUE(x.MemberBegin() == x.MemberEnd()); EXPECT_TRUE(x.MemberBegin() == x.MemberEnd());
...@@ -930,11 +930,14 @@ TEST(Value, Object) { ...@@ -930,11 +930,14 @@ TEST(Value, Object) {
for (int i = 0; i < 10; i++) for (int i = 0; i < 10; i++)
x.AddMember(keys[i], Value(kArrayType).PushBack(i, allocator), allocator); 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 // Erase the first
itr = x.EraseMember(x.MemberBegin()); itr = x.EraseMember(x.MemberBegin());
EXPECT_FALSE(x.HasMember(keys[0])); EXPECT_FALSE(x.HasMember(keys[0]));
EXPECT_EQ(x.MemberBegin(), itr); EXPECT_EQ(x.MemberBegin(), itr);
EXPECT_EQ(9, x.MemberEnd() - x.MemberBegin()); EXPECT_EQ(9u, x.MemberCount());
for (; itr != x.MemberEnd(); ++itr) { for (; itr != x.MemberEnd(); ++itr) {
int i = (itr - x.MemberBegin()) + 1; int i = (itr - x.MemberBegin()) + 1;
EXPECT_STREQ(itr->name.GetString(), keys[i]); EXPECT_STREQ(itr->name.GetString(), keys[i]);
...@@ -945,7 +948,7 @@ TEST(Value, Object) { ...@@ -945,7 +948,7 @@ TEST(Value, Object) {
itr = x.EraseMember(x.MemberEnd() - 1); itr = x.EraseMember(x.MemberEnd() - 1);
EXPECT_FALSE(x.HasMember(keys[9])); EXPECT_FALSE(x.HasMember(keys[9]));
EXPECT_EQ(x.MemberEnd(), itr); EXPECT_EQ(x.MemberEnd(), itr);
EXPECT_EQ(8, x.MemberEnd() - x.MemberBegin()); EXPECT_EQ(8u, x.MemberCount());
for (; itr != x.MemberEnd(); ++itr) { for (; itr != x.MemberEnd(); ++itr) {
int i = (itr - x.MemberBegin()) + 1; int i = (itr - x.MemberBegin()) + 1;
EXPECT_STREQ(itr->name.GetString(), keys[i]); EXPECT_STREQ(itr->name.GetString(), keys[i]);
...@@ -956,7 +959,7 @@ TEST(Value, Object) { ...@@ -956,7 +959,7 @@ TEST(Value, Object) {
itr = x.EraseMember(x.MemberBegin() + 4); itr = x.EraseMember(x.MemberBegin() + 4);
EXPECT_FALSE(x.HasMember(keys[5])); EXPECT_FALSE(x.HasMember(keys[5]));
EXPECT_EQ(x.MemberBegin() + 4, itr); EXPECT_EQ(x.MemberBegin() + 4, itr);
EXPECT_EQ(7, x.MemberEnd() - x.MemberBegin()); EXPECT_EQ(7u, x.MemberCount());
for (; itr != x.MemberEnd(); ++itr) { for (; itr != x.MemberEnd(); ++itr) {
int i = (itr - x.MemberBegin()); int i = (itr - x.MemberBegin());
i += (i<4) ? 1 : 2; i += (i<4) ? 1 : 2;
...@@ -980,7 +983,7 @@ TEST(Value, Object) { ...@@ -980,7 +983,7 @@ TEST(Value, Object) {
EXPECT_EQ(x.MemberBegin() + first, itr); EXPECT_EQ(x.MemberBegin() + first, itr);
size_t removeCount = last - first; 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++) for (unsigned i = 0; i < first; i++)
EXPECT_EQ(i, x[keys[i]][0u].GetUint()); EXPECT_EQ(i, x[keys[i]][0u].GetUint());
for (unsigned i = first; i < n - removeCount; i++) for (unsigned i = first; i < n - removeCount; i++)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment