Add JsonVariant::link() (resolves #1343)

This commit is contained in:
Benoit Blanchon
2022-04-27 15:06:58 +02:00
parent 5577d18377
commit 3d6c328a4f
35 changed files with 649 additions and 51 deletions

View File

@ -211,7 +211,7 @@ struct Converter<ArrayConstRef> {
static bool checkJson(VariantConstRef src) {
const VariantData* data = getData(src);
return data && data->isArray();
return data && data->resolve()->isArray();
}
};

View File

@ -109,6 +109,10 @@ class ElementProxy : public VariantOperators<ElementProxy<TArray> >,
return getOrAddUpstreamElement().template to<T>();
}
FORCE_INLINE void link(VariantConstRef value) const {
getOrAddUpstreamElement().link(value);
}
// Replaces the value
//
// bool set(const TValue&)

View File

@ -68,7 +68,7 @@ class JsonDocument : public Visitable,
}
size_t size() const {
return _data.size();
return _data.resolve()->size();
}
bool set(const JsonDocument& src) {

View File

@ -25,7 +25,7 @@ class JsonSerializer : public Visitor<size_t> {
VariantSlot *slot = array.head();
while (slot != 0) {
slot->data()->accept(*this);
slot->data()->resolve()->accept(*this);
slot = slot->next();
if (slot == 0)
@ -46,7 +46,7 @@ class JsonSerializer : public Visitor<size_t> {
while (slot != 0) {
_formatter.writeString(slot->key());
write(':');
slot->data()->accept(*this);
slot->data()->resolve()->accept(*this);
slot = slot->next();
if (slot == 0)

View File

@ -25,7 +25,7 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
_nesting++;
while (slot != 0) {
indent();
slot->data()->accept(*this);
slot->data()->resolve()->accept(*this);
slot = slot->next();
base::write(slot ? ",\r\n" : "\r\n");
@ -48,7 +48,7 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
indent();
base::visitString(slot->key());
base::write(": ");
slot->data()->accept(*this);
slot->data()->resolve()->accept(*this);
slot = slot->next();
base::write(slot ? ",\r\n" : "\r\n");

View File

@ -56,7 +56,7 @@ class MsgPackSerializer : public Visitor<size_t> {
writeInteger(uint32_t(n));
}
for (VariantSlot* slot = array.head(); slot; slot = slot->next()) {
slot->data()->accept(*this);
slot->data()->resolve()->accept(*this);
}
return bytesWritten();
}
@ -74,7 +74,7 @@ class MsgPackSerializer : public Visitor<size_t> {
}
for (VariantSlot* slot = object.head(); slot; slot = slot->next()) {
visitString(slot->key());
slot->data()->accept(*this);
slot->data()->resolve()->accept(*this);
}
return bytesWritten();
}

View File

@ -135,6 +135,10 @@ class MemberProxy : public VariantOperators<MemberProxy<TObject, TStringRef> >,
getUpstreamMember().remove(key);
}
FORCE_INLINE void link(VariantConstRef value) {
getOrAddUpstreamMember().link(value);
}
template <typename TValue>
FORCE_INLINE typename VariantTo<TValue>::type to() {
return getOrAddUpstreamMember().template to<TValue>();

View File

@ -278,7 +278,7 @@ struct Converter<ObjectConstRef> {
static bool checkJson(VariantConstRef src) {
const VariantData* data = getData(src);
return data && data->isObject();
return data && data->resolve()->isObject();
}
};

View File

@ -48,12 +48,12 @@ struct Converter<
static T fromJson(VariantConstRef src) {
ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T);
const VariantData* data = getData(src);
return data ? data->asIntegral<T>() : T();
return data ? data->resolve()->asIntegral<T>() : T();
}
static bool checkJson(VariantConstRef src) {
const VariantData* data = getData(src);
return data && data->isInteger<T>();
return data && data->resolve()->isInteger<T>();
}
};
@ -65,12 +65,12 @@ struct Converter<T, typename enable_if<is_enum<T>::value>::type> {
static T fromJson(VariantConstRef src) {
const VariantData* data = getData(src);
return data ? static_cast<T>(data->asIntegral<int>()) : T();
return data ? static_cast<T>(data->resolve()->asIntegral<int>()) : T();
}
static bool checkJson(VariantConstRef src) {
const VariantData* data = getData(src);
return data && data->isInteger<int>();
return data && data->resolve()->isInteger<int>();
}
};
@ -84,12 +84,12 @@ struct Converter<bool> {
static bool fromJson(VariantConstRef src) {
const VariantData* data = getData(src);
return data ? data->asBoolean() : false;
return data ? data->resolve()->asBoolean() : false;
}
static bool checkJson(VariantConstRef src) {
const VariantData* data = getData(src);
return data && data->isBoolean();
return data && data->resolve()->isBoolean();
}
};
@ -103,12 +103,12 @@ struct Converter<T, typename enable_if<is_floating_point<T>::value>::type> {
static T fromJson(VariantConstRef src) {
const VariantData* data = getData(src);
return data ? data->asFloat<T>() : false;
return data ? data->resolve()->asFloat<T>() : 0;
}
static bool checkJson(VariantConstRef src) {
const VariantData* data = getData(src);
return data && data->isFloat();
return data && data->resolve()->isFloat();
}
};
@ -121,12 +121,12 @@ struct Converter<const char*> {
static const char* fromJson(VariantConstRef src) {
const VariantData* data = getData(src);
return data ? data->asString().c_str() : 0;
return data ? data->resolve()->asString().c_str() : 0;
}
static bool checkJson(VariantConstRef src) {
const VariantData* data = getData(src);
return data && data->isString();
return data && data->resolve()->isString();
}
};
@ -139,12 +139,12 @@ struct Converter<String> {
static String fromJson(VariantConstRef src) {
const VariantData* data = getData(src);
return data ? data->asString() : 0;
return data ? data->resolve()->asString() : 0;
}
static bool checkJson(VariantConstRef src) {
const VariantData* data = getData(src);
return data && data->isString();
return data && data->resolve()->isString();
}
};
@ -192,7 +192,7 @@ struct Converter<decltype(nullptr)> {
}
static bool checkJson(VariantConstRef src) {
const VariantData* data = getData(src);
return data == 0 || data->isNull();
return data == 0 || data->resolve()->isNull();
}
};

View File

@ -31,6 +31,8 @@ enum {
VALUE_IS_SIGNED_INTEGER = 0x0A,
VALUE_IS_FLOAT = 0x0C,
VALUE_IS_POINTER = 0x10,
COLLECTION_MASK = 0x60,
VALUE_IS_OBJECT = 0x20,
VALUE_IS_ARRAY = 0x40,
@ -49,6 +51,7 @@ union VariantContent {
UInt asUnsignedInteger;
Integer asSignedInteger;
CollectionData asCollection;
const class VariantData *asPointer;
struct {
const char *data;
size_t size;

View File

@ -83,6 +83,12 @@ class VariantData {
bool asBoolean() const;
const VariantData *resolve() const {
if (isPointer())
return _content.asPointer->resolve();
return this;
}
CollectionData *asArray() {
return isArray() ? &_content.asCollection : 0;
}
@ -117,6 +123,10 @@ class VariantData {
return (_flags & COLLECTION_MASK) != 0;
}
bool isPointer() const {
return type() == VALUE_IS_POINTER;
}
template <typename T>
bool isInteger() const {
switch (type()) {
@ -212,6 +222,12 @@ class VariantData {
setType(VALUE_IS_NULL);
}
void setPointer(const VariantData *p) {
ARDUINOJSON_ASSERT(p);
setType(VALUE_IS_POINTER);
_content.asPointer = p;
}
void setString(String s) {
ARDUINOJSON_ASSERT(s);
if (s.isLinked())
@ -262,7 +278,8 @@ class VariantData {
}
VariantData *getElement(size_t index) const {
return isArray() ? _content.asCollection.getElement(index) : 0;
const CollectionData *col = asArray();
return col ? col->getElement(index) : 0;
}
VariantData *getOrAddElement(size_t index, MemoryPool *pool) {
@ -275,7 +292,8 @@ class VariantData {
template <typename TAdaptedString>
VariantData *getMember(TAdaptedString key) const {
return isObject() ? _content.asCollection.getMember(key) : 0;
const CollectionData *col = asObject();
return col ? col->getMember(key) : 0;
}
template <typename TAdaptedString, typename TStoragePolicy>

View File

@ -15,17 +15,17 @@ template <typename TVisitor>
inline typename TVisitor::result_type variantAccept(const VariantData *var,
TVisitor &visitor) {
if (var != 0)
return var->accept(visitor);
return var->resolve()->accept(visitor);
else
return visitor.visitNull();
}
inline const CollectionData *variantAsArray(const VariantData *var) {
return var != 0 ? var->asArray() : 0;
return var != 0 ? var->resolve()->asArray() : 0;
}
inline const CollectionData *variantAsObject(const VariantData *var) {
return var != 0 ? var->asObject() : 0;
return var != 0 ? var->resolve()->asObject() : 0;
}
inline CollectionData *variantAsObject(VariantData *var) {
@ -56,7 +56,7 @@ inline bool variantSetString(VariantData *var, TAdaptedString value,
}
inline size_t variantSize(const VariantData *var) {
return var != 0 ? var->size() : 0;
return var != 0 ? var->resolve()->size() : 0;
}
inline CollectionData *variantToArray(VariantData *var) {
@ -102,14 +102,14 @@ NO_INLINE VariantData *variantGetOrAddMember(VariantData *var,
}
inline bool variantIsNull(const VariantData *var) {
return var == 0 || var->isNull();
return var == 0 || var->resolve()->isNull();
}
inline size_t variantNesting(const VariantData *var) {
if (!var)
return 0;
const CollectionData *collection = var->asCollection();
const CollectionData *collection = var->resolve()->asCollection();
if (!collection)
return 0;

View File

@ -124,7 +124,8 @@ class VariantConstRef : public VariantRefBase<const VariantData>,
}
FORCE_INLINE VariantConstRef getElementConst(size_t index) const {
return VariantConstRef(_data != 0 ? _data->getElement(index) : 0);
return VariantConstRef(_data != 0 ? _data->resolve()->getElement(index)
: 0);
}
FORCE_INLINE VariantConstRef operator[](size_t index) const {
@ -135,8 +136,8 @@ class VariantConstRef : public VariantRefBase<const VariantData>,
// getMemberConst(const String&) const
template <typename TString>
FORCE_INLINE VariantConstRef getMemberConst(const TString &key) const {
return VariantConstRef(
objectGetMember(variantAsObject(_data), adaptString(key)));
return VariantConstRef(_data ? _data->resolve()->getMember(adaptString(key))
: 0);
}
// getMemberConst(char*) const
@ -144,8 +145,8 @@ class VariantConstRef : public VariantRefBase<const VariantData>,
// getMemberConst(const __FlashStringHelper*) const
template <typename TChar>
FORCE_INLINE VariantConstRef getMemberConst(TChar *key) const {
const CollectionData *obj = variantAsObject(_data);
return VariantConstRef(obj ? obj->getMember(adaptString(key)) : 0);
return VariantConstRef(_data ? _data->resolve()->getMember(adaptString(key))
: 0);
}
// operator[](const std::string&) const
@ -293,7 +294,8 @@ class VariantRef : public VariantRefBase<VariantData>,
}
FORCE_INLINE VariantConstRef getElementConst(size_t index) const {
return VariantConstRef(_data != 0 ? _data->getElement(index) : 0);
return VariantConstRef(_data != 0 ? _data->resolve()->getElement(index)
: 0);
}
FORCE_INLINE VariantRef getOrAddElement(size_t index) const {
@ -321,7 +323,8 @@ class VariantRef : public VariantRefBase<VariantData>,
// getMemberConst(const __FlashStringHelper*) const
template <typename TChar>
FORCE_INLINE VariantConstRef getMemberConst(TChar *key) const {
return VariantConstRef(_data ? _data->getMember(adaptString(key)) : 0);
return VariantConstRef(_data ? _data->resolve()->getMember(adaptString(key))
: 0);
}
// getMemberConst(const std::string&) const
@ -330,7 +333,8 @@ class VariantRef : public VariantRefBase<VariantData>,
FORCE_INLINE
typename enable_if<IsString<TString>::value, VariantConstRef>::type
getMemberConst(const TString &key) const {
return VariantConstRef(_data ? _data->getMember(adaptString(key)) : 0);
return VariantConstRef(_data ? _data->resolve()->getMember(adaptString(key))
: 0);
}
// getOrAddMember(char*) const
@ -370,6 +374,16 @@ class VariantRef : public VariantRefBase<VariantData>,
_data->remove(adaptString(key));
}
inline void link(VariantConstRef target) {
if (!_data)
return;
const VariantData *targetData = getData(target);
if (targetData)
_data->setPointer(targetData);
else
_data->setNull();
}
private:
MemoryPool *_pool;