From 0f85a55cac36444ee64fa7d1b7d2f3cc3ef09ce6 Mon Sep 17 00:00:00 2001 From: Benoit Blanchon Date: Sat, 26 Nov 2022 18:34:25 +0100 Subject: [PATCH] Implement `VariantRefBase` with a CRTP --- CHANGELOG.md | 1 - extras/tests/JsonDocument/ElementProxy.cpp | 4 +- extras/tests/JsonDocument/MemberProxy.cpp | 5 +- extras/tests/Misc/TypeTraits.cpp | 9 ++-- src/ArduinoJson/Array/ArrayImpl.hpp | 17 ++++--- src/ArduinoJson/Array/ArrayRef.hpp | 6 +-- src/ArduinoJson/Array/ElementProxy.hpp | 36 +++++++++++---- src/ArduinoJson/Document/JsonDocument.hpp | 22 ++++----- src/ArduinoJson/Object/MemberProxy.hpp | 36 +++++++++++---- src/ArduinoJson/Object/ObjectImpl.hpp | 53 ++++++++++------------ src/ArduinoJson/Object/ObjectRef.hpp | 16 +++---- src/ArduinoJson/Variant/VariantImpl.hpp | 33 +++++++------- src/ArduinoJson/Variant/VariantProxy.hpp | 51 --------------------- src/ArduinoJson/Variant/VariantRef.hpp | 21 +++------ src/ArduinoJson/Variant/VariantRefBase.hpp | 42 ++++++++--------- 15 files changed, 153 insertions(+), 199 deletions(-) delete mode 100644 src/ArduinoJson/Variant/VariantProxy.hpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fec6b86..a74e8c23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,6 @@ HEAD * Fix comparison operators for `JsonArray`, `JsonArrayConst`, `JsonObject`, and `JsonObjectConst` * Fix lax parsing of `true`, `false`, and `null` (issue #1781) * Remove undocumented `accept()` functions -* Remove undocumented `ElementProxy` and `MemberProxy` classes * Rename `addElement()` to `add()` * Remove `getElement()`, `getOrAddElement()`, `getMember()`, and `getOrAddMember()` * Remove undocumented `JsonDocument::data()` and `JsonDocument::memoryPool()` diff --git a/extras/tests/JsonDocument/ElementProxy.cpp b/extras/tests/JsonDocument/ElementProxy.cpp index 62dcc091..eafc85f3 100644 --- a/extras/tests/JsonDocument/ElementProxy.cpp +++ b/extras/tests/JsonDocument/ElementProxy.cpp @@ -5,9 +5,7 @@ #include #include -using namespace ARDUINOJSON_NAMESPACE; - -typedef VariantProxy > ElementProxy; +typedef ARDUINOJSON_NAMESPACE::ElementProxy ElementProxy; TEST_CASE("ElementProxy::add()") { DynamicJsonDocument doc(4096); diff --git a/extras/tests/JsonDocument/MemberProxy.cpp b/extras/tests/JsonDocument/MemberProxy.cpp index 58958a1e..ed3e32bf 100644 --- a/extras/tests/JsonDocument/MemberProxy.cpp +++ b/extras/tests/JsonDocument/MemberProxy.cpp @@ -5,9 +5,8 @@ #include #include -using namespace ARDUINOJSON_NAMESPACE; - -typedef VariantProxy > MemberProxy; +typedef ARDUINOJSON_NAMESPACE::MemberProxy + MemberProxy; TEST_CASE("MemberProxy::add()") { DynamicJsonDocument doc(4096); diff --git a/extras/tests/Misc/TypeTraits.cpp b/extras/tests/Misc/TypeTraits.cpp index 9002e6b4..5f861afa 100644 --- a/extras/tests/Misc/TypeTraits.cpp +++ b/extras/tests/Misc/TypeTraits.cpp @@ -184,13 +184,12 @@ TEST_CASE("Polyfills/type_traits") { CHECK((is_convertible::value == true)); CHECK((is_convertible::value == true)); CHECK((is_convertible::value == true)); - CHECK((is_convertible >, - JsonVariantConst>::value == true)); + CHECK((is_convertible, JsonVariantConst>::value == + true)); CHECK((is_convertible::value == true)); CHECK((is_convertible::value == true)); - CHECK( - (is_convertible >, - JsonVariantConst>::value == true)); + CHECK((is_convertible, + JsonVariantConst>::value == true)); CHECK((is_convertible::value == true)); CHECK( (is_convertible::value == true)); diff --git a/src/ArduinoJson/Array/ArrayImpl.hpp b/src/ArduinoJson/Array/ArrayImpl.hpp index c8fb8279..646820ef 100644 --- a/src/ArduinoJson/Array/ArrayImpl.hpp +++ b/src/ArduinoJson/Array/ArrayImpl.hpp @@ -13,21 +13,20 @@ inline ObjectRef ArrayRef::createNestedObject() const { return add().to(); } -template -inline ArrayRef VariantRefBase::createNestedArray() const { +template +inline ArrayRef VariantRefBase::createNestedArray() const { return add().template to(); } -template -inline ObjectRef VariantRefBase::createNestedObject() const { +template +inline ObjectRef VariantRefBase::createNestedObject() const { return add().template to(); } -template -inline VariantProxy > > -VariantRefBase::operator[](size_t index) const { - return VariantProxy > >( - ElementDataSource >(*this, index)); +template +inline ElementProxy VariantRefBase::operator[]( + size_t index) const { + return ElementProxy(derived(), index); } } // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Array/ArrayRef.hpp b/src/ArduinoJson/Array/ArrayRef.hpp index 4d73a989..e25a6bd5 100644 --- a/src/ArduinoJson/Array/ArrayRef.hpp +++ b/src/ArduinoJson/Array/ArrayRef.hpp @@ -184,10 +184,8 @@ class ArrayRef : public ArrayRefBase, } // Returns the element at specified index if the variant is an array. - FORCE_INLINE VariantProxy > operator[]( - size_t index) const { - return VariantProxy >( - ElementDataSource(*this, index)); + FORCE_INLINE ElementProxy operator[](size_t index) const { + return ElementProxy(*this, index); } FORCE_INLINE ObjectRef createNestedObject() const; diff --git a/src/ArduinoJson/Array/ElementProxy.hpp b/src/ArduinoJson/Array/ElementProxy.hpp index 0995b310..5607b466 100644 --- a/src/ArduinoJson/Array/ElementProxy.hpp +++ b/src/ArduinoJson/Array/ElementProxy.hpp @@ -4,16 +4,40 @@ #pragma once -#include +#include namespace ARDUINOJSON_NAMESPACE { template -class ElementDataSource { +class ElementProxy : public VariantRefBase >, + public VariantOperators > { + friend class VariantAttorney; + public: - ElementDataSource(TUpstream upstream, size_t index) + ElementProxy(TUpstream upstream, size_t index) : _upstream(upstream), _index(index) {} + ElementProxy(const ElementProxy& src) + : _upstream(src._upstream), _index(src._index) {} + + FORCE_INLINE ElementProxy& operator=(const ElementProxy& src) { + this->set(src); + return *this; + } + + template + FORCE_INLINE ElementProxy& operator=(const T& src) { + this->set(src); + return *this; + } + + template + FORCE_INLINE ElementProxy& operator=(T* src) { + this->set(src); + return *this; + } + + private: FORCE_INLINE MemoryPool* getPool() const { return VariantAttorney::getPool(_upstream); } @@ -27,12 +51,6 @@ class ElementDataSource { _index, VariantAttorney::getPool(_upstream)); } - private: -#if defined _MSC_VER && _MSC_VER <= 1800 // Visual Studio 2013 or below - // Prevent "assignment operator could not be generated" - ElementDataSource& operator=(const ElementDataSource&); -#endif - TUpstream _upstream; size_t _index; }; diff --git a/src/ArduinoJson/Document/JsonDocument.hpp b/src/ArduinoJson/Document/JsonDocument.hpp index 55a96240..371ea379 100644 --- a/src/ArduinoJson/Document/JsonDocument.hpp +++ b/src/ArduinoJson/Document/JsonDocument.hpp @@ -139,24 +139,20 @@ class JsonDocument : public VariantOperators { // operator[](const std::string&) // operator[](const String&) template - FORCE_INLINE typename enable_if< - IsString::value, - VariantProxy > >::type + FORCE_INLINE typename enable_if::value, + MemberProxy >::type operator[](const TString& key) { - return VariantProxy >( - MemberDataSource(*this, key)); + return MemberProxy(*this, key); } // operator[](char*) // operator[](const char*) // operator[](const __FlashStringHelper*) template - FORCE_INLINE typename enable_if< - IsString::value, - VariantProxy > >::type + FORCE_INLINE typename enable_if::value, + MemberProxy >::type operator[](TChar* key) { - return VariantProxy >( - MemberDataSource(*this, key)); + return MemberProxy(*this, key); } // operator[](const std::string&) const @@ -178,10 +174,8 @@ class JsonDocument : public VariantOperators { return VariantConstRef(_data.getMember(adaptString(key))); } - FORCE_INLINE VariantProxy > operator[]( - size_t index) { - return VariantProxy >( - ElementDataSource(*this, index)); + FORCE_INLINE ElementProxy operator[](size_t index) { + return ElementProxy(*this, index); } FORCE_INLINE VariantConstRef operator[](size_t index) const { diff --git a/src/ArduinoJson/Object/MemberProxy.hpp b/src/ArduinoJson/Object/MemberProxy.hpp index e239d402..63c8bee9 100644 --- a/src/ArduinoJson/Object/MemberProxy.hpp +++ b/src/ArduinoJson/Object/MemberProxy.hpp @@ -4,16 +4,41 @@ #pragma once -#include +#include namespace ARDUINOJSON_NAMESPACE { template -class MemberDataSource { +class MemberProxy + : public VariantRefBase >, + public VariantOperators > { + friend class VariantAttorney; + public: - FORCE_INLINE MemberDataSource(TUpstream upstream, TStringRef key) + FORCE_INLINE MemberProxy(TUpstream upstream, TStringRef key) : _upstream(upstream), _key(key) {} + MemberProxy(const MemberProxy& src) + : _upstream(src._upstream), _key(src._key) {} + + FORCE_INLINE MemberProxy& operator=(const MemberProxy& src) { + this->set(src); + return *this; + } + + template + FORCE_INLINE MemberProxy& operator=(const T& src) { + this->set(src); + return *this; + } + + template + FORCE_INLINE MemberProxy& operator=(T* src) { + this->set(src); + return *this; + } + + private: FORCE_INLINE MemoryPool* getPool() const { return VariantAttorney::getPool(_upstream); } @@ -30,11 +55,6 @@ class MemberDataSource { } private: -#if defined _MSC_VER && _MSC_VER <= 1800 // Visual Studio 2013 or below - // Prevent "assignment operator could not be generated" - MemberDataSource& operator=(const MemberDataSource&); -#endif - TUpstream _upstream; TStringRef _key; }; diff --git a/src/ArduinoJson/Object/ObjectImpl.hpp b/src/ArduinoJson/Object/ObjectImpl.hpp index 9dd6f533..15d86539 100644 --- a/src/ArduinoJson/Object/ObjectImpl.hpp +++ b/src/ArduinoJson/Object/ObjectImpl.hpp @@ -19,68 +19,63 @@ inline ArrayRef ObjectRef::createNestedArray(TChar* key) const { return operator[](key).template to(); } -template +template template -inline ArrayRef VariantRefBase::createNestedArray( +inline ArrayRef VariantRefBase::createNestedArray( const TString& key) const { return operator[](key).template to(); } -template +template template -inline ArrayRef VariantRefBase::createNestedArray( - TChar* key) const { +inline ArrayRef VariantRefBase::createNestedArray(TChar* key) const { return operator[](key).template to(); } -template +template template -inline ObjectRef VariantRefBase::createNestedObject( +inline ObjectRef VariantRefBase::createNestedObject( const TString& key) const { return operator[](key).template to(); } -template +template template -inline ObjectRef VariantRefBase::createNestedObject( +inline ObjectRef VariantRefBase::createNestedObject( TChar* key) const { return operator[](key).template to(); } -template +template template inline typename enable_if::value, bool>::type -VariantRefBase::containsKey(const TString& key) const { - return variantGetMember(VariantAttorney::getData(*this), adaptString(key)) != - 0; +VariantRefBase::containsKey(const TString& key) const { + return variantGetMember(VariantAttorney::getData(derived()), + adaptString(key)) != 0; } -template +template template inline typename enable_if::value, bool>::type -VariantRefBase::containsKey(TChar* key) const { - return variantGetMember(VariantAttorney::getData(*this), adaptString(key)) != - 0; +VariantRefBase::containsKey(TChar* key) const { + return variantGetMember(VariantAttorney::getData(derived()), + adaptString(key)) != 0; } -template +template template inline typename enable_if::value, - VariantProxy, TString*> > >::type -VariantRefBase::operator[](TString* key) const { - return VariantProxy >( - MemberDataSource(*this, key)); + MemberProxy >::type +VariantRefBase::operator[](TString* key) const { + return MemberProxy(derived(), key); } -template +template template inline typename enable_if::value, - VariantProxy, TString> > >::type -VariantRefBase::operator[](const TString& key) const { - return VariantProxy >( - MemberDataSource(*this, key)); + MemberProxy >::type +VariantRefBase::operator[](const TString& key) const { + return MemberProxy(derived(), key); } } // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Object/ObjectRef.hpp b/src/ArduinoJson/Object/ObjectRef.hpp index 56ff6c23..59f94c4f 100644 --- a/src/ArduinoJson/Object/ObjectRef.hpp +++ b/src/ArduinoJson/Object/ObjectRef.hpp @@ -176,21 +176,17 @@ class ObjectRef : public ObjectRefBase, } template - FORCE_INLINE typename enable_if< - IsString::value, - VariantProxy > >::type + FORCE_INLINE typename enable_if::value, + MemberProxy >::type operator[](const TString& key) const { - return VariantProxy >( - MemberDataSource(*this, key)); + return MemberProxy(*this, key); } template - FORCE_INLINE typename enable_if< - IsString::value, - VariantProxy > >::type + FORCE_INLINE typename enable_if::value, + MemberProxy >::type operator[](TChar* key) const { - return VariantProxy >( - MemberDataSource(*this, key)); + return MemberProxy(*this, key); } FORCE_INLINE void remove(iterator it) const { diff --git a/src/ArduinoJson/Variant/VariantImpl.hpp b/src/ArduinoJson/Variant/VariantImpl.hpp index 511fc274..10ab52cb 100644 --- a/src/ArduinoJson/Variant/VariantImpl.hpp +++ b/src/ArduinoJson/Variant/VariantImpl.hpp @@ -104,52 +104,51 @@ inline bool VariantData::copyFrom(const VariantData& src, MemoryPool* pool) { } } -template -inline VariantRef VariantRefBase::add() const { +template +inline VariantRef VariantRefBase::add() const { return VariantRef(getPool(), variantAddElement(getOrCreateData(), getPool())); } -template -inline VariantRef VariantRefBase::getVariant() const { +template +inline VariantRef VariantRefBase::getVariant() const { return VariantRef(getPool(), getData()); } -template -inline VariantRef VariantRefBase::getOrCreateVariant() const { +template +inline VariantRef VariantRefBase::getOrCreateVariant() const { return VariantRef(getPool(), getOrCreateData()); } -template +template template inline typename enable_if::value, ArrayRef>::type -VariantRefBase::to() const { +VariantRefBase::to() const { return ArrayRef(getPool(), variantToArray(getOrCreateData())); } -template +template template typename enable_if::value, ObjectRef>::type -VariantRefBase::to() const { +VariantRefBase::to() const { return ObjectRef(getPool(), variantToObject(getOrCreateData())); } -template +template template typename enable_if::value, VariantRef>::type -VariantRefBase::to() const { +VariantRefBase::to() const { variantSetNull(getOrCreateData()); return *this; } // Out of class definition to avoid #1560 -template -inline bool VariantRefBase::set(char value) const { +template +inline bool VariantRefBase::set(char value) const { return set(static_cast(value)); } -template -inline void convertToJson(const VariantRefBase& src, - VariantRef dst) { +template +inline void convertToJson(const VariantRefBase& src, VariantRef dst) { dst.set(src.template as()); } diff --git a/src/ArduinoJson/Variant/VariantProxy.hpp b/src/ArduinoJson/Variant/VariantProxy.hpp deleted file mode 100644 index 22d260f9..00000000 --- a/src/ArduinoJson/Variant/VariantProxy.hpp +++ /dev/null @@ -1,51 +0,0 @@ -// ArduinoJson - https://arduinojson.org -// Copyright © 2014-2022, Benoit BLANCHON -// MIT License - -#pragma once - -#include -#include - -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable : 4522) -#endif - -namespace ARDUINOJSON_NAMESPACE { - -template -class VariantProxy : public VariantRefBase, - public VariantOperators > { - public: - explicit FORCE_INLINE VariantProxy(TDataSource source) - : VariantRefBase(source) {} - - // Copy-constructor required because of user-defined copy-assignment - // operator - FORCE_INLINE VariantProxy(const VariantProxy& src) - : VariantRefBase(src) {} - - FORCE_INLINE VariantProxy& operator=(const VariantProxy& src) { - this->set(src); - return *this; - } - - template - FORCE_INLINE VariantProxy& operator=(const T& src) { - this->set(src); - return *this; - } - - template - FORCE_INLINE VariantProxy& operator=(T* src) { - this->set(src); - return *this; - } -}; - -} // namespace ARDUINOJSON_NAMESPACE - -#ifdef _MSC_VER -# pragma warning(pop) -#endif diff --git a/src/ArduinoJson/Variant/VariantRef.hpp b/src/ArduinoJson/Variant/VariantRef.hpp index 4f9005a6..d1df1caf 100644 --- a/src/ArduinoJson/Variant/VariantRef.hpp +++ b/src/ArduinoJson/Variant/VariantRef.hpp @@ -8,13 +8,16 @@ namespace ARDUINOJSON_NAMESPACE { -class VariantDataSource { +class VariantRef : public VariantRefBase, + public VariantOperators { + friend class VariantAttorney; + public: - VariantDataSource() : _data(0), _pool(0) {} + VariantRef() : _data(0), _pool(0) {} - VariantDataSource(MemoryPool* pool, VariantData* data) - : _data(data), _pool(pool) {} + VariantRef(MemoryPool* pool, VariantData* data) : _data(data), _pool(pool) {} + private: FORCE_INLINE MemoryPool* getPool() const { return _pool; } @@ -27,20 +30,10 @@ class VariantDataSource { return _data; } - private: VariantData* _data; MemoryPool* _pool; }; -class VariantRef : public VariantRefBase, - public VariantOperators { - public: - VariantRef() : VariantRefBase(VariantDataSource()) {} - - VariantRef(MemoryPool* pool, VariantData* data) - : VariantRefBase(VariantDataSource(pool, data)) {} -}; - template <> struct Converter : private VariantAttorney { static void toJson(VariantRef src, VariantRef dst) { diff --git a/src/ArduinoJson/Variant/VariantRefBase.hpp b/src/ArduinoJson/Variant/VariantRefBase.hpp index 4515ae82..47064eb0 100644 --- a/src/ArduinoJson/Variant/VariantRefBase.hpp +++ b/src/ArduinoJson/Variant/VariantRefBase.hpp @@ -15,21 +15,16 @@ namespace ARDUINOJSON_NAMESPACE { class VariantRef; template -class ElementDataSource; +class ElementProxy; template -class MemberDataSource; +class MemberProxy; -template -class VariantProxy; - -template +template class VariantRefBase : public VariantTag { friend class VariantAttorney; public: - explicit FORCE_INLINE VariantRefBase(TDataSource source) : _source(source) {} - FORCE_INLINE void clear() const { variantSetNull(getData()); } @@ -206,8 +201,7 @@ class VariantRefBase : public VariantTag { FORCE_INLINE ArrayRef createNestedArray() const; FORCE_INLINE ObjectRef createNestedObject() const; - FORCE_INLINE VariantProxy > operator[]( - size_t index) const; + FORCE_INLINE ElementProxy operator[](size_t index) const; template FORCE_INLINE typename enable_if::value, bool>::type @@ -218,15 +212,13 @@ class VariantRefBase : public VariantTag { containsKey(TChar* key) const; template - FORCE_INLINE typename enable_if< - IsString::value, - VariantProxy > >::type + FORCE_INLINE typename enable_if::value, + MemberProxy >::type operator[](const TString& key) const; template - FORCE_INLINE typename enable_if< - IsString::value, - VariantProxy > >::type + FORCE_INLINE typename enable_if::value, + MemberProxy >::type operator[](TChar* key) const; template @@ -241,17 +233,25 @@ class VariantRefBase : public VariantTag { template ObjectRef createNestedObject(TChar* key) const; - protected: + private: + TDerived& derived() { + return static_cast(*this); + } + + const TDerived& derived() const { + return static_cast(*this); + } + FORCE_INLINE MemoryPool* getPool() const { - return _source.getPool(); + return VariantAttorney::getPool(derived()); } FORCE_INLINE VariantData* getData() const { - return _source.getData(); + return VariantAttorney::getData(derived()); } FORCE_INLINE VariantData* getOrCreateData() const { - return _source.getOrCreateData(); + return VariantAttorney::getOrCreateData(derived()); } private: @@ -262,8 +262,6 @@ class VariantRefBase : public VariantTag { } FORCE_INLINE VariantRef getOrCreateVariant() const; - - TDataSource _source; }; } // namespace ARDUINOJSON_NAMESPACE