Add VariantAttorney

This commit is contained in:
Benoit Blanchon
2022-07-07 11:10:48 +02:00
parent c5838a876b
commit 84b7037b3e
12 changed files with 113 additions and 43 deletions

View File

@ -6,6 +6,7 @@
#include <ArduinoJson/Array/ArrayFunctions.hpp> #include <ArduinoJson/Array/ArrayFunctions.hpp>
#include <ArduinoJson/Array/ArrayIterator.hpp> #include <ArduinoJson/Array/ArrayIterator.hpp>
#include <ArduinoJson/Variant/VariantAttorney.hpp>
#include <ArduinoJson/Variant/VariantData.hpp> #include <ArduinoJson/Variant/VariantData.hpp>
// Returns the size (in bytes) of an array with n elements. // Returns the size (in bytes) of an array with n elements.
@ -105,6 +106,8 @@ class ArrayRef : public ArrayRefBase<CollectionData>,
public VariantOperators<ArrayRef> { public VariantOperators<ArrayRef> {
typedef ArrayRefBase<CollectionData> base_type; typedef ArrayRefBase<CollectionData> base_type;
friend class VariantAttorney;
public: public:
typedef ArrayIterator iterator; typedef ArrayIterator iterator;
@ -168,6 +171,7 @@ class ArrayRef : public ArrayRefBase<CollectionData>,
_data->clear(); _data->clear();
} }
protected:
MemoryPool* getPool() const { MemoryPool* getPool() const {
return _pool; return _pool;
} }
@ -185,7 +189,7 @@ class ArrayRef : public ArrayRefBase<CollectionData>,
}; };
template <> template <>
struct Converter<ArrayConstRef> { struct Converter<ArrayConstRef> : private VariantAttorney {
static void toJson(VariantConstRef src, VariantRef dst) { static void toJson(VariantConstRef src, VariantRef dst) {
variantCopyFrom(getData(dst), getData(src), getPool(dst)); variantCopyFrom(getData(dst), getData(src), getPool(dst));
} }
@ -202,7 +206,7 @@ struct Converter<ArrayConstRef> {
}; };
template <> template <>
struct Converter<ArrayRef> { struct Converter<ArrayRef> : private VariantAttorney {
static void toJson(VariantConstRef src, VariantRef dst) { static void toJson(VariantConstRef src, VariantRef dst) {
variantCopyFrom(getData(dst), getData(src), getPool(dst)); variantCopyFrom(getData(dst), getData(src), getPool(dst));
} }

View File

@ -22,6 +22,8 @@ class ElementProxy : public VariantOperators<ElementProxy<TArray> >,
public VariantTag { public VariantTag {
typedef ElementProxy<TArray> this_type; typedef ElementProxy<TArray> this_type;
friend class VariantAttorney;
public: public:
FORCE_INLINE ElementProxy(TArray array, size_t index) FORCE_INLINE ElementProxy(TArray array, size_t index)
: _array(array), _index(index) {} : _array(array), _index(index) {}
@ -160,17 +162,18 @@ class ElementProxy : public VariantOperators<ElementProxy<TArray> >,
getUpstreamElement().remove(key); getUpstreamElement().remove(key);
} }
protected:
FORCE_INLINE MemoryPool* getPool() const { FORCE_INLINE MemoryPool* getPool() const {
return _array.getPool(); return VariantAttorney::getPool(_array);
} }
FORCE_INLINE VariantData* getData() const { FORCE_INLINE VariantData* getData() const {
return variantGetElement(_array.getData(), _index); return variantGetElement(VariantAttorney::getData(_array), _index);
} }
FORCE_INLINE VariantData* getOrCreateData() const { FORCE_INLINE VariantData* getOrCreateData() const {
return variantGetOrAddElement(_array.getOrCreateData(), _index, return variantGetOrAddElement(VariantAttorney::getOrCreateData(_array),
_array.getPool()); _index, VariantAttorney::getPool(_array));
} }
private: private:

View File

@ -15,6 +15,8 @@
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
class JsonDocument : public VariantOperators<const JsonDocument&> { class JsonDocument : public VariantOperators<const JsonDocument&> {
friend class VariantAttorney;
public: public:
template <typename T> template <typename T>
T as() { T as() {
@ -268,7 +270,7 @@ class JsonDocument : public VariantOperators<const JsonDocument&> {
JsonDocument(const JsonDocument&); JsonDocument(const JsonDocument&);
JsonDocument& operator=(const JsonDocument&); JsonDocument& operator=(const JsonDocument&);
public: protected:
MemoryPool* getPool() { MemoryPool* getPool() {
return &_pool; return &_pool;
} }

View File

@ -25,6 +25,8 @@ class MemberProxy : public VariantOperators<MemberProxy<TObject, TStringRef> >,
public VariantTag { public VariantTag {
typedef MemberProxy<TObject, TStringRef> this_type; typedef MemberProxy<TObject, TStringRef> this_type;
friend class VariantAttorney;
public: public:
FORCE_INLINE MemberProxy(TObject variant, TStringRef key) FORCE_INLINE MemberProxy(TObject variant, TStringRef key)
: _object(variant), _key(key) {} : _object(variant), _key(key) {}
@ -160,17 +162,19 @@ class MemberProxy : public VariantOperators<MemberProxy<TObject, TStringRef> >,
using ArrayShortcuts<MemberProxy<TObject, TStringRef> >::add; using ArrayShortcuts<MemberProxy<TObject, TStringRef> >::add;
protected:
FORCE_INLINE MemoryPool *getPool() const { FORCE_INLINE MemoryPool *getPool() const {
return _object.getPool(); return VariantAttorney::getPool(_object);
} }
FORCE_INLINE VariantData *getData() const { FORCE_INLINE VariantData *getData() const {
return variantGetMember(_object.getData(), adaptString(_key)); return variantGetMember(VariantAttorney::getData(_object),
adaptString(_key));
} }
FORCE_INLINE VariantData *getOrCreateData() const { FORCE_INLINE VariantData *getOrCreateData() const {
return variantGetOrAddMember(_object.getOrCreateData(), _key, return variantGetOrAddMember(VariantAttorney::getOrCreateData(_object),
_object.getPool()); _key, VariantAttorney::getPool(_object));
} }
private: private:

View File

@ -40,14 +40,16 @@ template <typename TObject>
template <typename TString> template <typename TString>
inline typename enable_if<IsString<TString>::value, bool>::type inline typename enable_if<IsString<TString>::value, bool>::type
ObjectShortcuts<TObject>::containsKey(const TString& key) const { ObjectShortcuts<TObject>::containsKey(const TString& key) const {
return variantGetMember(impl()->getData(), adaptString(key)) != 0; return variantGetMember(VariantAttorney::getData(*impl()),
adaptString(key)) != 0;
} }
template <typename TObject> template <typename TObject>
template <typename TChar> template <typename TChar>
inline typename enable_if<IsString<TChar*>::value, bool>::type inline typename enable_if<IsString<TChar*>::value, bool>::type
ObjectShortcuts<TObject>::containsKey(TChar* key) const { ObjectShortcuts<TObject>::containsKey(TChar* key) const {
return variantGetMember(impl()->getData(), adaptString(key)) != 0; return variantGetMember(VariantAttorney::getData(*impl()),
adaptString(key)) != 0;
} }
template <typename TObject> template <typename TObject>

View File

@ -125,6 +125,8 @@ class ObjectRef : public ObjectRefBase<CollectionData>,
public VariantOperators<ObjectRef> { public VariantOperators<ObjectRef> {
typedef ObjectRefBase<CollectionData> base_type; typedef ObjectRefBase<CollectionData> base_type;
friend class VariantAttorney;
public: public:
typedef ObjectIterator iterator; typedef ObjectIterator iterator;
@ -188,6 +190,7 @@ class ObjectRef : public ObjectRefBase<CollectionData>,
objectRemove(_data, adaptString(key)); objectRemove(_data, adaptString(key));
} }
protected:
MemoryPool* getPool() const { MemoryPool* getPool() const {
return _pool; return _pool;
} }
@ -205,7 +208,7 @@ class ObjectRef : public ObjectRefBase<CollectionData>,
}; };
template <> template <>
struct Converter<ObjectConstRef> { struct Converter<ObjectConstRef> : private VariantAttorney {
static void toJson(VariantConstRef src, VariantRef dst) { static void toJson(VariantConstRef src, VariantRef dst) {
variantCopyFrom(getData(dst), getData(src), getPool(dst)); variantCopyFrom(getData(dst), getData(src), getPool(dst));
} }
@ -222,7 +225,7 @@ struct Converter<ObjectConstRef> {
}; };
template <> template <>
struct Converter<ObjectRef> { struct Converter<ObjectRef> : private VariantAttorney {
static void toJson(VariantConstRef src, VariantRef dst) { static void toJson(VariantConstRef src, VariantRef dst) {
variantCopyFrom(getData(dst), getData(src), getPool(dst)); variantCopyFrom(getData(dst), getData(src), getPool(dst));
} }

View File

@ -13,7 +13,7 @@ template <template <typename> class TSerializer>
size_t measure(VariantConstRef source) { size_t measure(VariantConstRef source) {
DummyWriter dp; DummyWriter dp;
TSerializer<DummyWriter> serializer(dp); TSerializer<DummyWriter> serializer(dp);
return variantAccept(getData(source), serializer); return variantAccept(VariantAttorney::getData(source), serializer);
} }
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@ -12,7 +12,7 @@ namespace ARDUINOJSON_NAMESPACE {
template <template <typename> class TSerializer, typename TWriter> template <template <typename> class TSerializer, typename TWriter>
size_t doSerialize(VariantConstRef source, TWriter writer) { size_t doSerialize(VariantConstRef source, TWriter writer) {
TSerializer<TWriter> serializer(writer); TSerializer<TWriter> serializer(writer);
return variantAccept(getData(source), serializer); return variantAccept(VariantAttorney::getData(source), serializer);
} }
template <template <typename> class TSerializer, typename TDestination> template <template <typename> class TSerializer, typename TDestination>

View File

@ -37,7 +37,8 @@ struct Converter {
template <typename T> template <typename T>
struct Converter< struct Converter<
T, typename enable_if<is_integral<T>::value && !is_same<bool, T>::value && T, typename enable_if<is_integral<T>::value && !is_same<bool, T>::value &&
!is_same<char, T>::value>::type> { !is_same<char, T>::value>::type>
: private VariantAttorney {
static void toJson(T src, VariantRef dst) { static void toJson(T src, VariantRef dst) {
VariantData* data = getData(dst); VariantData* data = getData(dst);
ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T); ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T);
@ -58,7 +59,8 @@ struct Converter<
}; };
template <typename T> template <typename T>
struct Converter<T, typename enable_if<is_enum<T>::value>::type> { struct Converter<T, typename enable_if<is_enum<T>::value>::type>
: private VariantAttorney {
static void toJson(T src, VariantRef dst) { static void toJson(T src, VariantRef dst) {
dst.set(static_cast<Integer>(src)); dst.set(static_cast<Integer>(src));
} }
@ -75,7 +77,7 @@ struct Converter<T, typename enable_if<is_enum<T>::value>::type> {
}; };
template <> template <>
struct Converter<bool> { struct Converter<bool> : private VariantAttorney {
static void toJson(bool src, VariantRef dst) { static void toJson(bool src, VariantRef dst) {
VariantData* data = getData(dst); VariantData* data = getData(dst);
if (data) if (data)
@ -94,7 +96,8 @@ struct Converter<bool> {
}; };
template <typename T> template <typename T>
struct Converter<T, typename enable_if<is_floating_point<T>::value>::type> { struct Converter<T, typename enable_if<is_floating_point<T>::value>::type>
: private VariantAttorney {
static void toJson(T src, VariantRef dst) { static void toJson(T src, VariantRef dst) {
VariantData* data = getData(dst); VariantData* data = getData(dst);
if (data) if (data)
@ -113,7 +116,7 @@ struct Converter<T, typename enable_if<is_floating_point<T>::value>::type> {
}; };
template <> template <>
struct Converter<const char*> { struct Converter<const char*> : private VariantAttorney {
static void toJson(const char* src, VariantRef dst) { static void toJson(const char* src, VariantRef dst) {
variantSetString(getData(dst), adaptString(src), getPool(dst), variantSetString(getData(dst), adaptString(src), getPool(dst),
getStringStoragePolicy(src)); getStringStoragePolicy(src));
@ -131,7 +134,7 @@ struct Converter<const char*> {
}; };
template <> template <>
struct Converter<String> { struct Converter<String> : private VariantAttorney {
static void toJson(String src, VariantRef dst) { static void toJson(String src, VariantRef dst) {
variantSetString(getData(dst), adaptString(src), getPool(dst), variantSetString(getData(dst), adaptString(src), getPool(dst),
getStringStoragePolicy(src)); getStringStoragePolicy(src));
@ -151,8 +154,8 @@ struct Converter<String> {
template <typename T> template <typename T>
inline typename enable_if<IsString<T>::value, bool>::type convertToJson( inline typename enable_if<IsString<T>::value, bool>::type convertToJson(
const T& src, VariantRef dst) { const T& src, VariantRef dst) {
VariantData* data = getData(dst); VariantData* data = VariantAttorney::getData(dst);
MemoryPool* pool = getPool(dst); MemoryPool* pool = VariantAttorney::getPool(dst);
return variantSetString(data, adaptString(src), pool, return variantSetString(data, adaptString(src), pool,
getStringStoragePolicy(src)); getStringStoragePolicy(src));
} }
@ -160,7 +163,7 @@ inline typename enable_if<IsString<T>::value, bool>::type convertToJson(
template <> template <>
struct Converter<SerializedValue<const char*> > { struct Converter<SerializedValue<const char*> > {
static void toJson(SerializedValue<const char*> src, VariantRef dst) { static void toJson(SerializedValue<const char*> src, VariantRef dst) {
VariantData* data = getData(dst); VariantData* data = VariantAttorney::getData(dst);
if (data) if (data)
data->setLinkedRaw(src); data->setLinkedRaw(src);
} }
@ -171,7 +174,8 @@ struct Converter<SerializedValue<const char*> > {
// SerializedValue<const __FlashStringHelper*> // SerializedValue<const __FlashStringHelper*>
template <typename T> template <typename T>
struct Converter<SerializedValue<T>, struct Converter<SerializedValue<T>,
typename enable_if<!is_same<const char*, T>::value>::type> { typename enable_if<!is_same<const char*, T>::value>::type>
: private VariantAttorney {
static void toJson(SerializedValue<T> src, VariantRef dst) { static void toJson(SerializedValue<T> src, VariantRef dst) {
VariantData* data = getData(dst); VariantData* data = getData(dst);
MemoryPool* pool = getPool(dst); MemoryPool* pool = getPool(dst);
@ -183,7 +187,7 @@ struct Converter<SerializedValue<T>,
#if ARDUINOJSON_HAS_NULLPTR #if ARDUINOJSON_HAS_NULLPTR
template <> template <>
struct Converter<decltype(nullptr)> { struct Converter<decltype(nullptr)> : private VariantAttorney {
static void toJson(decltype(nullptr), VariantRef dst) { static void toJson(decltype(nullptr), VariantRef dst) {
variantSetNull(getData(dst)); variantSetNull(getData(dst));
} }
@ -241,8 +245,8 @@ class MemoryPoolPrint : public Print {
}; };
inline void convertToJson(const ::Printable& src, VariantRef dst) { inline void convertToJson(const ::Printable& src, VariantRef dst) {
MemoryPool* pool = getPool(dst); MemoryPool* pool = VariantAttorney::getPool(dst);
VariantData* data = getData(dst); VariantData* data = VariantAttorney::getData(dst);
if (!pool || !data) if (!pool || !data)
return; return;
MemoryPoolPrint print(pool); MemoryPoolPrint print(pool);

View File

@ -0,0 +1,51 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2022, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Polyfills/attributes.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp>
#include <ArduinoJson/Variant/VariantTo.hpp>
#include "VariantRef.hpp"
namespace ARDUINOJSON_NAMESPACE {
// Grants access to the internal variant API
class VariantAttorney {
// Tells whether getData() returns a const pointer
template <typename TClient>
struct ResultOfGetData {
protected: // <- to avoid GCC's "all member functions in class are private"
typedef char Yes[1];
typedef char No[2];
static Yes &probe(const VariantData *);
static No &probe(VariantData *);
static TClient &client;
public:
typedef typename conditional<sizeof(probe(client.getData())) == sizeof(Yes),
const VariantData *, VariantData *>::type type;
};
public:
template <typename TClient>
FORCE_INLINE static MemoryPool *getPool(TClient &client) {
return client.getPool();
}
template <typename TClient>
FORCE_INLINE static typename ResultOfGetData<TClient>::type getData(
TClient &client) {
return client.getData();
}
template <typename TClient>
FORCE_INLINE static VariantData *getOrCreateData(TClient &client) {
return client.getOrCreateData();
}
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -180,7 +180,8 @@ struct VariantComparer : ComparerBase {
private: private:
template <typename TComparer> template <typename TComparer>
CompareResult accept(TComparer &comparer) { CompareResult accept(TComparer &comparer) {
CompareResult reversedResult = variantAccept(getData(rhs), comparer); CompareResult reversedResult =
variantAccept(VariantAttorney::getData(rhs), comparer);
switch (reversedResult) { switch (reversedResult) {
case COMPARE_RESULT_GREATER: case COMPARE_RESULT_GREATER:
return COMPARE_RESULT_LESS; return COMPARE_RESULT_LESS;
@ -203,7 +204,7 @@ struct Comparer<
template <typename T> template <typename T>
CompareResult compare(VariantConstRef lhs, const T &rhs) { CompareResult compare(VariantConstRef lhs, const T &rhs) {
Comparer<T> comparer(rhs); Comparer<T> comparer(rhs);
return variantAccept(getData(lhs), comparer); return variantAccept(VariantAttorney::getData(lhs), comparer);
} }
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@ -11,6 +11,7 @@
#include <ArduinoJson/Polyfills/type_traits.hpp> #include <ArduinoJson/Polyfills/type_traits.hpp>
#include <ArduinoJson/Strings/StringAdapters.hpp> #include <ArduinoJson/Strings/StringAdapters.hpp>
#include <ArduinoJson/Variant/Converter.hpp> #include <ArduinoJson/Variant/Converter.hpp>
#include <ArduinoJson/Variant/VariantAttorney.hpp>
#include <ArduinoJson/Variant/VariantFunctions.hpp> #include <ArduinoJson/Variant/VariantFunctions.hpp>
#include <ArduinoJson/Variant/VariantOperators.hpp> #include <ArduinoJson/Variant/VariantOperators.hpp>
#include <ArduinoJson/Variant/VariantRef.hpp> #include <ArduinoJson/Variant/VariantRef.hpp>
@ -50,10 +51,6 @@ class VariantRefBase : public VariantTag {
protected: protected:
VariantRefBase(TData *data) : _data(data) {} VariantRefBase(TData *data) : _data(data) {}
TData *_data; TData *_data;
friend TData *getData(const VariantRefBase &variant) {
return variant._data;
}
}; };
class VariantConstRef : public VariantRefBase<const VariantData>, class VariantConstRef : public VariantRefBase<const VariantData>,
@ -61,6 +58,8 @@ class VariantConstRef : public VariantRefBase<const VariantData>,
public VariantShortcuts<VariantConstRef> { public VariantShortcuts<VariantConstRef> {
typedef VariantRefBase<const VariantData> base_type; typedef VariantRefBase<const VariantData> base_type;
friend class VariantAttorney;
public: public:
VariantConstRef() : base_type(0) {} VariantConstRef() : base_type(0) {}
explicit VariantConstRef(const VariantData *data) : base_type(data) {} explicit VariantConstRef(const VariantData *data) : base_type(data) {}
@ -139,6 +138,7 @@ class VariantConstRef : public VariantRefBase<const VariantData>,
return VariantConstRef(variantGetMember(_data, adaptString(key))); return VariantConstRef(variantGetMember(_data, adaptString(key)));
} }
protected:
const VariantData *getData() const { const VariantData *getData() const {
return _data; return _data;
} }
@ -285,7 +285,7 @@ class VariantRef : public VariantRefBase<VariantData>,
inline void shallowCopy(VariantConstRef target) { inline void shallowCopy(VariantConstRef target) {
if (!_data) if (!_data)
return; return;
const VariantData *targetData = target.getData(); const VariantData *targetData = VariantAttorney::getData(target);
if (targetData) if (targetData)
*_data = *targetData; *_data = *targetData;
else else
@ -306,14 +306,10 @@ class VariantRef : public VariantRefBase<VariantData>,
private: private:
MemoryPool *_pool; MemoryPool *_pool;
friend MemoryPool *getPool(const VariantRef &variant) {
return variant._pool;
}
}; };
template <> template <>
struct Converter<VariantRef> { struct Converter<VariantRef> : private VariantAttorney {
static void toJson(VariantRef src, VariantRef dst) { static void toJson(VariantRef src, VariantRef dst) {
variantCopyFrom(getData(dst), getData(src), getPool(dst)); variantCopyFrom(getData(dst), getData(src), getPool(dst));
} }
@ -336,7 +332,7 @@ struct Converter<VariantRef> {
}; };
template <> template <>
struct Converter<VariantConstRef> { struct Converter<VariantConstRef> : private VariantAttorney {
static void toJson(VariantConstRef src, VariantRef dst) { static void toJson(VariantConstRef src, VariantRef dst) {
variantCopyFrom(getData(dst), getData(src), getPool(dst)); variantCopyFrom(getData(dst), getData(src), getPool(dst));
} }