From 4d648fdcd8bd32826e12151c5eba29c3417cde89 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 12 Feb 2016 18:23:32 +0800 Subject: [PATCH 01/16] 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/16] 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/16] 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/16] 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/16] 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/16] 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/16] 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/16] 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/16] 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/16] 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/16] 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/16] 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/16] 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/16] 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/16] 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/16] 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; }