From 05179e28916ada5feb56d7a8f67f9964938498bc Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Thu, 3 Jul 2014 14:24:58 +0200 Subject: [PATCH 1/6] internal/meta.h: add some template meta functions * Add/RemoveConst * IsSame, IsConst, IsMoreConst * Enable/DisableIf (including helper macro) --- include/rapidjson/internal/meta.h | 71 +++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 include/rapidjson/internal/meta.h diff --git a/include/rapidjson/internal/meta.h b/include/rapidjson/internal/meta.h new file mode 100644 index 0000000..8a1e966 --- /dev/null +++ b/include/rapidjson/internal/meta.h @@ -0,0 +1,71 @@ +#ifndef RAPIDJSON_INTERNAL_META_H_ +#define RAPIDJSON_INTERNAL_META_H_ + +//@cond RAPIDJSON_INTERNAL +namespace rapidjson { +namespace internal { + +template struct IntegralC { enum { Value = N }; }; +template struct BoolType : IntegralC {}; +struct TrueType : BoolType {}; +struct FalseType : BoolType {}; + +template struct AddConst { typedef const T Type; }; +template struct RemoveConst { typedef T Type; }; +template struct RemoveConst { typedef T Type; }; + +template struct SelectIfCond; +template struct SelectIfCond { typedef T1 Type; }; +template struct SelectIfCond { typedef T2 Type; }; + +template +struct SelectIf : SelectIfCond {}; + +template +struct MaybeAddConst : SelectIfCond {}; + +template struct IsSame { enum { Value = false }; }; +template struct IsSame { enum { Value = true }; }; + +template struct IsConst { enum { Value = false }; }; +template struct IsConst { enum { Value = true }; }; + +template +struct IsMoreConst { + enum { Value = + ( IsSame< typename RemoveConst::Type, typename RemoveConst::Type>::Value + && ( IsConst::Value >= IsConst::Value ) ) + }; +}; + +template struct EnableIfCond; +template struct EnableIfCond { typedef T Type; }; +template struct EnableIfCond { /* empty */ }; + +template +struct DisableIfCond : EnableIfCond {}; + +template +struct EnableIf : EnableIfCond {}; + +template +struct DisableIf : DisableIfCond {}; + +// SFINAE helpers +struct SfinaeResultTag {}; +template struct RemoveSfinaeFptr {}; +template struct RemoveSfinaeFptr { typedef T Type; }; + +#define RAPIDJSON_REMOVEFPTR_(type) \ + typename ::rapidjson::internal::RemoveSfinaeFptr \ + < ::rapidjson::internal::SfinaeResultTag&(*) type>::Type + +#define RAPIDJSON_ENABLEIF(cond) \ + typename ::rapidjson::internal::EnableIf \ + ::Type * = NULL + +} // namespace internal +} // namespace rapidjson +//@endcond + +#endif // RAPIDJSON_INTERNAL_META_H_ From 17a8804cf3c3f99bfc1083730755ca4f4d1abd0a Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Thu, 3 Jul 2014 14:29:57 +0200 Subject: [PATCH 2/6] document.h: add GenericMemberIterator Add dedicated class-based member iterator to prepare the switch to a (safe) API change to return MemberEnd() from FindMember(). Pointer-based iterator can be kept by defining RAPIDJSON_NOMEMBERITERATORCLASS. This may be useful for platforms without a working header. --- include/rapidjson/document.h | 150 ++++++++++++++++++++++++++++++++++- 1 file changed, 147 insertions(+), 3 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index ae13c28..3017dfd 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -5,6 +5,11 @@ #include "internal/strfunc.h" #include // placement new +#ifndef RAPIDJSON_NOMEMBERITERATORCLASS +#include "internal/meta.h" +#include // std::iterator, std::random_access_iterator_tag +#endif + #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4127) // conditional expression is constant @@ -21,7 +26,7 @@ namespace rapidjson { template class GenericValue; -//! Name-value pair in an object. +//! Name-value pair in a JSON object value. /*! This class was internal to GenericValue. It used to be a inner struct. But a compiler (IBM XL C/C++ for AIX) have reported to have problem with that so it moved as a namespace scope struct. @@ -33,6 +38,145 @@ struct GenericMember { GenericValue value; //!< value of member. }; +#ifndef RAPIDJSON_NOMEMBERITERATORCLASS + +//! (Const) member iterator for a JSON object value +/*! + \tparam Const Is this a const iterator? + \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) + \tparam Allocator Allocator type for allocating memory of object, array and string. + + This class implements a Random Access Iterator for GenericMember elements + of a GenericValue, see ISO/IEC 14882:2003(E) C++ standard, 24.1 [lib.iterator.requirements]. + + \note This iterator implementation is mainly intended to avoid implicit + conversions from iterator values to \c NULL, + e.g. from GenericValue::FindMember. + + \note Define \c RAPIDJSON_NOMEMBERITERATORCLASS to fall back to a + pointer-based implementation, if your platform doesn't provide + the C++ header. + + \see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator + */ +template +class GenericMemberIterator + : public std::iterator >::Type> { + + friend class GenericValue; + template friend class GenericMemberIterator; + + typedef GenericMember PlainType; + typedef typename internal::MaybeAddConst::Type ValueType; + typedef std::iterator BaseType; + +public: + //! Iterator type itself + typedef GenericMemberIterator Type; + //! Const iterator type + typedef GenericMemberIterator ConstType; + //! Non-const iterator type + typedef GenericMemberIterator NonConstType; + + //! Pointer to (const) GenericMember + typedef typename BaseType::pointer Pointer; + //! Reference to (const) GenericMember + typedef typename BaseType::reference Reference; + //! Signed integer type (e.g. \c ptrdiff_t) + typedef typename BaseType::difference_type DifferenceType; + + //! Default constructor (singular value) + /*! Creates an iterator pointing to no element. + \note All operations, except for comparisons, are undefined on such values. + */ + GenericMemberIterator() : ptr_() {} + + //! Iterator conversions to more const + /*! + \param it (Non-const) iterator to copy from + + Allows the creation of an iterator from another GenericMemberIterator + that is "less const". Especially, creating a non-const iterator from + a const iterator are disabled: + \li const -> non-const (not ok) + \li const -> const (ok) + \li non-const -> const (ok) + \li non-const -> non-const (ok) + + \note If the \c Const template parameter is already \c false, this + constructor effectively defines a regular copy-constructor. + Otherwise, the copy constructor is implicitly defined. + */ + GenericMemberIterator(const NonConstType & it) + : ptr_( it.ptr_ ) {} + + //! @name stepping + //@{ + Type& operator++(){ ++ptr_; return *this; } + Type& operator--(){ --ptr_; return *this; } + Type operator++(int){ Type old(*this); ++ptr_; return old; } + Type operator--(int){ Type old(*this); --ptr_; return old; } + //@} + + //! @name increment/decrement + //@{ + Type operator+(DifferenceType n) const { return Type(ptr_+n); } + Type operator-(DifferenceType n) const { return Type(ptr_-n); } + + Type& operator+=(DifferenceType n) { ptr_+=n; return *this; } + Type& operator-=(DifferenceType n) { ptr_-=n; return *this; } + //@} + + //! @name relations + //@{ + bool operator==(Type that) const { return ptr_ == that.ptr_; } + bool operator!=(Type that) const { return ptr_ != that.ptr_; } + bool operator<=(Type that) const { return ptr_ <= that.ptr_; } + bool operator>=(Type that) const { return ptr_ >= that.ptr_; } + bool operator< (Type that) const { return ptr_ < that.ptr_; } + bool operator> (Type that) const { return ptr_ > that.ptr_; } + //@} + + //! @name dereference + //@{ + Reference operator*() const { return *ptr_; } + Pointer operator->() const { return ptr_; } + Reference operator[](DifferenceType n) const { return ptr_[n]; } + //@} + + //! Distance + DifferenceType operator-(Type that) const { return ptr_-that.ptr_; } + +private: + //!< Internal constructor from plain pointer + explicit GenericMemberIterator(Pointer p) : ptr_(p) {} + + Pointer ptr_; //!< raw pointer +}; + +#else // RAPIDJSON_NOMEMBERITERATORCLASS + +// class-based member iterator implementation disabled, use plain pointers + +template +struct GenericMemberIterator; + +//! non-const GenericMemberIterator +template +struct GenericMemberIterator { + //! use plain pointer as iterator type + typedef GenericMember* Type; +}; +//! const GenericMemberIterator +template +struct GenericMemberIterator { + //! use plain const pointer as iterator type + typedef const GenericMember* Type; +}; + +#endif // RAPIDJSON_NOMEMBERITERATORCLASS + /////////////////////////////////////////////////////////////////////////////// // GenericValue @@ -55,8 +199,8 @@ public: typedef Encoding EncodingType; //!< Encoding type from template parameter. typedef Allocator AllocatorType; //!< Allocator type from template parameter. typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. - typedef Member* MemberIterator; //!< Member iterator for iterating in object. - typedef const Member* ConstMemberIterator; //!< Constant member iterator for iterating in object. + typedef typename GenericMemberIterator::Type MemberIterator; //!< Member iterator for iterating in object. + typedef typename GenericMemberIterator::Type ConstMemberIterator; //!< Constant member iterator for iterating in object. typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array. typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array. From 43737ef3103de8192ede109fdfaabb87c9a97a8c Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Thu, 3 Jul 2014 14:33:56 +0200 Subject: [PATCH 3/6] GenericValue::FindMember: return MemberEnd, if member doesn't exist --- include/rapidjson/document.h | 58 +++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 3017dfd..183db67 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -420,7 +420,8 @@ public: A better approach is to use the now public FindMember(). */ GenericValue& operator[](const Ch* name) { - if (MemberIterator member = FindMember(name)) + MemberIterator member = FindMember(name); + if (member != MemberEnd()) return member->value; else { RAPIDJSON_ASSERT(false); // see above note @@ -433,7 +434,8 @@ public: // This version is faster because it does not need a StrLen(). // It can also handle string with null character. GenericValue& operator[](const GenericValue& name) { - if (Member* member = FindMember(name)) + MemberIterator member = FindMember(name); + if (member != MemberEnd()) return member->value; else { RAPIDJSON_ASSERT(false); // see above note @@ -443,37 +445,51 @@ public: } const GenericValue& operator[](const GenericValue& name) const { return const_cast(*this)[name]; } - //! Member iterators. - ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.members; } - ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.members + data_.o.size; } - MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return data_.o.members; } - MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return data_.o.members + data_.o.size; } + //! Const member iterator + /*! \pre IsObject() == true */ + ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members); } + //! Const \em past-the-end member iterator + /*! \pre IsObject() == true */ + ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members + data_.o.size); } + //! Member iterator + /*! \pre IsObject() == true */ + MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(data_.o.members); } + //! \em Past-the-end member iterator + /*! \pre IsObject() == true */ + MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(data_.o.members + data_.o.size); } //! Check whether a member exists in the object. /*! \note It is better to use FindMember() directly if you need the obtain the value as well. */ - bool HasMember(const Ch* name) const { return FindMember(name) != 0; } + bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); } // This version is faster because it does not need a StrLen(). // It can also handle string with null character. - bool HasMember(const GenericValue& name) const { return FindMember(name) != 0; } + bool HasMember(const GenericValue& name) const { return FindMember(name) != MemberEnd(); } //! Find member by name. /*! - \return Return the member if exists. Otherwise returns null pointer. + \pre IsObject() == true + \return Iterator to member, if it exists. + Otherwise returns \ref MemberEnd(). + + \note Earlier versions of Rapidjson returned a \c NULL pointer, in case + the requested member doesn't exist. For consistency with e.g. + \c std::map, this has been changed to MemberEnd() now. */ MemberIterator FindMember(const Ch* name) { RAPIDJSON_ASSERT(name); RAPIDJSON_ASSERT(IsObject()); SizeType len = internal::StrLen(name); - for (MemberIterator member = MemberBegin(); member != MemberEnd(); ++member) + MemberIterator member = MemberBegin(); + for (; member != MemberEnd(); ++member) if (member->name.data_.s.length == len && memcmp(member->name.data_.s.str, name, len * sizeof(Ch)) == 0) - return member; - - return 0; + break; + return member; } + ConstMemberIterator FindMember(const Ch* name) const { return const_cast(*this).FindMember(name); } // This version is faster because it does not need a StrLen(). @@ -482,11 +498,11 @@ public: RAPIDJSON_ASSERT(IsObject()); RAPIDJSON_ASSERT(name.IsString()); SizeType len = name.data_.s.length; - for (MemberIterator member = MemberBegin(); member != MemberEnd(); ++member) + MemberIterator member = MemberBegin(); + for ( ; member != MemberEnd(); ++member) if (member->name.data_.s.length == len && memcmp(member->name.data_.s.str, name.data_.s.str, len * sizeof(Ch)) == 0) - return member; - - return 0; + break; + return member; } ConstMemberIterator FindMember(const GenericValue& name) const { return const_cast(*this).FindMember(name); } @@ -543,7 +559,7 @@ public: */ bool RemoveMember(const Ch* name) { MemberIterator m = FindMember(name); - if (m) { + if (m != MemberEnd()) { RemoveMember(m); return true; } @@ -553,7 +569,7 @@ public: bool RemoveMember(const GenericValue& name) { MemberIterator m = FindMember(name); - if (m) { + if (m != MemberEnd()) { RemoveMember(m); return true; } @@ -572,7 +588,7 @@ public: RAPIDJSON_ASSERT(data_.o.members != 0); RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd()); - MemberIterator last = data_.o.members + (data_.o.size - 1); + MemberIterator last(data_.o.members + (data_.o.size - 1)); if (data_.o.size > 1 && m != last) { // Move the last one to this place m->name = last->name; From 86c47a6a8bf83172aff0f3442a6bde4944de7f67 Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Thu, 3 Jul 2014 14:56:43 +0200 Subject: [PATCH 4/6] document.h: move inclusion of template meta functions In order to activate the suppression of "-Weffc++" warnings in the template meta function classes (non-virtual destructor), move the inclusion of the meta-function header `internal/meta.h` after the suppression pragma. --- include/rapidjson/document.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 183db67..9639014 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -5,11 +5,6 @@ #include "internal/strfunc.h" #include // placement new -#ifndef RAPIDJSON_NOMEMBERITERATORCLASS -#include "internal/meta.h" -#include // std::iterator, std::random_access_iterator_tag -#endif - #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4127) // conditional expression is constant @@ -20,6 +15,11 @@ #pragma GCC diagnostic ignored "-Weffc++" #endif +#ifndef RAPIDJSON_NOMEMBERITERATORCLASS +#include "internal/meta.h" +#include // std::iterator, std::random_access_iterator_tag +#endif + namespace rapidjson { // Forward declaration. From 78c75de22ced477e7a42507debc79f68eb9ea411 Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Thu, 3 Jul 2014 15:04:04 +0200 Subject: [PATCH 5/6] tutorial.cpp: update for FindMember change * use MemberIterator instead of plain pointer * check against MemberEnd() instead of NULL --- example/tutorial/tutorial.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example/tutorial/tutorial.cpp b/example/tutorial/tutorial.cpp index 592543e..c0aca10 100644 --- a/example/tutorial/tutorial.cpp +++ b/example/tutorial/tutorial.cpp @@ -44,8 +44,8 @@ int main(int, char*[]) { printf("hello = %s\n", document["hello"].GetString()); // Since version 0.2, you can use single lookup to check the existing of member and its value: - Value::Member* hello = document.FindMember("hello"); - assert(hello != 0); + Value::MemberIterator hello = document.FindMember("hello"); + assert(hello != document.MemberEnd()); assert(hello->value.IsString()); assert(strcmp("world", hello->value.GetString()) == 0); (void)hello; From 58357502599702fecce49594d5291903528ebf33 Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Thu, 3 Jul 2014 15:18:01 +0200 Subject: [PATCH 6/6] GenericMemberIterator: fixup some formatting and documentation No functional changes. --- include/rapidjson/document.h | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 9639014..fe9d9ee 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -40,9 +40,9 @@ struct GenericMember { #ifndef RAPIDJSON_NOMEMBERITERATORCLASS -//! (Const) member iterator for a JSON object value +//! (Constant) member iterator for a JSON object value /*! - \tparam Const Is this a const iterator? + \tparam Const Is this a constant iterator? \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) \tparam Allocator Allocator type for allocating memory of object, array and string. @@ -74,9 +74,9 @@ class GenericMemberIterator public: //! Iterator type itself typedef GenericMemberIterator Type; - //! Const iterator type + //! Constant iterator type typedef GenericMemberIterator ConstType; - //! Non-const iterator type + //! Non-constant iterator type typedef GenericMemberIterator NonConstType; //! Pointer to (const) GenericMember @@ -97,8 +97,8 @@ public: \param it (Non-const) iterator to copy from Allows the creation of an iterator from another GenericMemberIterator - that is "less const". Especially, creating a non-const iterator from - a const iterator are disabled: + that is "less const". Especially, creating a non-constant iterator + from a constant iterator are disabled: \li const -> non-const (not ok) \li const -> const (ok) \li non-const -> const (ok) @@ -108,8 +108,7 @@ public: constructor effectively defines a regular copy-constructor. Otherwise, the copy constructor is implicitly defined. */ - GenericMemberIterator(const NonConstType & it) - : ptr_( it.ptr_ ) {} + GenericMemberIterator(const NonConstType & it) : ptr_( it.ptr_ ) {} //! @name stepping //@{ @@ -149,7 +148,7 @@ public: DifferenceType operator-(Type that) const { return ptr_-that.ptr_; } private: - //!< Internal constructor from plain pointer + //! Internal constructor from plain pointer explicit GenericMemberIterator(Pointer p) : ptr_(p) {} Pointer ptr_; //!< raw pointer