From 1634395378d886c4461e78117ecb715e1619d968 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sun, 14 Feb 2016 13:49:52 +0800 Subject: [PATCH] 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);