From 4d648fdcd8bd32826e12151c5eba29c3417cde89 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 12 Feb 2016 18:23:32 +0800 Subject: [PATCH 01/17] Add templated accessors --- include/rapidjson/document.h | 98 ++++++++++++++++++++++++++++++++++++ test/unittest/valuetest.cpp | 56 +++++++++++++++++++-- 2 files changed, 151 insertions(+), 3 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index b0a5d34..d0f4bea 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -393,6 +393,87 @@ template struct IsGenericValue : IsGenericValueImpl::Type {}; } // namespace internal +/////////////////////////////////////////////////////////////////////////////// +// TypeHelper + +namespace internal { + +template +struct TypeHelper { + static bool Is(const ValueType&) { RAPIDJSON_ASSERT(false && "Unsupport type"); } + static T Get(const ValueType&) { RAPIDJSON_ASSERT(false && "Unsupport type"); } + static ValueType& Set(ValueType&, T) { RAPIDJSON_ASSERT(false && "Unsupport type"); } + static ValueType& Set(ValueType&, T, typename ValueType::AllocatorType&) { RAPIDJSON_ASSERT(false && "Unsupport type"); } +}; + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsBool(); } + static bool Get(const ValueType& v) { return v.GetBool(); } + static ValueType& Set(ValueType& v, bool data) { return v.SetBool(data); } + static ValueType& Set(ValueType& v, bool data, typename ValueType::AllocatorType&) { return v.SetBool(data); } +}; + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsInt(); } + static int Get(const ValueType& v) { return v.GetInt(); } + static ValueType& Set(ValueType& v, int data) { return v.SetInt(data); } + static ValueType& Set(ValueType& v, int data, typename ValueType::AllocatorType&) { return v.SetInt(data); } +}; + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsUint(); } + static unsigned Get(const ValueType& v) { return v.GetUint(); } + static ValueType& Set(ValueType& v, unsigned data) { return v.SetUint(data); } + static ValueType& Set(ValueType& v, unsigned data, typename ValueType::AllocatorType&) { return v.SetUint(data); } +}; + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsInt64(); } + static int64_t Get(const ValueType& v) { return v.GetInt64(); } + static ValueType& Set(ValueType& v, int64_t data) { return v.SetInt64(data); } + static ValueType& Set(ValueType& v, int64_t data, typename ValueType::AllocatorType&) { return v.SetInt64(data); } +}; + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsUint64(); } + static uint64_t Get(const ValueType& v) { return v.GetUint64(); } + static ValueType& Set(ValueType& v, uint64_t data) { return v.SetUint64(data); } + static ValueType& Set(ValueType& v, uint64_t data, typename ValueType::AllocatorType&) { return v.SetUint64(data); } +}; + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsDouble(); } + static double Get(const ValueType& v) { return v.GetDouble(); } + static ValueType& Set(ValueType& v, double data) { return v.SetDouble(data); } + static ValueType& Set(ValueType& v, double data, typename ValueType::AllocatorType&) { return v.SetDouble(data); } +}; + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsFloat(); } + static float Get(const ValueType& v) { return v.GetFloat(); } + static ValueType& Set(ValueType& v, float data) { return v.SetFloat(data); } + static ValueType& Set(ValueType& v, float data, typename ValueType::AllocatorType&) { return v.SetFloat(data); } +}; + +#if RAPIDJSON_HAS_STDSTRING +template +struct TypeHelper > { + typedef std::basic_string StringType; + static bool Is(const ValueType& v) { return v.IsString(); } + static StringType Get(const ValueType& v) { return v.GetString(); } + static ValueType& Set(ValueType& v, const StringType& data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); } +}; +#endif + +} // namespace internal + /////////////////////////////////////////////////////////////////////////////// // GenericValue @@ -1484,6 +1565,7 @@ public: /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessFloat() to check whether the converison is lossless. */ double GetFloat() const { + RAPIDJSON_ASSERT(IsFloat()); return static_cast(GetDouble()); } @@ -1554,6 +1636,22 @@ public: //@} + //! Templated version for checking whether this value is type T. + /*! + \tparam T Either \c bool, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c float, \c std::basic_string + */ + template + bool Is() const { return internal::TypeHelper::Is(*this); } + + template + T Get() const { return internal::TypeHelper::Get(*this); } + + template + ValueType& Set(const T& data) { return internal::TypeHelper::Set(*this, data); } + + template + ValueType& Set(const T& data, AllocatorType& allocator) { return internal::TypeHelper::Set(*this, data, allocator); } + //! Generate events of this value to a Handler. /*! This function adopts the GoF visitor pattern. Typical usage is to output this JSON value as JSON text via Writer, which is a Handler. diff --git a/test/unittest/valuetest.cpp b/test/unittest/valuetest.cpp index 4179ccb..7d1bb9e 100644 --- a/test/unittest/valuetest.cpp +++ b/test/unittest/valuetest.cpp @@ -335,6 +335,12 @@ TEST(Value, True) { Value z; z.SetBool(true); EXPECT_TRUE(z.IsTrue()); + + // Templated functions + EXPECT_TRUE(z.Is()); + EXPECT_TRUE(z.Get()); + EXPECT_FALSE(z.Set(false).Get()); + EXPECT_TRUE(z.Set(true).Get()); } TEST(Value, False) { @@ -414,6 +420,12 @@ TEST(Value, Int) { // operator=(int) z = 5678; EXPECT_EQ(5678, z.GetInt()); + + // Templated functions + EXPECT_TRUE(z.Is()); + EXPECT_EQ(5678, z.Get()); + EXPECT_EQ(5679, z.Set(5679).Get()); + EXPECT_EQ(5680, z.Set(5680).Get()); } TEST(Value, Uint) { @@ -453,6 +465,12 @@ TEST(Value, Uint) { EXPECT_EQ(2147483648u, z.GetUint()); EXPECT_FALSE(z.IsInt()); EXPECT_TRUE(z.IsInt64()); // Issue 41: Incorrect parsing of unsigned int number types + + // Templated functions + EXPECT_TRUE(z.Is()); + EXPECT_EQ(2147483648u, z.Get()); + EXPECT_EQ(2147483649u, z.Set(2147483649u).Get()); + EXPECT_EQ(2147483650u, z.Set(2147483650u).Get()); } TEST(Value, Int64) { @@ -505,8 +523,15 @@ TEST(Value, Int64) { EXPECT_FALSE(z.IsInt()); EXPECT_NEAR(-2147483649.0, z.GetDouble(), 0.0); - z.SetInt64(static_cast(RAPIDJSON_UINT64_C2(0x80000000, 00000000))); + int64_t i = static_cast(RAPIDJSON_UINT64_C2(0x80000000, 00000000)); + z.SetInt64(i); EXPECT_DOUBLE_EQ(-9223372036854775808.0, z.GetDouble()); + + // Templated functions + EXPECT_TRUE(z.Is()); + EXPECT_EQ(i, z.Get()); + EXPECT_EQ(i - 1, z.Set(i - 1).Get()); + EXPECT_EQ(i - 2, z.Set(i - 2).Get()); } TEST(Value, Uint64) { @@ -547,10 +572,17 @@ TEST(Value, Uint64) { EXPECT_FALSE(z.IsUint()); EXPECT_TRUE(z.IsInt64()); - z.SetUint64(RAPIDJSON_UINT64_C2(0x80000000, 0x00000000)); // 2^63 cannot cast as int64 + uint64_t u = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000); + z.SetUint64(u); // 2^63 cannot cast as int64 EXPECT_FALSE(z.IsInt64()); - EXPECT_EQ(RAPIDJSON_UINT64_C2(0x80000000, 0x00000000), z.GetUint64()); // Issue 48 + EXPECT_EQ(u, z.GetUint64()); // Issue 48 EXPECT_DOUBLE_EQ(9223372036854775808.0, z.GetDouble()); + + // Templated functions + EXPECT_TRUE(z.Is()); + EXPECT_EQ(u, z.Get()); + EXPECT_EQ(u + 1, z.Set(u + 1).Get()); + EXPECT_EQ(u + 2, z.Set(u + 2).Get()); } TEST(Value, Double) { @@ -577,6 +609,12 @@ TEST(Value, Double) { z = 56.78; EXPECT_NEAR(56.78, z.GetDouble(), 0.0); + + // Templated functions + EXPECT_TRUE(z.Is()); + EXPECT_EQ(56.78, z.Get()); + EXPECT_EQ(57.78, z.Set(57.78).Get()); + EXPECT_EQ(58.78, z.Set(58.78).Get()); } TEST(Value, Float) { @@ -604,6 +642,12 @@ TEST(Value, Float) { z = 56.78f; EXPECT_NEAR(56.78f, z.GetFloat(), 0.0f); + + // Templated functions + EXPECT_TRUE(z.Is()); + EXPECT_EQ(56.78f, z.Get()); + EXPECT_EQ(57.78f, z.Set(57.78f).Get()); + EXPECT_EQ(58.78f, z.Set(58.78f).Get()); } TEST(Value, IsLosslessDouble) { @@ -759,6 +803,12 @@ TEST(Value, String) { vs1 = StringRef(str); TestEqual(str, vs1); TestEqual(vs0, vs1); + + // Templated function. + EXPECT_TRUE(vs0.Is()); + EXPECT_EQ(str, vs0.Get()); + EXPECT_EQ(std::string("Apple"), vs0.Set(std::string("Apple"), allocator).template Get()); + EXPECT_EQ(std::string("Orange"), vs0.Set(std::string("Orange"), allocator).template Get()); } #endif // RAPIDJSON_HAS_STDSTRING } From 59309b5dd2bdfc405d2d9b6f842d702cb8db8b26 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sat, 13 Feb 2016 19:06:03 +0800 Subject: [PATCH 02/17] Add GenericArray helper class with range-based for --- include/rapidjson/document.h | 73 ++++++++++++++++++++++++++- include/rapidjson/rapidjson.h | 11 ++++ test/unittest/valuetest.cpp | 95 +++++++++++++++++++++++++++-------- 3 files changed, 157 insertions(+), 22 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 194c8c6..59eb59f 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -483,6 +483,9 @@ struct TypeHelper > { } // namespace internal +template +class GenericArray; + /////////////////////////////////////////////////////////////////////////////// // GenericValue @@ -510,6 +513,7 @@ public: typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array. typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array. typedef GenericValue ValueType; //!< Value type of itself. + typedef GenericArray ArrayType; //!@name Constructors and destructor. //@{ @@ -1556,6 +1560,9 @@ public: return pos; } + ArrayType GetArray() { RAPIDJSON_ASSERT(IsArray()); return ArrayType(*this); } + const ArrayType GetArray() const { RAPIDJSON_ASSERT(IsArray()); return ArrayType(*this); } + //@} //!@name Number @@ -1653,9 +1660,12 @@ public: //@} + //!@name Array + //@{ + //! Templated version for checking whether this value is type T. /*! - \tparam T Either \c bool, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c float, \c std::basic_string + \tparam T Either \c bool, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c float, \c const \c char*, \c std::basic_string */ template bool Is() const { return internal::TypeHelper::Is(*this); } @@ -1669,6 +1679,8 @@ public: template ValueType& Set(const T& data, AllocatorType& allocator) { return internal::TypeHelper::Set(*this, data, allocator); } + //@} + //! Generate events of this value to a Handler. /*! This function adopts the GoF visitor pattern. Typical usage is to output this JSON value as JSON text via Writer, which is a Handler. @@ -2278,6 +2290,65 @@ GenericValue::GenericValue(const GenericValue +class GenericArray { +public: + typedef typename ValueType::ValueIterator ValueIterator; + typedef typename ValueType::ConstValueIterator ConstValueIterator; + typedef typename ValueType::AllocatorType AllocatorType; + typedef typename ValueType::StringRefType StringRefType; + + template + friend class GenericValue; + + GenericArray() : ptr_() {} + GenericArray(const GenericArray& rhs) : ptr_(rhs.ptr_) {} + GenericArray& operator=(GenericArray& rhs) { ptr_ = rhs.ptr_; return *this; } + ~GenericArray() {} + + SizeType Size() const { return ptr_->Size(); } + SizeType Capacity() const { return ptr_->Capacity(); } + bool Empty() const { return ptr_->Empty(); } + void Clear() { ptr_->Clear(); } + ValueType& operator[](SizeType index) { return (*ptr_)[index]; } + const ValueType& operator[](SizeType index) const { return (*ptr_)[index]; } + ValueIterator Begin() { return ptr_->Begin(); } + ValueIterator End() { return ptr_->End(); } + ConstValueIterator Begin() const { return ptr_->Begin(); } + ConstValueIterator End() const { return ptr_->End(); } + GenericArray& Reserve(SizeType newCapacity, AllocatorType &allocator) { ptr_->Reserve(newCapacity, allocator); return *this; } + GenericArray& PushBack(ValueType& value, AllocatorType& allocator) { ptr_->PushBack(value, allocator); return *this; } +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + GenericArray& PushBack(ValueType&& value, AllocatorType& allocator) { ptr_->PushBack(value, allocator); return *this; } +#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS + GenericArray& PushBack(StringRefType value, AllocatorType& allocator) { ptr_->PushBack(value, allocator); return *this; } + template + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericArray&)) + PushBack(T value, AllocatorType& allocator) { ptr_->PushBack(value, allocator); return *this; } + GenericArray& PopBack() { ptr_->PopBack(); return *this; } + ValueIterator Erase(ConstValueIterator pos) { return ptr_->Erase(pos); } + ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) { return ptr_->Erase(first, last); } + +#if RAPIDJSON_HAS_CXX11_RANGE_FOR + ValueIterator begin() { return ptr_->Begin(); } + ValueIterator end() { return ptr_->End(); } + ConstValueIterator begin() const { return ptr_->Begin(); } + ConstValueIterator end() const { return ptr_->End(); } +#endif + +private: + GenericArray(ValueType& value) : ptr_(&value) {} + GenericArray(const ValueType& value) : ptr_(const_cast(&value)) {} + ValueType* ptr_; +}; + +typedef GenericArray Array; + RAPIDJSON_NAMESPACE_END #ifdef _MSC_VER diff --git a/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h index 9cb40a9..d5480ec 100644 --- a/include/rapidjson/rapidjson.h +++ b/include/rapidjson/rapidjson.h @@ -530,6 +530,17 @@ RAPIDJSON_NAMESPACE_END #define RAPIDJSON_HAS_CXX11_TYPETRAITS 0 #endif +#ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR +#if defined(__clang) +#define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for) +#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ + (defined(_MSC_VER) && _MSC_VER >= 1600) +#define RAPIDJSON_HAS_CXX11_RANGE_FOR 1 +#else +#define RAPIDJSON_HAS_CXX11_RANGE_FOR 0 +#endif +#endif // RAPIDJSON_HAS_CXX11_RANGE_FOR + //!@endcond /////////////////////////////////////////////////////////////////////////////// diff --git a/test/unittest/valuetest.cpp b/test/unittest/valuetest.cpp index a1912b3..4f2d9df 100644 --- a/test/unittest/valuetest.cpp +++ b/test/unittest/valuetest.cpp @@ -824,25 +824,9 @@ TEST(Value, SetStringNullException) { EXPECT_THROW(v.SetString(0, 0), AssertException); } -TEST(Value, Array) { - Value x(kArrayType); - const Value& y = x; - Value::AllocatorType allocator; - - EXPECT_EQ(kArrayType, x.GetType()); - EXPECT_TRUE(x.IsArray()); - EXPECT_TRUE(x.Empty()); - EXPECT_EQ(0u, x.Size()); - EXPECT_TRUE(y.IsArray()); - EXPECT_TRUE(y.Empty()); - EXPECT_EQ(0u, y.Size()); - - EXPECT_FALSE(x.IsNull()); - EXPECT_FALSE(x.IsBool()); - EXPECT_FALSE(x.IsFalse()); - EXPECT_FALSE(x.IsTrue()); - EXPECT_FALSE(x.IsString()); - EXPECT_FALSE(x.IsObject()); +template +void TestArray(T& x, Allocator& allocator) { + const T& y = x; // PushBack() Value v; @@ -889,7 +873,7 @@ TEST(Value, Array) { #endif // iterator - Value::ValueIterator itr = x.Begin(); + typename T::ValueIterator itr = x.Begin(); EXPECT_TRUE(itr != x.End()); EXPECT_TRUE(itr->IsNull()); ++itr; @@ -908,7 +892,7 @@ TEST(Value, Array) { EXPECT_STREQ("foo", itr->GetString()); // const iterator - Value::ConstValueIterator citr = y.Begin(); + typename T::ConstValueIterator citr = y.Begin(); EXPECT_TRUE(citr != y.End()); EXPECT_TRUE(citr->IsNull()); ++citr; @@ -994,6 +978,29 @@ TEST(Value, Array) { EXPECT_EQ(i + removeCount, x[static_cast(i)][0].GetUint()); } } +} + +TEST(Value, Array) { + Value x(kArrayType); + const Value& y = x; + Value::AllocatorType allocator; + + EXPECT_EQ(kArrayType, x.GetType()); + EXPECT_TRUE(x.IsArray()); + EXPECT_TRUE(x.Empty()); + EXPECT_EQ(0u, x.Size()); + EXPECT_TRUE(y.IsArray()); + EXPECT_TRUE(y.Empty()); + EXPECT_EQ(0u, y.Size()); + + EXPECT_FALSE(x.IsNull()); + EXPECT_FALSE(x.IsBool()); + EXPECT_FALSE(x.IsFalse()); + EXPECT_FALSE(x.IsTrue()); + EXPECT_FALSE(x.IsString()); + EXPECT_FALSE(x.IsObject()); + + TestArray(x, allocator); // Working in gcc without C++11, but VS2013 cannot compile. To be diagnosed. // http://en.wikipedia.org/wiki/Erase-remove_idiom @@ -1017,6 +1024,52 @@ TEST(Value, Array) { EXPECT_TRUE(z.Empty()); } +TEST(Value, ArrayHelper) { + Value::AllocatorType allocator; + { + Value x(kArrayType); + Array a = x.GetArray(); + TestArray(a, allocator); + } + + Value x(kArrayType); + Array a = x.GetArray(); + a.PushBack(1, allocator); + + Array a2(a); // copy constructor + EXPECT_EQ(1, a2.Size()); + + Array a3; // default constructor + a3 = a; // assignment operator + EXPECT_EQ(1, a3.Size()); +} + +#if RAPIDJSON_HAS_CXX11_RANGE_FOR +TEST(Value, ArrayHelperRangeFor) { + Value::AllocatorType allocator; + Value x(kArrayType); + + for (int i = 0; i < 10; i++) + x.PushBack(i, allocator); + + { + int i = 0; + for (auto& v : x.GetArray()) + EXPECT_EQ(i++, v.GetInt()); + EXPECT_EQ(i, 10); + } + { + int i = 0; + for (auto& v : const_cast(x).GetArray()) + EXPECT_EQ(i++, v.GetInt()); + EXPECT_EQ(i, 10); + } + + // Array a = x.GetArray(); + // Array ca = const_cast(x).GetArray(); +} +#endif + TEST(Value, Object) { Value x(kObjectType); const Value& y = x; // const version From 0b098eb38d57c35741a62883340cf2b2af7e4634 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sat, 13 Feb 2016 22:09:14 +0800 Subject: [PATCH 03/17] Rectify constness of Array --- include/rapidjson/document.h | 54 ++++++++++++++++++++++++++---------- test/unittest/valuetest.cpp | 38 +++++++++++++++++++------ 2 files changed, 68 insertions(+), 24 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 59eb59f..1339c5b 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -481,9 +481,25 @@ struct TypeHelper > { }; #endif +template +struct TypeHelper { + typedef typename ValueType::Array ArratType; + static bool Is(const ValueType& v) { return v.IsArray(); } + static ArratType Get(ValueType& v) { return v.GetArray(); } + static ValueType& Set(ValueType& v, ArratType data) { return v.SetArray(data); } + static ValueType& Set(ValueType& v, ArratType data, typename ValueType::AllocatorType&) { return v.SetArray(data); } +}; + +template +struct TypeHelper { + typedef typename ValueType::ConstArray ArratType; + static bool Is(const ValueType& v) { return v.IsArray(); } + static ArratType Get(const ValueType& v) { return v.GetArray(); } +}; + } // namespace internal -template +template class GenericArray; /////////////////////////////////////////////////////////////////////////////// @@ -513,7 +529,8 @@ public: typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array. typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array. typedef GenericValue ValueType; //!< Value type of itself. - typedef GenericArray ArrayType; + typedef GenericArray Array; + typedef GenericArray ConstArray; //!@name Constructors and destructor. //@{ @@ -1114,7 +1131,7 @@ public: RAPIDJSON_ASSERT(IsObject()); RAPIDJSON_ASSERT(name.IsString()); - Object& o = data_.o; + ObjectData& o = data_.o; if (o.size >= o.capacity) { if (o.capacity == 0) { o.capacity = kDefaultObjectCapacity; @@ -1392,7 +1409,10 @@ public: //! Set this value as an empty array. /*! \post IsArray == true */ - GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; } + GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; } + + //! Set this value with an array. + GenericValue& SetArray(Array& a) { return *this = *a.ptr_; } //! Get the number of elements in array. SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; } @@ -1560,8 +1580,8 @@ public: return pos; } - ArrayType GetArray() { RAPIDJSON_ASSERT(IsArray()); return ArrayType(*this); } - const ArrayType GetArray() const { RAPIDJSON_ASSERT(IsArray()); return ArrayType(*this); } + Array GetArray() { RAPIDJSON_ASSERT(IsArray()); return Array(*this); } + ConstArray GetArray() const { RAPIDJSON_ASSERT(IsArray()); return ConstArray(*this); } //@} @@ -1673,6 +1693,9 @@ public: template T Get() const { return internal::TypeHelper::Get(*this); } + template + T Get() { return internal::TypeHelper::Get(*this); } + template ValueType& Set(const T& data) { return internal::TypeHelper::Set(*this, data); } @@ -1815,13 +1838,13 @@ private: double d; }; // 8 bytes - struct Object { + struct ObjectData { Member* members; SizeType size; SizeType capacity; }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode - struct Array { + struct ArrayData { GenericValue* elements; SizeType size; SizeType capacity; @@ -1831,8 +1854,8 @@ private: String s; ShortString ss; Number n; - Object o; - Array a; + ObjectData o; + ArrayData a; }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode // Initialize this value as array with initial data, without calling destructor. @@ -2295,9 +2318,13 @@ GenericValue::GenericValue(const GenericValue +template class GenericArray { public: + typedef GenericArray ConstArray; + typedef GenericArray Array; + typedef ValueT PlainType; + typedef typename internal::MaybeAddConst::Type ValueType; typedef typename ValueType::ValueIterator ValueIterator; typedef typename ValueType::ConstValueIterator ConstValueIterator; typedef typename ValueType::AllocatorType AllocatorType; @@ -2308,7 +2335,7 @@ public: GenericArray() : ptr_() {} GenericArray(const GenericArray& rhs) : ptr_(rhs.ptr_) {} - GenericArray& operator=(GenericArray& rhs) { ptr_ = rhs.ptr_; return *this; } + GenericArray& operator=(const GenericArray& rhs) { ptr_ = rhs.ptr_; return *this; } ~GenericArray() {} SizeType Size() const { return ptr_->Size(); } @@ -2343,12 +2370,9 @@ public: private: GenericArray(ValueType& value) : ptr_(&value) {} - GenericArray(const ValueType& value) : ptr_(const_cast(&value)) {} ValueType* ptr_; }; -typedef GenericArray Array; - RAPIDJSON_NAMESPACE_END #ifdef _MSC_VER diff --git a/test/unittest/valuetest.cpp b/test/unittest/valuetest.cpp index 4f2d9df..9af1e1c 100644 --- a/test/unittest/valuetest.cpp +++ b/test/unittest/valuetest.cpp @@ -1028,20 +1028,40 @@ TEST(Value, ArrayHelper) { Value::AllocatorType allocator; { Value x(kArrayType); - Array a = x.GetArray(); + Value::Array a = x.GetArray(); TestArray(a, allocator); } - Value x(kArrayType); - Array a = x.GetArray(); - a.PushBack(1, allocator); + { + Value x(kArrayType); + Value::Array a = x.GetArray(); + a.PushBack(1, allocator); - Array a2(a); // copy constructor - EXPECT_EQ(1, a2.Size()); + Value::Array a2(a); // copy constructor + EXPECT_EQ(1, a2.Size()); - Array a3; // default constructor - a3 = a; // assignment operator - EXPECT_EQ(1, a3.Size()); + Value::Array a3; // default constructor + a3 = a; // assignment operator + EXPECT_EQ(1, a3.Size()); + + Value::ConstArray y = static_cast(x).GetArray(); + (void)y; + // y.PushBack(1, allocator); // should not compile + + // Templated functions + x.Clear(); + EXPECT_TRUE(x.Is()); + EXPECT_TRUE(x.Is()); + a.PushBack(1, allocator); + a = x.Get(); + EXPECT_EQ(1, a[0].GetInt()); + EXPECT_EQ(1, x.Get()[0].GetInt()); + + Value x2; + x2.Set(a); + EXPECT_TRUE(x.IsNull()); + EXPECT_EQ(1, x2.Get()[0].GetInt()); + } } #if RAPIDJSON_HAS_CXX11_RANGE_FOR From 2a78b4da8c1f80d1845ed23ec9abeffa546f38fa Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sat, 13 Feb 2016 22:11:12 +0800 Subject: [PATCH 04/17] Fix Value.String test compilation error --- test/unittest/valuetest.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/unittest/valuetest.cpp b/test/unittest/valuetest.cpp index 9af1e1c..a8b6c57 100644 --- a/test/unittest/valuetest.cpp +++ b/test/unittest/valuetest.cpp @@ -812,8 +812,10 @@ TEST(Value, String) { // Templated function. EXPECT_TRUE(vs0.Is()); EXPECT_EQ(str, vs0.Get()); - EXPECT_EQ(std::string("Apple"), vs0.Set(std::string("Apple"), allocator).template Get()); - EXPECT_EQ(std::string("Orange"), vs0.Set(std::string("Orange"), allocator).template Get()); + vs0.Set(std::string("Apple"), allocator); + EXPECT_EQ(std::string("Apple"), vs0.Get()); + vs0.Set(std::string("Orange"), allocator); + EXPECT_EQ(std::string("Orange"), vs0.Get()); } #endif // RAPIDJSON_HAS_STDSTRING } From 960324a95b65315afdcf736806e8f0666f70cd3f Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sat, 13 Feb 2016 23:07:26 +0800 Subject: [PATCH 05/17] Try to fix gcc compilation error --- test/unittest/valuetest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unittest/valuetest.cpp b/test/unittest/valuetest.cpp index a8b6c57..7077fe5 100644 --- a/test/unittest/valuetest.cpp +++ b/test/unittest/valuetest.cpp @@ -1082,7 +1082,7 @@ TEST(Value, ArrayHelperRangeFor) { } { int i = 0; - for (auto& v : const_cast(x).GetArray()) + for (const auto& v : const_cast(x).GetArray()) EXPECT_EQ(i++, v.GetInt()); EXPECT_EQ(i, 10); } From effc8a8f304bc8239c8a29e1a8988a2567277c72 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sun, 14 Feb 2016 00:12:04 +0800 Subject: [PATCH 06/17] Let constness of GenericArray::ValueItaertor depending on ValueType --- include/rapidjson/document.h | 39 ++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 1339c5b..1ce2e4f 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -2325,8 +2325,8 @@ public: typedef GenericArray Array; typedef ValueT PlainType; typedef typename internal::MaybeAddConst::Type ValueType; - typedef typename ValueType::ValueIterator ValueIterator; - typedef typename ValueType::ConstValueIterator ConstValueIterator; + typedef ValueType* ValueIterator; // This may be const or non-const iterator + typedef const ValueType* ConstValueIterator; typedef typename ValueType::AllocatorType AllocatorType; typedef typename ValueType::StringRefType StringRefType; @@ -2341,31 +2341,26 @@ public: SizeType Size() const { return ptr_->Size(); } SizeType Capacity() const { return ptr_->Capacity(); } bool Empty() const { return ptr_->Empty(); } - void Clear() { ptr_->Clear(); } - ValueType& operator[](SizeType index) { return (*ptr_)[index]; } - const ValueType& operator[](SizeType index) const { return (*ptr_)[index]; } - ValueIterator Begin() { return ptr_->Begin(); } - ValueIterator End() { return ptr_->End(); } - ConstValueIterator Begin() const { return ptr_->Begin(); } - ConstValueIterator End() const { return ptr_->End(); } - GenericArray& Reserve(SizeType newCapacity, AllocatorType &allocator) { ptr_->Reserve(newCapacity, allocator); return *this; } - GenericArray& PushBack(ValueType& value, AllocatorType& allocator) { ptr_->PushBack(value, allocator); return *this; } + void Clear() const { ptr_->Clear(); } + ValueType& operator[](SizeType index) const { return (*ptr_)[index]; } + ValueIterator Begin() const { return ptr_->Begin(); } + ValueIterator End() const { return ptr_->End(); } + const GenericArray& Reserve(SizeType newCapacity, AllocatorType &allocator) const { ptr_->Reserve(newCapacity, allocator); return *this; } + const GenericArray& PushBack(ValueType& value, AllocatorType& allocator) const { ptr_->PushBack(value, allocator); return *this; } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS - GenericArray& PushBack(ValueType&& value, AllocatorType& allocator) { ptr_->PushBack(value, allocator); return *this; } + const GenericArray& PushBack(ValueType&& value, AllocatorType& allocator) const { ptr_->PushBack(value, allocator); return *this; } #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS - GenericArray& PushBack(StringRefType value, AllocatorType& allocator) { ptr_->PushBack(value, allocator); return *this; } + const GenericArray& PushBack(StringRefType value, AllocatorType& allocator) const { ptr_->PushBack(value, allocator); return *this; } template - RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericArray&)) - PushBack(T value, AllocatorType& allocator) { ptr_->PushBack(value, allocator); return *this; } - GenericArray& PopBack() { ptr_->PopBack(); return *this; } - ValueIterator Erase(ConstValueIterator pos) { return ptr_->Erase(pos); } - ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) { return ptr_->Erase(first, last); } + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (const GenericArray&)) + PushBack(T value, AllocatorType& allocator) const { ptr_->PushBack(value, allocator); return *this; } + const GenericArray& PopBack() const { ptr_->PopBack(); return *this; } + ValueIterator Erase(ConstValueIterator pos) const { return ptr_->Erase(pos); } + ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) const { return ptr_->Erase(first, last); } #if RAPIDJSON_HAS_CXX11_RANGE_FOR - ValueIterator begin() { return ptr_->Begin(); } - ValueIterator end() { return ptr_->End(); } - ConstValueIterator begin() const { return ptr_->Begin(); } - ConstValueIterator end() const { return ptr_->End(); } + ValueIterator begin() const { return ptr_->Begin(); } + ValueIterator end() const { return ptr_->End(); } #endif private: From 923db0e6413a5589a67fdc7f5b2e694f09e6f16c Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sun, 14 Feb 2016 06:14:12 +0800 Subject: [PATCH 07/17] Fix gcc compilation error --- include/rapidjson/document.h | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 1ce2e4f..bd47e0c 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -399,12 +399,7 @@ template struct IsGenericValue : IsGenericValueImpl::Type {}; namespace internal { template -struct TypeHelper { - static bool Is(const ValueType&) { RAPIDJSON_ASSERT(false && "Unsupport type"); } - static T Get(const ValueType&) { RAPIDJSON_ASSERT(false && "Unsupport type"); return T(); } - static ValueType& Set(ValueType&, T) { RAPIDJSON_ASSERT(false && "Unsupport type"); } - static ValueType& Set(ValueType&, T, typename ValueType::AllocatorType&) { RAPIDJSON_ASSERT(false && "Unsupport type"); } -}; +struct TypeHelper {}; template struct TypeHelper { From 1634395378d886c4461e78117ecb715e1619d968 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sun, 14 Feb 2016 13:49:52 +0800 Subject: [PATCH 08/17] Add object helper --- include/rapidjson/document.h | 121 ++++++++++++++++++++++++++++++++-- include/rapidjson/rapidjson.h | 2 +- test/unittest/valuetest.cpp | 116 +++++++++++++++++++++++++++----- 3 files changed, 217 insertions(+), 22 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index bd47e0c..4370409 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -492,10 +492,27 @@ struct TypeHelper { static ArratType Get(const ValueType& v) { return v.GetArray(); } }; +template +struct TypeHelper { + typedef typename ValueType::Object ArratType; + static bool Is(const ValueType& v) { return v.IsObject(); } + static ArratType Get(ValueType& v) { return v.GetObject(); } + static ValueType& Set(ValueType& v, ArratType data) { return v.SetObject(data); } + static ValueType& Set(ValueType& v, ArratType data, typename ValueType::AllocatorType&) { return v.SetObject(data); } +}; + +template +struct TypeHelper { + typedef typename ValueType::ConstObject ArratType; + static bool Is(const ValueType& v) { return v.IsObject(); } + static ArratType Get(const ValueType& v) { return v.GetObject(); } +}; + } // namespace internal -template -class GenericArray; +// Forward declarations +template class GenericArray; +template class GenericObject; /////////////////////////////////////////////////////////////////////////////// // GenericValue @@ -526,6 +543,8 @@ public: typedef GenericValue ValueType; //!< Value type of itself. typedef GenericArray Array; typedef GenericArray ConstArray; + typedef GenericObject Object; + typedef GenericObject ConstObject; //!@name Constructors and destructor. //@{ @@ -951,6 +970,9 @@ public: /*! \post IsObject() == true */ GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; } + //! Set this value with an object. + GenericValue& SetObject(Object& o) { return *this = *o.ptr_; } + //! Get the number of members in the object. SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; } @@ -1397,6 +1419,9 @@ public: return false; } + Object GetObject() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); } + ConstObject GetObject() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); } + //@} //!@name Array @@ -2321,7 +2346,7 @@ public: typedef ValueT PlainType; typedef typename internal::MaybeAddConst::Type ValueType; typedef ValueType* ValueIterator; // This may be const or non-const iterator - typedef const ValueType* ConstValueIterator; + typedef const ValueT* ConstValueIterator; typedef typename ValueType::AllocatorType AllocatorType; typedef typename ValueType::StringRefType StringRefType; @@ -2346,9 +2371,7 @@ public: const GenericArray& PushBack(ValueType&& value, AllocatorType& allocator) const { ptr_->PushBack(value, allocator); return *this; } #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS const GenericArray& PushBack(StringRefType value, AllocatorType& allocator) const { ptr_->PushBack(value, allocator); return *this; } - template - RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (const GenericArray&)) - PushBack(T value, AllocatorType& allocator) const { ptr_->PushBack(value, allocator); return *this; } + template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (const GenericArray&)) PushBack(T value, AllocatorType& allocator) const { ptr_->PushBack(value, allocator); return *this; } const GenericArray& PopBack() const { ptr_->PopBack(); return *this; } ValueIterator Erase(ConstValueIterator pos) const { return ptr_->Erase(pos); } ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) const { return ptr_->Erase(first, last); } @@ -2363,6 +2386,92 @@ private: ValueType* ptr_; }; +//! Helper class for accessing Value of array type. +/*! + Instance of this helper class is obtained by \c GenericValue::GetArray(). + In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1. +*/ +template +class GenericObject { +public: + typedef GenericObject ConstObject; + typedef GenericObject Object; + typedef ValueT PlainType; + typedef typename internal::MaybeAddConst::Type ValueType; + typedef GenericMemberIterator MemberIterator; // This may be const or non-const iterator + typedef GenericMemberIterator ConstMemberIterator; + typedef typename ValueType::AllocatorType AllocatorType; + typedef typename ValueType::StringRefType StringRefType; + typedef typename ValueType::EncodingType EncodingType; + typedef typename ValueType::Ch Ch; + + template + friend class GenericValue; + + GenericObject() : ptr_() {} + GenericObject(const GenericObject& rhs) : ptr_(rhs.ptr_) {} + GenericObject& operator=(const GenericObject& rhs) { ptr_ = rhs.ptr_; return *this; } + ~GenericObject() {} + + SizeType MemberCount() const { return ptr_->MemberCount(); } + bool ObjectEmpty() const { return ptr_->ObjectEmpty(); } + ValueType& operator[](Ch* name) const { return (*ptr_)[name]; } + template ValueType& operator[](const GenericValue& name) const { return (*ptr_)[name]; } +#if RAPIDJSON_HAS_STDSTRING + ValueType& operator[](const std::basic_string& name) const { return (*ptr_)[name]; } +#endif + MemberIterator MemberBegin() const { return ptr_->MemberBegin(); } + MemberIterator MemberEnd() const { return ptr_->MemberEnd(); } + bool HasMember(const Ch* name) const { return ptr_->HasMember(name); } +#if RAPIDJSON_HAS_STDSTRING + bool HasMember(const std::basic_string& name) const { return ptr_->HasMember(name); } +#endif + template bool HasMember(const GenericValue& name) const { return ptr_->HasMember(name); } + MemberIterator FindMember(const Ch* name) const { ptr_->FindMember(name); } + template MemberIterator FindMember(const GenericValue& name) const { ptr_->FindMember(name); } +#if RAPIDJSON_HAS_STDSTRING + MemberIterator FindMember(const std::basic_string& name) const { return ptr_->FindMember(name); } +#endif + ValueType& AddMember(ValueType& name, ValueType& value, AllocatorType& allocator) const { return ptr_->AddMember(name, value, allocator); } + ValueType& AddMember(ValueType& name, StringRefType value, AllocatorType& allocator) const { return ptr_->AddMember(name, value, allocator); } +#if RAPIDJSON_HAS_STDSTRING + ValueType& AddMember(ValueType& name, std::basic_string& value, AllocatorType& allocator) const { return ptr_->AddMember(name, value, allocator); } +#endif + template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) AddMember(ValueType& name, T value, AllocatorType& allocator) const { return ptr_->AddMember(name, value, allocator); } +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + ValueType& AddMember(ValueType&& name, ValueType&& value, AllocatorType& allocator) const { return ptr_->AddMember(name, value, allocator); } + ValueType& AddMember(ValueType&& name, ValueType& value, AllocatorType& allocator) const { return ptr_->AddMember(name, value, allocator); } + ValueType& AddMember(ValueType& name, ValueType&& value, AllocatorType& allocator) const { return ptr_->AddMember(name, value, allocator); } + ValueType& AddMember(StringRefType name, ValueType&& value, AllocatorType& allocator) const { return ptr_->AddMember(name, value, allocator); } +#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS + ValueType& AddMember(StringRefType name, ValueType& value, AllocatorType& allocator) const { return ptr_->AddMember(name, value, allocator); } + ValueType& AddMember(StringRefType name, StringRefType value, AllocatorType& allocator) const { return ptr_->AddMember(name, value, allocator); } + template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) AddMember(StringRefType name, T value, AllocatorType& allocator) const { return ptr_->AddMember(name, value, allocator); } + void RemoveAllMembers() { return ptr_->RemoveAllMembers(); } + bool RemoveMember(const Ch* name) const { return ptr_->RemoveMember(name); } +#if RAPIDJSON_HAS_STDSTRING + bool RemoveMember(const std::basic_string& name) const { return ptr_->RemoveMember(name); } +#endif + template bool RemoveMember(const GenericValue& name) const { return ptr_->RemoveMember(name); } + MemberIterator RemoveMember(MemberIterator m) const { return ptr_->RemoveMember(m); } + MemberIterator EraseMember(ConstMemberIterator pos) const { return ptr_->EraseMember(pos); } + MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) const { return ptr_->EraseMember(first, last); } + bool EraseMember(const Ch* name) const { ptr_->EraseMember(name); } +#if RAPIDJSON_HAS_STDSTRING + bool EraseMember(const std::basic_string& name) const { return EraseMember(ValueType(StringRef(name))); } +#endif + template bool EraseMember(const GenericValue& name) const { ptr_->EraseMember(name); } + +#if RAPIDJSON_HAS_CXX11_RANGE_FOR + MemberIterator begin() const { return ptr_->MemberBegin(); } + MemberIterator end() const { return ptr_->MemberEnd(); } +#endif + +private: + GenericObject(ValueType& value) : ptr_(&value) {} + ValueType* ptr_; +}; + RAPIDJSON_NAMESPACE_END #ifdef _MSC_VER diff --git a/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h index d5480ec..d0bbd10 100644 --- a/include/rapidjson/rapidjson.h +++ b/include/rapidjson/rapidjson.h @@ -531,7 +531,7 @@ RAPIDJSON_NAMESPACE_END #endif #ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR -#if defined(__clang) +#if defined(__clang__) #define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for) #elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ (defined(_MSC_VER) && _MSC_VER >= 1600) diff --git a/test/unittest/valuetest.cpp b/test/unittest/valuetest.cpp index 7077fe5..50eb206 100644 --- a/test/unittest/valuetest.cpp +++ b/test/unittest/valuetest.cpp @@ -827,7 +827,7 @@ TEST(Value, SetStringNullException) { } template -void TestArray(T& x, Allocator& allocator) { +static void TestArray(T& x, Allocator& allocator) { const T& y = x; // PushBack() @@ -1092,19 +1092,9 @@ TEST(Value, ArrayHelperRangeFor) { } #endif -TEST(Value, Object) { - Value x(kObjectType); - const Value& y = x; // const version - Value::AllocatorType allocator; - - EXPECT_EQ(kObjectType, x.GetType()); - EXPECT_TRUE(x.IsObject()); - EXPECT_TRUE(x.ObjectEmpty()); - EXPECT_EQ(0u, x.MemberCount()); - EXPECT_EQ(kObjectType, y.GetType()); - EXPECT_TRUE(y.IsObject()); - EXPECT_TRUE(y.ObjectEmpty()); - EXPECT_EQ(0u, y.MemberCount()); +template +static void TestObject(T& x, Allocator& allocator) { + const T& y = x; // const version // AddMember() x.AddMember("A", "Apple", allocator); @@ -1345,7 +1335,7 @@ TEST(Value, Object) { const unsigned n = 10; for (unsigned first = 0; first < n; first++) { for (unsigned last = first; last <= n; last++) { - Value(kObjectType).Swap(x); + x.RemoveAllMembers(); for (unsigned i = 0; i < n; i++) x.AddMember(keys[i], Value(kArrayType).PushBack(i, allocator), allocator); @@ -1368,6 +1358,23 @@ TEST(Value, Object) { x.RemoveAllMembers(); EXPECT_TRUE(x.ObjectEmpty()); EXPECT_EQ(0u, x.MemberCount()); +} + +TEST(Value, Object) { + Value x(kObjectType); + const Value& y = x; // const version + Value::AllocatorType allocator; + + EXPECT_EQ(kObjectType, x.GetType()); + EXPECT_TRUE(x.IsObject()); + EXPECT_TRUE(x.ObjectEmpty()); + EXPECT_EQ(0u, x.MemberCount()); + EXPECT_EQ(kObjectType, y.GetType()); + EXPECT_TRUE(y.IsObject()); + EXPECT_TRUE(y.ObjectEmpty()); + EXPECT_EQ(0u, y.MemberCount()); + + TestObject(x, allocator); // SetObject() Value z; @@ -1375,6 +1382,85 @@ TEST(Value, Object) { EXPECT_TRUE(z.IsObject()); } +TEST(Value, ObjectHelper) { + Value::AllocatorType allocator; + { + Value x(kObjectType); + Value::Object o = x.GetObject(); + TestObject(o, allocator); + } + + { + Value x(kObjectType); + Value::Object o = x.GetObject(); + o.AddMember("1", 1, allocator); + + Value::Object o2(o); // copy constructor + EXPECT_EQ(1, o2.MemberCount()); + + Value::Object o3; // default constructor + o3 = o; // assignment operator + EXPECT_EQ(1, o3.MemberCount()); + + Value::ConstObject y = static_cast(x).GetObject(); + (void)y; + // y.AddMember("1", 1, allocator); // should not compile + + // Templated functions + x.RemoveAllMembers(); + EXPECT_TRUE(x.Is()); + EXPECT_TRUE(x.Is()); + o.AddMember("1", 1, allocator); + o = x.Get(); + EXPECT_EQ(1, o["1"].GetInt()); + EXPECT_EQ(1, x.Get()["1"].GetInt()); + + Value x2; + x2.Set(o); + EXPECT_TRUE(x.IsNull()); + EXPECT_EQ(1, x2.Get()["1"].GetInt()); + } +} + +#if RAPIDJSON_HAS_CXX11_RANGE_FOR +TEST(Value, ObjectHelperRangeFor) { + Value::AllocatorType allocator; + Value x(kObjectType); + + for (int i = 0; i < 10; i++) { + char name[10]; + Value n(name, static_cast(sprintf(name, "%d", i)), allocator); + x.AddMember(n, i, allocator); + } + + { + int i = 0; + for (auto& m : x.GetObject()) { + char name[10]; + sprintf(name, "%d", i); + EXPECT_STREQ(name, m.name.GetString()); + EXPECT_EQ(i, m.value.GetInt()); + i++; + } + EXPECT_EQ(i, 10); + } + { + int i = 0; + for (const auto& m : const_cast(x).GetObject()) { + char name[10]; + sprintf(name, "%d", i); + EXPECT_STREQ(name, m.name.GetString()); + EXPECT_EQ(i, m.value.GetInt()); + i++; + } + EXPECT_EQ(i, 10); + } + + // Object a = x.GetObject(); + // Object ca = const_cast(x).GetObject(); +} +#endif + TEST(Value, EraseMember_String) { Value::AllocatorType allocator; Value x(kObjectType); From be66450ecdb5450f320561544fcdf19ab0141e78 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sun, 14 Feb 2016 14:00:27 +0800 Subject: [PATCH 09/17] Fix compilation errors --- include/rapidjson/document.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 4370409..f208902 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -2415,7 +2415,7 @@ public: SizeType MemberCount() const { return ptr_->MemberCount(); } bool ObjectEmpty() const { return ptr_->ObjectEmpty(); } - ValueType& operator[](Ch* name) const { return (*ptr_)[name]; } + template ValueType& operator[](T* name) const { return (*ptr_)[name]; } template ValueType& operator[](const GenericValue& name) const { return (*ptr_)[name]; } #if RAPIDJSON_HAS_STDSTRING ValueType& operator[](const std::basic_string& name) const { return (*ptr_)[name]; } @@ -2456,7 +2456,7 @@ public: MemberIterator RemoveMember(MemberIterator m) const { return ptr_->RemoveMember(m); } MemberIterator EraseMember(ConstMemberIterator pos) const { return ptr_->EraseMember(pos); } MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) const { return ptr_->EraseMember(first, last); } - bool EraseMember(const Ch* name) const { ptr_->EraseMember(name); } + bool EraseMember(const Ch* name) const { return ptr_->EraseMember(name); } #if RAPIDJSON_HAS_STDSTRING bool EraseMember(const std::basic_string& name) const { return EraseMember(ValueType(StringRef(name))); } #endif From 6671bd50f1a3fbc70a50347e15b2160956fe969b Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sun, 14 Feb 2016 14:07:19 +0800 Subject: [PATCH 10/17] Fix another compilation error --- include/rapidjson/document.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index f208902..67f9e9b 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -2460,7 +2460,7 @@ public: #if RAPIDJSON_HAS_STDSTRING bool EraseMember(const std::basic_string& name) const { return EraseMember(ValueType(StringRef(name))); } #endif - template bool EraseMember(const GenericValue& name) const { ptr_->EraseMember(name); } + template bool EraseMember(const GenericValue& name) const { return ptr_->EraseMember(name); } #if RAPIDJSON_HAS_CXX11_RANGE_FOR MemberIterator begin() const { return ptr_->MemberBegin(); } From 4ababca8938b478ced660bcafa6b52c8a053640f Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Wed, 17 Feb 2016 08:48:22 +0800 Subject: [PATCH 11/17] Fixed typos pointed out by @pah --- include/rapidjson/document.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 67f9e9b..1aecbd5 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -478,34 +478,34 @@ struct TypeHelper > { template struct TypeHelper { - typedef typename ValueType::Array ArratType; + typedef typename ValueType::Array ArrayType; static bool Is(const ValueType& v) { return v.IsArray(); } - static ArratType Get(ValueType& v) { return v.GetArray(); } - static ValueType& Set(ValueType& v, ArratType data) { return v.SetArray(data); } - static ValueType& Set(ValueType& v, ArratType data, typename ValueType::AllocatorType&) { return v.SetArray(data); } + static ArrayType Get(ValueType& v) { return v.GetArray(); } + static ValueType& Set(ValueType& v, ArrayType data) { return v.SetArray(data); } + static ValueType& Set(ValueType& v, ArrayType data, typename ValueType::AllocatorType&) { return v.SetArray(data); } }; template struct TypeHelper { - typedef typename ValueType::ConstArray ArratType; + typedef typename ValueType::ConstArray ArrayType; static bool Is(const ValueType& v) { return v.IsArray(); } - static ArratType Get(const ValueType& v) { return v.GetArray(); } + static ArrayType Get(const ValueType& v) { return v.GetArray(); } }; template struct TypeHelper { - typedef typename ValueType::Object ArratType; + typedef typename ValueType::Object ObjectType; static bool Is(const ValueType& v) { return v.IsObject(); } - static ArratType Get(ValueType& v) { return v.GetObject(); } - static ValueType& Set(ValueType& v, ArratType data) { return v.SetObject(data); } - static ValueType& Set(ValueType& v, ArratType data, typename ValueType::AllocatorType&) { return v.SetObject(data); } + static ObjectType Get(ValueType& v) { return v.GetObject(); } + static ValueType& Set(ValueType& v, ObjectType data) { return v.SetObject(data); } + static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { return v.SetObject(data); } }; template struct TypeHelper { - typedef typename ValueType::ConstObject ArratType; + typedef typename ValueType::ConstObject ObjectType; static bool Is(const ValueType& v) { return v.IsObject(); } - static ArratType Get(const ValueType& v) { return v.GetObject(); } + static ObjectType Get(const ValueType& v) { return v.GetObject(); } }; } // namespace internal From 8c79fb65ae86a78c78e757e82af4c225c206afe6 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Wed, 17 Feb 2016 09:34:19 +0800 Subject: [PATCH 12/17] Fix return type of GenericObject::AddMember() --- include/rapidjson/document.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 1aecbd5..5f2c1ba 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -2432,21 +2432,21 @@ public: #if RAPIDJSON_HAS_STDSTRING MemberIterator FindMember(const std::basic_string& name) const { return ptr_->FindMember(name); } #endif - ValueType& AddMember(ValueType& name, ValueType& value, AllocatorType& allocator) const { return ptr_->AddMember(name, value, allocator); } - ValueType& AddMember(ValueType& name, StringRefType value, AllocatorType& allocator) const { return ptr_->AddMember(name, value, allocator); } + const GenericObject& AddMember(ValueType& name, ValueType& value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } + const GenericObject& AddMember(ValueType& name, StringRefType value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } #if RAPIDJSON_HAS_STDSTRING - ValueType& AddMember(ValueType& name, std::basic_string& value, AllocatorType& allocator) const { return ptr_->AddMember(name, value, allocator); } + const GenericObject& AddMember(ValueType& name, std::basic_string& value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } #endif - template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) AddMember(ValueType& name, T value, AllocatorType& allocator) const { return ptr_->AddMember(name, value, allocator); } + template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) AddMember(ValueType& name, T value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS - ValueType& AddMember(ValueType&& name, ValueType&& value, AllocatorType& allocator) const { return ptr_->AddMember(name, value, allocator); } - ValueType& AddMember(ValueType&& name, ValueType& value, AllocatorType& allocator) const { return ptr_->AddMember(name, value, allocator); } - ValueType& AddMember(ValueType& name, ValueType&& value, AllocatorType& allocator) const { return ptr_->AddMember(name, value, allocator); } - ValueType& AddMember(StringRefType name, ValueType&& value, AllocatorType& allocator) const { return ptr_->AddMember(name, value, allocator); } + const GenericObject& AddMember(ValueType&& name, ValueType&& value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } + const GenericObject& AddMember(ValueType&& name, ValueType& value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } + const GenericObject& AddMember(ValueType& name, ValueType&& value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } + const GenericObject& AddMember(StringRefType name, ValueType&& value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS - ValueType& AddMember(StringRefType name, ValueType& value, AllocatorType& allocator) const { return ptr_->AddMember(name, value, allocator); } - ValueType& AddMember(StringRefType name, StringRefType value, AllocatorType& allocator) const { return ptr_->AddMember(name, value, allocator); } - template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) AddMember(StringRefType name, T value, AllocatorType& allocator) const { return ptr_->AddMember(name, value, allocator); } + const GenericObject& AddMember(StringRefType name, ValueType& value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } + const GenericObject& AddMember(StringRefType name, StringRefType value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } + template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (const GenericObject&)) AddMember(StringRefType name, T value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } void RemoveAllMembers() { return ptr_->RemoveAllMembers(); } bool RemoveMember(const Ch* name) const { return ptr_->RemoveMember(name); } #if RAPIDJSON_HAS_STDSTRING From 70f9671bdfffb500160fbe9dfb3410fa1230c60b Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Thu, 18 Feb 2016 01:19:47 +0800 Subject: [PATCH 13/17] Return value type for GenericObject/Array member functions --- include/rapidjson/document.h | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 5f2c1ba..20c6712 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -2365,14 +2365,14 @@ public: ValueType& operator[](SizeType index) const { return (*ptr_)[index]; } ValueIterator Begin() const { return ptr_->Begin(); } ValueIterator End() const { return ptr_->End(); } - const GenericArray& Reserve(SizeType newCapacity, AllocatorType &allocator) const { ptr_->Reserve(newCapacity, allocator); return *this; } - const GenericArray& PushBack(ValueType& value, AllocatorType& allocator) const { ptr_->PushBack(value, allocator); return *this; } + GenericArray Reserve(SizeType newCapacity, AllocatorType &allocator) const { ptr_->Reserve(newCapacity, allocator); return *this; } + GenericArray PushBack(ValueType& value, AllocatorType& allocator) const { ptr_->PushBack(value, allocator); return *this; } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS - const GenericArray& PushBack(ValueType&& value, AllocatorType& allocator) const { ptr_->PushBack(value, allocator); return *this; } + GenericArray PushBack(ValueType&& value, AllocatorType& allocator) const { ptr_->PushBack(value, allocator); return *this; } #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS - const GenericArray& PushBack(StringRefType value, AllocatorType& allocator) const { ptr_->PushBack(value, allocator); return *this; } + GenericArray PushBack(StringRefType value, AllocatorType& allocator) const { ptr_->PushBack(value, allocator); return *this; } template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (const GenericArray&)) PushBack(T value, AllocatorType& allocator) const { ptr_->PushBack(value, allocator); return *this; } - const GenericArray& PopBack() const { ptr_->PopBack(); return *this; } + GenericArray PopBack() const { ptr_->PopBack(); return *this; } ValueIterator Erase(ConstValueIterator pos) const { return ptr_->Erase(pos); } ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) const { return ptr_->Erase(first, last); } @@ -2432,21 +2432,21 @@ public: #if RAPIDJSON_HAS_STDSTRING MemberIterator FindMember(const std::basic_string& name) const { return ptr_->FindMember(name); } #endif - const GenericObject& AddMember(ValueType& name, ValueType& value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } - const GenericObject& AddMember(ValueType& name, StringRefType value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } + GenericObject AddMember(ValueType& name, ValueType& value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } + GenericObject AddMember(ValueType& name, StringRefType value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } #if RAPIDJSON_HAS_STDSTRING - const GenericObject& AddMember(ValueType& name, std::basic_string& value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } + GenericObject AddMember(ValueType& name, std::basic_string& value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } #endif template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) AddMember(ValueType& name, T value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS - const GenericObject& AddMember(ValueType&& name, ValueType&& value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } - const GenericObject& AddMember(ValueType&& name, ValueType& value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } - const GenericObject& AddMember(ValueType& name, ValueType&& value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } - const GenericObject& AddMember(StringRefType name, ValueType&& value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } + GenericObject AddMember(ValueType&& name, ValueType&& value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } + GenericObject AddMember(ValueType&& name, ValueType& value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } + GenericObject AddMember(ValueType& name, ValueType&& value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } + GenericObject AddMember(StringRefType name, ValueType&& value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS - const GenericObject& AddMember(StringRefType name, ValueType& value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } - const GenericObject& AddMember(StringRefType name, StringRefType value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } - template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (const GenericObject&)) AddMember(StringRefType name, T value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } + GenericObject AddMember(StringRefType name, ValueType& value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } + GenericObject AddMember(StringRefType name, StringRefType value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } + template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericObject)) AddMember(StringRefType name, T value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } void RemoveAllMembers() { return ptr_->RemoveAllMembers(); } bool RemoveMember(const Ch* name) const { return ptr_->RemoveMember(name); } #if RAPIDJSON_HAS_STDSTRING From d13be6c72170842bcde1f182d72ca7638960bf66 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Thu, 18 Feb 2016 19:04:22 +0800 Subject: [PATCH 14/17] Change pointer to reference in GenericArray|Object --- include/rapidjson/document.h | 128 +++++++++++++++++------------------ test/unittest/valuetest.cpp | 12 ++-- 2 files changed, 68 insertions(+), 72 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 20c6712..c90705c 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -971,7 +971,7 @@ public: GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; } //! Set this value with an object. - GenericValue& SetObject(Object& o) { return *this = *o.ptr_; } + GenericValue& SetObject(Object& o) { return *this = o.value_; } //! Get the number of members in the object. SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; } @@ -1432,7 +1432,7 @@ public: GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; } //! Set this value with an array. - GenericValue& SetArray(Array& a) { return *this = *a.ptr_; } + GenericValue& SetArray(Array& a) { return *this = a.value_; } //! Get the number of elements in array. SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; } @@ -2353,37 +2353,37 @@ public: template friend class GenericValue; - GenericArray() : ptr_() {} - GenericArray(const GenericArray& rhs) : ptr_(rhs.ptr_) {} - GenericArray& operator=(const GenericArray& rhs) { ptr_ = rhs.ptr_; return *this; } + GenericArray(const GenericArray& rhs) : value_(rhs.value_) {} + GenericArray& operator=(const GenericArray& rhs) { value_ = rhs.value_; return *this; } ~GenericArray() {} - SizeType Size() const { return ptr_->Size(); } - SizeType Capacity() const { return ptr_->Capacity(); } - bool Empty() const { return ptr_->Empty(); } - void Clear() const { ptr_->Clear(); } - ValueType& operator[](SizeType index) const { return (*ptr_)[index]; } - ValueIterator Begin() const { return ptr_->Begin(); } - ValueIterator End() const { return ptr_->End(); } - GenericArray Reserve(SizeType newCapacity, AllocatorType &allocator) const { ptr_->Reserve(newCapacity, allocator); return *this; } - GenericArray PushBack(ValueType& value, AllocatorType& allocator) const { ptr_->PushBack(value, allocator); return *this; } + SizeType Size() const { return value_.Size(); } + SizeType Capacity() const { return value_.Capacity(); } + bool Empty() const { return value_.Empty(); } + void Clear() const { value_.Clear(); } + ValueType& operator[](SizeType index) const { return value_[index]; } + ValueIterator Begin() const { return value_.Begin(); } + ValueIterator End() const { return value_.End(); } + GenericArray Reserve(SizeType newCapacity, AllocatorType &allocator) const { value_.Reserve(newCapacity, allocator); return *this; } + GenericArray PushBack(ValueType& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS - GenericArray PushBack(ValueType&& value, AllocatorType& allocator) const { ptr_->PushBack(value, allocator); return *this; } + GenericArray PushBack(ValueType&& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS - GenericArray PushBack(StringRefType value, AllocatorType& allocator) const { ptr_->PushBack(value, allocator); return *this; } - template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (const GenericArray&)) PushBack(T value, AllocatorType& allocator) const { ptr_->PushBack(value, allocator); return *this; } - GenericArray PopBack() const { ptr_->PopBack(); return *this; } - ValueIterator Erase(ConstValueIterator pos) const { return ptr_->Erase(pos); } - ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) const { return ptr_->Erase(first, last); } + GenericArray PushBack(StringRefType value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } + template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (const GenericArray&)) PushBack(T value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } + GenericArray PopBack() const { value_.PopBack(); return *this; } + ValueIterator Erase(ConstValueIterator pos) const { return value_.Erase(pos); } + ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) const { return value_.Erase(first, last); } #if RAPIDJSON_HAS_CXX11_RANGE_FOR - ValueIterator begin() const { return ptr_->Begin(); } - ValueIterator end() const { return ptr_->End(); } + ValueIterator begin() const { return value_.Begin(); } + ValueIterator end() const { return value_.End(); } #endif private: - GenericArray(ValueType& value) : ptr_(&value) {} - ValueType* ptr_; + GenericArray(); + GenericArray(ValueType& value) : value_(value) {} + ValueType& value_; }; //! Helper class for accessing Value of array type. @@ -2408,68 +2408,68 @@ public: template friend class GenericValue; - GenericObject() : ptr_() {} - GenericObject(const GenericObject& rhs) : ptr_(rhs.ptr_) {} - GenericObject& operator=(const GenericObject& rhs) { ptr_ = rhs.ptr_; return *this; } + GenericObject(const GenericObject& rhs) : value_(rhs.value_) {} + GenericObject& operator=(const GenericObject& rhs) { value_ = rhs.value_; return *this; } ~GenericObject() {} - SizeType MemberCount() const { return ptr_->MemberCount(); } - bool ObjectEmpty() const { return ptr_->ObjectEmpty(); } - template ValueType& operator[](T* name) const { return (*ptr_)[name]; } - template ValueType& operator[](const GenericValue& name) const { return (*ptr_)[name]; } + SizeType MemberCount() const { return value_.MemberCount(); } + bool ObjectEmpty() const { return value_.ObjectEmpty(); } + template ValueType& operator[](T* name) const { return value_[name]; } + template ValueType& operator[](const GenericValue& name) const { return value_[name]; } #if RAPIDJSON_HAS_STDSTRING - ValueType& operator[](const std::basic_string& name) const { return (*ptr_)[name]; } + ValueType& operator[](const std::basic_string& name) const { return value_[name]; } #endif - MemberIterator MemberBegin() const { return ptr_->MemberBegin(); } - MemberIterator MemberEnd() const { return ptr_->MemberEnd(); } - bool HasMember(const Ch* name) const { return ptr_->HasMember(name); } + MemberIterator MemberBegin() const { return value_.MemberBegin(); } + MemberIterator MemberEnd() const { return value_.MemberEnd(); } + bool HasMember(const Ch* name) const { return value_.HasMember(name); } #if RAPIDJSON_HAS_STDSTRING - bool HasMember(const std::basic_string& name) const { return ptr_->HasMember(name); } + bool HasMember(const std::basic_string& name) const { return value_.HasMember(name); } #endif - template bool HasMember(const GenericValue& name) const { return ptr_->HasMember(name); } - MemberIterator FindMember(const Ch* name) const { ptr_->FindMember(name); } - template MemberIterator FindMember(const GenericValue& name) const { ptr_->FindMember(name); } + template bool HasMember(const GenericValue& name) const { return value_.HasMember(name); } + MemberIterator FindMember(const Ch* name) const { value_.FindMember(name); } + template MemberIterator FindMember(const GenericValue& name) const { value_.FindMember(name); } #if RAPIDJSON_HAS_STDSTRING - MemberIterator FindMember(const std::basic_string& name) const { return ptr_->FindMember(name); } + MemberIterator FindMember(const std::basic_string& name) const { return value_.FindMember(name); } #endif - GenericObject AddMember(ValueType& name, ValueType& value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } - GenericObject AddMember(ValueType& name, StringRefType value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } + GenericObject AddMember(ValueType& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + GenericObject AddMember(ValueType& name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } #if RAPIDJSON_HAS_STDSTRING - GenericObject AddMember(ValueType& name, std::basic_string& value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } + GenericObject AddMember(ValueType& name, std::basic_string& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } #endif - template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) AddMember(ValueType& name, T value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } + template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) AddMember(ValueType& name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS - GenericObject AddMember(ValueType&& name, ValueType&& value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } - GenericObject AddMember(ValueType&& name, ValueType& value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } - GenericObject AddMember(ValueType& name, ValueType&& value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } - GenericObject AddMember(StringRefType name, ValueType&& value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } + GenericObject AddMember(ValueType&& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + GenericObject AddMember(ValueType&& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + GenericObject AddMember(ValueType& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + GenericObject AddMember(StringRefType name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS - GenericObject AddMember(StringRefType name, ValueType& value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } - GenericObject AddMember(StringRefType name, StringRefType value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } - template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericObject)) AddMember(StringRefType name, T value, AllocatorType& allocator) const { ptr_->AddMember(name, value, allocator); return *this; } - void RemoveAllMembers() { return ptr_->RemoveAllMembers(); } - bool RemoveMember(const Ch* name) const { return ptr_->RemoveMember(name); } + GenericObject AddMember(StringRefType name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + GenericObject AddMember(StringRefType name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericObject)) AddMember(StringRefType name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + void RemoveAllMembers() { return value_.RemoveAllMembers(); } + bool RemoveMember(const Ch* name) const { return value_.RemoveMember(name); } #if RAPIDJSON_HAS_STDSTRING - bool RemoveMember(const std::basic_string& name) const { return ptr_->RemoveMember(name); } + bool RemoveMember(const std::basic_string& name) const { return value_.RemoveMember(name); } #endif - template bool RemoveMember(const GenericValue& name) const { return ptr_->RemoveMember(name); } - MemberIterator RemoveMember(MemberIterator m) const { return ptr_->RemoveMember(m); } - MemberIterator EraseMember(ConstMemberIterator pos) const { return ptr_->EraseMember(pos); } - MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) const { return ptr_->EraseMember(first, last); } - bool EraseMember(const Ch* name) const { return ptr_->EraseMember(name); } + template bool RemoveMember(const GenericValue& name) const { return value_.RemoveMember(name); } + MemberIterator RemoveMember(MemberIterator m) const { return value_.RemoveMember(m); } + MemberIterator EraseMember(ConstMemberIterator pos) const { return value_.EraseMember(pos); } + MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) const { return value_.EraseMember(first, last); } + bool EraseMember(const Ch* name) const { return value_.EraseMember(name); } #if RAPIDJSON_HAS_STDSTRING bool EraseMember(const std::basic_string& name) const { return EraseMember(ValueType(StringRef(name))); } #endif - template bool EraseMember(const GenericValue& name) const { return ptr_->EraseMember(name); } + template bool EraseMember(const GenericValue& name) const { return value_.EraseMember(name); } #if RAPIDJSON_HAS_CXX11_RANGE_FOR - MemberIterator begin() const { return ptr_->MemberBegin(); } - MemberIterator end() const { return ptr_->MemberEnd(); } + MemberIterator begin() const { return value_.MemberBegin(); } + MemberIterator end() const { return value_.MemberEnd(); } #endif private: - GenericObject(ValueType& value) : ptr_(&value) {} - ValueType* ptr_; + GenericObject(); + GenericObject(ValueType& value) : value_(value) {} + ValueType& value_; }; RAPIDJSON_NAMESPACE_END diff --git a/test/unittest/valuetest.cpp b/test/unittest/valuetest.cpp index 50eb206..28d84d4 100644 --- a/test/unittest/valuetest.cpp +++ b/test/unittest/valuetest.cpp @@ -1042,8 +1042,7 @@ TEST(Value, ArrayHelper) { Value::Array a2(a); // copy constructor EXPECT_EQ(1, a2.Size()); - Value::Array a3; // default constructor - a3 = a; // assignment operator + Value::Array a3 = a; EXPECT_EQ(1, a3.Size()); Value::ConstArray y = static_cast(x).GetArray(); @@ -1055,8 +1054,7 @@ TEST(Value, ArrayHelper) { EXPECT_TRUE(x.Is()); EXPECT_TRUE(x.Is()); a.PushBack(1, allocator); - a = x.Get(); - EXPECT_EQ(1, a[0].GetInt()); + EXPECT_EQ(1, x.Get()[0].GetInt()); EXPECT_EQ(1, x.Get()[0].GetInt()); Value x2; @@ -1398,8 +1396,7 @@ TEST(Value, ObjectHelper) { Value::Object o2(o); // copy constructor EXPECT_EQ(1, o2.MemberCount()); - Value::Object o3; // default constructor - o3 = o; // assignment operator + Value::Object o3 = o; EXPECT_EQ(1, o3.MemberCount()); Value::ConstObject y = static_cast(x).GetObject(); @@ -1411,8 +1408,7 @@ TEST(Value, ObjectHelper) { EXPECT_TRUE(x.Is()); EXPECT_TRUE(x.Is()); o.AddMember("1", 1, allocator); - o = x.Get(); - EXPECT_EQ(1, o["1"].GetInt()); + EXPECT_EQ(1, x.Get()["1"].GetInt()); EXPECT_EQ(1, x.Get()["1"].GetInt()); Value x2; From 46dc8e9240113f53e3d9db32f66f46b8e40f89f7 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 19 Feb 2016 00:49:05 +0800 Subject: [PATCH 15/17] Add implicit constructors of GenericValue for GenercArray|Object MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also remove SetArray|Object(…) --- include/rapidjson/document.h | 36 +++++++++++++++++++++-------- test/unittest/valuetest.cpp | 44 ++++++++++++++++++++++++++++++++++-- 2 files changed, 68 insertions(+), 12 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index c90705c..520e9e1 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -481,8 +481,8 @@ struct TypeHelper { typedef typename ValueType::Array ArrayType; static bool Is(const ValueType& v) { return v.IsArray(); } static ArrayType Get(ValueType& v) { return v.GetArray(); } - static ValueType& Set(ValueType& v, ArrayType data) { return v.SetArray(data); } - static ValueType& Set(ValueType& v, ArrayType data, typename ValueType::AllocatorType&) { return v.SetArray(data); } + static ValueType& Set(ValueType& v, ArrayType data) { return v = data; } + static ValueType& Set(ValueType& v, ArrayType data, typename ValueType::AllocatorType&) { return v = data; } }; template @@ -497,8 +497,8 @@ struct TypeHelper { typedef typename ValueType::Object ObjectType; static bool Is(const ValueType& v) { return v.IsObject(); } static ObjectType Get(ValueType& v) { return v.GetObject(); } - static ValueType& Set(ValueType& v, ObjectType data) { return v.SetObject(data); } - static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { return v.SetObject(data); } + static ValueType& Set(ValueType& v, ObjectType data) { return v = data; } + static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { v = data; } }; template @@ -681,6 +681,28 @@ public: GenericValue(const std::basic_string& s, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s), allocator); } #endif + //! Constructor for Array. + /*! + \param a An array obtained by \c GetArray(). + \note \c Array is always pass-by-value. + \note the source array is moved into this value and the sourec array becomes empty. + */ + GenericValue(Array a) : data_(a.value_.data_), flags_(a.value_.flags_) { + a.value_.data_ = Data(); + a.value_.flags_ = kArrayFlag; + } + + //! Constructor for Object. + /*! + \param o An object obtained by \c GetObject(). + \note \c Object is always pass-by-value. + \note the source object is moved into this value and the sourec object becomes empty. + */ + GenericValue(Object o) : data_(o.value_.data_), flags_(o.value_.flags_) { + o.value_.data_ = Data(); + o.value_.flags_ = kObjectFlag; + } + //! Destructor. /*! Need to destruct elements of array, members of object, or copy-string. */ @@ -970,9 +992,6 @@ public: /*! \post IsObject() == true */ GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; } - //! Set this value with an object. - GenericValue& SetObject(Object& o) { return *this = o.value_; } - //! Get the number of members in the object. SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; } @@ -1431,9 +1450,6 @@ public: /*! \post IsArray == true */ GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; } - //! Set this value with an array. - GenericValue& SetArray(Array& a) { return *this = a.value_; } - //! Get the number of elements in array. SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; } diff --git a/test/unittest/valuetest.cpp b/test/unittest/valuetest.cpp index 28d84d4..db99907 100644 --- a/test/unittest/valuetest.cpp +++ b/test/unittest/valuetest.cpp @@ -1059,9 +1059,32 @@ TEST(Value, ArrayHelper) { Value x2; x2.Set(a); - EXPECT_TRUE(x.IsNull()); + EXPECT_TRUE(x.IsArray()); // IsArray() is invariant after moving. EXPECT_EQ(1, x2.Get()[0].GetInt()); } + + { + Value y(kArrayType); + y.PushBack(123, allocator); + + Value x(y.GetArray()); // Construct value form array. + EXPECT_TRUE(x.IsArray()); + EXPECT_EQ(123, x[0].GetInt()); + EXPECT_TRUE(y.IsArray()); // Invariant + EXPECT_TRUE(y.Empty()); + } + + { + Value x(kArrayType); + Value y(kArrayType); + y.PushBack(123, allocator); + x.PushBack(y.GetArray(), allocator); // Implicit constructor to convert Array to GenericValue + + EXPECT_EQ(1, x.Size()); + EXPECT_EQ(123, x[0][0].GetInt()); + EXPECT_TRUE(y.IsArray()); + EXPECT_TRUE(y.Empty()); + } } #if RAPIDJSON_HAS_CXX11_RANGE_FOR @@ -1413,9 +1436,26 @@ TEST(Value, ObjectHelper) { Value x2; x2.Set(o); - EXPECT_TRUE(x.IsNull()); + EXPECT_TRUE(x.IsObject()); // IsObject() is invariant after moving EXPECT_EQ(1, x2.Get()["1"].GetInt()); } + + { + Value x(kObjectType); + x.AddMember("a", "apple", allocator); + Value y(x.GetObject()); + EXPECT_STREQ("apple", y["a"].GetString()); + EXPECT_TRUE(x.IsObject()); // Invariant + } + + { + Value x(kObjectType); + x.AddMember("a", "apple", allocator); + Value y(kObjectType); + y.AddMember("fruits", x.GetObject(), allocator); + EXPECT_STREQ("apple", y["fruits"]["a"].GetString()); + EXPECT_TRUE(x.IsObject()); // Invariant + } } #if RAPIDJSON_HAS_CXX11_RANGE_FOR From 9f6736c2ccbf74c5fa4a0fad915f086dd3a7b5b5 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 19 Feb 2016 01:07:16 +0800 Subject: [PATCH 16/17] Add noexcept to the constructors --- include/rapidjson/document.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 520e9e1..f2dfbef 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -687,7 +687,7 @@ public: \note \c Array is always pass-by-value. \note the source array is moved into this value and the sourec array becomes empty. */ - GenericValue(Array a) : data_(a.value_.data_), flags_(a.value_.flags_) { + GenericValue(Array a) RAPIDJSON_NOEXCEPT : data_(a.value_.data_), flags_(a.value_.flags_) { a.value_.data_ = Data(); a.value_.flags_ = kArrayFlag; } @@ -698,7 +698,7 @@ public: \note \c Object is always pass-by-value. \note the source object is moved into this value and the sourec object becomes empty. */ - GenericValue(Object o) : data_(o.value_.data_), flags_(o.value_.flags_) { + GenericValue(Object o) RAPIDJSON_NOEXCEPT : data_(o.value_.data_), flags_(o.value_.flags_) { o.value_.data_ = Data(); o.value_.flags_ = kObjectFlag; } From 479a6b9f68b1f3c2103f3e61dcfc63f747cfd994 Mon Sep 17 00:00:00 2001 From: Ian Bell Date: Thu, 18 Feb 2016 19:23:07 -0700 Subject: [PATCH 17/17] Editorial changes to schema documentation Fixed up some wording to the schema documentation --- doc/schema.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/schema.md b/doc/schema.md index 4e07e9f..053fc23 100644 --- a/doc/schema.md +++ b/doc/schema.md @@ -2,17 +2,17 @@ ## Status: experimental, shall be included in v1.1 -JSON Schema is a draft standard for describing format of JSON. The schema itself is also a JSON. By validating a JSON with JSON Schema, your code can safely access the DOM without manually checking types, or whether a key exists, etc. It can also ensure that the serialized JSON conform to a specified schema. +JSON Schema is a draft standard for describing the format of JSON data. The schema itself is also JSON data. By validating a JSON structure with JSON Schema, your code can safely access the DOM without manually checking types, or whether a key exists, etc. It can also ensure that the serialized JSON conform to a specified schema. -RapidJSON implemented a JSON Schema validator for [JSON Schema Draft v4](http://json-schema.org/documentation.html). If you do not familiar with JSON Schema, you may refer to [Understanding JSON Schema](http://spacetelescope.github.io/understanding-json-schema/). +RapidJSON implemented a JSON Schema validator for [JSON Schema Draft v4](http://json-schema.org/documentation.html). If you are not familiar with JSON Schema, you may refer to [Understanding JSON Schema](http://spacetelescope.github.io/understanding-json-schema/). [TOC] ## Basic Usage -First of all, you need to parse a JSON Schema into `Document`, and then compile the `Document` into `SchemaDocument`. +First of all, you need to parse a JSON Schema into `Document`, and then compile the `Document` into a `SchemaDocument`. -Secondly, construct a `SchemaValidator` with the `SchedmaDocument`. It is similar to a `Writer` in the sense of handling SAX events. So, you can use `document.Accept(validator)` to validate a document, and then check the validity. +Secondly, construct a `SchemaValidator` with the `SchemaDocument`. It is similar to a `Writer` in the sense of handling SAX events. So, you can use `document.Accept(validator)` to validate a document, and then check the validity. ~~~cpp #include "rapidjson/schema.h" @@ -54,7 +54,7 @@ Some notes: ## Validation during parsing/serialization -Differ to most JSON Schema validator implementations, RapidJSON provides a SAX-based schema validator. Therefore, you can parse a JSON from a stream while validating it on the fly. If the validator encounters a JSON value that invalidates the supplied schema, the parsing will be terminated immediately. This design is especially useful for parsing large JSON files. +Unlike most JSON Schema validator implementations, RapidJSON provides a SAX-based schema validator. Therefore, you can parse a JSON from a stream while validating it on the fly. If the validator encounters a JSON value that invalidates the supplied schema, the parsing will be terminated immediately. This design is especially useful for parsing large JSON files. ### DOM parsing @@ -111,7 +111,7 @@ if (!reader.Parse(stream, validator)) { } ~~~ -This is exactly the method used in [schemavalidator](example/schemavalidator/schemavalidator.cpp) example. The distinct advantage is low memory usage, no matter how big the JSON was (the memory usage depends on the complexity of the schema). +This is exactly the method used in the [schemavalidator](example/schemavalidator/schemavalidator.cpp) example. The distinct advantage is low memory usage, no matter how big the JSON was (the memory usage depends on the complexity of the schema). If you need to handle the SAX events further, then you need to use the template class `GenericSchemaValidator` to set the output handler of the validator: @@ -213,7 +213,7 @@ For C++11 compiler, it is also possible to use the `std::regex` by defining `RAP ## Performance -Most C++ JSON libraries have not yet supporting JSON Schema. So we tried to evaluate the performance of RapidJSON's JSON Schema validator according to [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark), which tests 11 JavaScript libraries running on Node.js. +Most C++ JSON libraries do not yet support JSON Schema. So we tried to evaluate the performance of RapidJSON's JSON Schema validator according to [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark), which tests 11 JavaScript libraries running on Node.js. That benchmark runs validations on [JSON Schema Test Suite](https://github.com/json-schema/JSON-Schema-Test-Suite), in which some test suites and tests are excluded. We made the same benchmarking procedure in [`schematest.cpp`](test/perftest/schematest.cpp).