forked from bblanchon/ArduinoJson
Change link()
to shallowCopy()
(issue #1343)
Instead of storing a pointer, the function copies the `VariantData`. Benefits: * smaller code * no impact on programs that don't use this feature Drawbacks: * changes to the original variant are not always reflected on the copy * modifying the original from the shallow copy leads to UB
This commit is contained in:
@ -202,12 +202,12 @@ struct Converter<ArrayConstRef> {
|
||||
|
||||
static ArrayConstRef fromJson(VariantConstRef src) {
|
||||
const VariantData* data = getData(src);
|
||||
return data ? data->resolve()->asArray() : 0;
|
||||
return data ? data->asArray() : 0;
|
||||
}
|
||||
|
||||
static bool checkJson(VariantConstRef src) {
|
||||
const VariantData* data = getData(src);
|
||||
return data && data->resolve()->isArray();
|
||||
return data && data->isArray();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -106,8 +106,8 @@ class ElementProxy : public VariantOperators<ElementProxy<TArray> >,
|
||||
return getOrAddUpstreamElement().template to<T>();
|
||||
}
|
||||
|
||||
FORCE_INLINE void link(VariantConstRef value) const {
|
||||
getOrAddUpstreamElement().link(value);
|
||||
FORCE_INLINE void shallowCopy(VariantConstRef value) const {
|
||||
getOrAddUpstreamElement().shallowCopy(value);
|
||||
}
|
||||
|
||||
// Replaces the value
|
||||
|
@ -17,6 +17,7 @@ inline VariantSlot* CollectionData::addSlot(MemoryPool* pool) {
|
||||
return 0;
|
||||
|
||||
if (_tail) {
|
||||
ARDUINOJSON_ASSERT(pool->owns(_tail)); // Can't alter a linked array/object
|
||||
_tail->setNextNotNull(slot);
|
||||
_tail = slot;
|
||||
} else {
|
||||
|
@ -62,7 +62,7 @@ class JsonDocument : public VariantOperators<const JsonDocument&> {
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return _data.resolve()->size();
|
||||
return _data.size();
|
||||
}
|
||||
|
||||
bool set(const JsonDocument& src) {
|
||||
|
@ -24,7 +24,7 @@ class JsonSerializer : public Visitor<size_t> {
|
||||
const VariantSlot *slot = array.head();
|
||||
|
||||
while (slot != 0) {
|
||||
slot->data()->resolve()->accept(*this);
|
||||
slot->data()->accept(*this);
|
||||
|
||||
slot = slot->next();
|
||||
if (slot == 0)
|
||||
@ -45,7 +45,7 @@ class JsonSerializer : public Visitor<size_t> {
|
||||
while (slot != 0) {
|
||||
_formatter.writeString(slot->key());
|
||||
write(':');
|
||||
slot->data()->resolve()->accept(*this);
|
||||
slot->data()->accept(*this);
|
||||
|
||||
slot = slot->next();
|
||||
if (slot == 0)
|
||||
|
@ -25,7 +25,7 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
|
||||
_nesting++;
|
||||
while (slot != 0) {
|
||||
indent();
|
||||
slot->data()->resolve()->accept(*this);
|
||||
slot->data()->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()->resolve()->accept(*this);
|
||||
slot->data()->accept(*this);
|
||||
|
||||
slot = slot->next();
|
||||
base::write(slot ? ",\r\n" : "\r\n");
|
||||
|
@ -56,7 +56,7 @@ class MsgPackSerializer : public Visitor<size_t> {
|
||||
writeInteger(uint32_t(n));
|
||||
}
|
||||
for (const VariantSlot* slot = array.head(); slot; slot = slot->next()) {
|
||||
slot->data()->resolve()->accept(*this);
|
||||
slot->data()->accept(*this);
|
||||
}
|
||||
return bytesWritten();
|
||||
}
|
||||
@ -74,7 +74,7 @@ class MsgPackSerializer : public Visitor<size_t> {
|
||||
}
|
||||
for (const VariantSlot* slot = object.head(); slot; slot = slot->next()) {
|
||||
visitString(slot->key());
|
||||
slot->data()->resolve()->accept(*this);
|
||||
slot->data()->accept(*this);
|
||||
}
|
||||
return bytesWritten();
|
||||
}
|
||||
|
@ -132,8 +132,8 @@ class MemberProxy : public VariantOperators<MemberProxy<TObject, TStringRef> >,
|
||||
getUpstreamMember().remove(key);
|
||||
}
|
||||
|
||||
FORCE_INLINE void link(VariantConstRef value) {
|
||||
getOrAddUpstreamMember().link(value);
|
||||
FORCE_INLINE void shallowCopy(VariantConstRef value) {
|
||||
getOrAddUpstreamMember().shallowCopy(value);
|
||||
}
|
||||
|
||||
template <typename TValue>
|
||||
|
@ -269,12 +269,12 @@ struct Converter<ObjectConstRef> {
|
||||
|
||||
static ObjectConstRef fromJson(VariantConstRef src) {
|
||||
const VariantData* data = getData(src);
|
||||
return data != 0 ? data->resolve()->asObject() : 0;
|
||||
return data != 0 ? data->asObject() : 0;
|
||||
}
|
||||
|
||||
static bool checkJson(VariantConstRef src) {
|
||||
const VariantData* data = getData(src);
|
||||
return data && data->resolve()->isObject();
|
||||
return data && data->isObject();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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->resolve()->asIntegral<T>() : T();
|
||||
return data ? data->asIntegral<T>() : T();
|
||||
}
|
||||
|
||||
static bool checkJson(VariantConstRef src) {
|
||||
const VariantData* data = getData(src);
|
||||
return data && data->resolve()->isInteger<T>();
|
||||
return data && data->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->resolve()->asIntegral<int>()) : T();
|
||||
return data ? static_cast<T>(data->asIntegral<int>()) : T();
|
||||
}
|
||||
|
||||
static bool checkJson(VariantConstRef src) {
|
||||
const VariantData* data = getData(src);
|
||||
return data && data->resolve()->isInteger<int>();
|
||||
return data && data->isInteger<int>();
|
||||
}
|
||||
};
|
||||
|
||||
@ -84,12 +84,12 @@ struct Converter<bool> {
|
||||
|
||||
static bool fromJson(VariantConstRef src) {
|
||||
const VariantData* data = getData(src);
|
||||
return data ? data->resolve()->asBoolean() : false;
|
||||
return data ? data->asBoolean() : false;
|
||||
}
|
||||
|
||||
static bool checkJson(VariantConstRef src) {
|
||||
const VariantData* data = getData(src);
|
||||
return data && data->resolve()->isBoolean();
|
||||
return data && data->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->resolve()->asFloat<T>() : 0;
|
||||
return data ? data->asFloat<T>() : 0;
|
||||
}
|
||||
|
||||
static bool checkJson(VariantConstRef src) {
|
||||
const VariantData* data = getData(src);
|
||||
return data && data->resolve()->isFloat();
|
||||
return data && data->isFloat();
|
||||
}
|
||||
};
|
||||
|
||||
@ -121,12 +121,12 @@ struct Converter<const char*> {
|
||||
|
||||
static const char* fromJson(VariantConstRef src) {
|
||||
const VariantData* data = getData(src);
|
||||
return data ? data->resolve()->asString().c_str() : 0;
|
||||
return data ? data->asString().c_str() : 0;
|
||||
}
|
||||
|
||||
static bool checkJson(VariantConstRef src) {
|
||||
const VariantData* data = getData(src);
|
||||
return data && data->resolve()->isString();
|
||||
return data && data->isString();
|
||||
}
|
||||
};
|
||||
|
||||
@ -139,12 +139,12 @@ struct Converter<String> {
|
||||
|
||||
static String fromJson(VariantConstRef src) {
|
||||
const VariantData* data = getData(src);
|
||||
return data ? data->resolve()->asString() : 0;
|
||||
return data ? data->asString() : 0;
|
||||
}
|
||||
|
||||
static bool checkJson(VariantConstRef src) {
|
||||
const VariantData* data = getData(src);
|
||||
return data && data->resolve()->isString();
|
||||
return data && data->isString();
|
||||
}
|
||||
};
|
||||
|
||||
@ -192,7 +192,7 @@ struct Converter<decltype(nullptr)> {
|
||||
}
|
||||
static bool checkJson(VariantConstRef src) {
|
||||
const VariantData* data = getData(src);
|
||||
return data == 0 || data->resolve()->isNull();
|
||||
return data == 0 || data->isNull();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -31,8 +31,6 @@ 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,
|
||||
@ -51,7 +49,6 @@ union VariantContent {
|
||||
UInt asUnsignedInteger;
|
||||
Integer asSignedInteger;
|
||||
CollectionData asCollection;
|
||||
const class VariantData *asPointer;
|
||||
struct {
|
||||
const char *data;
|
||||
size_t size;
|
||||
|
@ -37,6 +37,11 @@ class VariantData {
|
||||
_flags = VALUE_IS_NULL;
|
||||
}
|
||||
|
||||
void operator=(const VariantData &src) {
|
||||
_content = src._content;
|
||||
_flags = uint8_t((_flags & OWNED_KEY_BIT) | (src._flags & ~OWNED_KEY_BIT));
|
||||
}
|
||||
|
||||
template <typename TVisitor>
|
||||
typename TVisitor::result_type accept(TVisitor &visitor) const {
|
||||
switch (type()) {
|
||||
@ -83,12 +88,6 @@ class VariantData {
|
||||
|
||||
bool asBoolean() const;
|
||||
|
||||
const VariantData *resolve() const {
|
||||
if (isPointer())
|
||||
return _content.asPointer->resolve();
|
||||
return this;
|
||||
}
|
||||
|
||||
CollectionData *asArray() {
|
||||
return isArray() ? &_content.asCollection : 0;
|
||||
}
|
||||
@ -123,10 +122,6 @@ class VariantData {
|
||||
return (_flags & COLLECTION_MASK) != 0;
|
||||
}
|
||||
|
||||
bool isPointer() const {
|
||||
return type() == VALUE_IS_POINTER;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool isInteger() const {
|
||||
switch (type()) {
|
||||
@ -222,12 +217,6 @@ 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())
|
||||
|
@ -15,7 +15,7 @@ template <typename TVisitor>
|
||||
inline typename TVisitor::result_type variantAccept(const VariantData *var,
|
||||
TVisitor &visitor) {
|
||||
if (var != 0)
|
||||
return var->resolve()->accept(visitor);
|
||||
return var->accept(visitor);
|
||||
else
|
||||
return visitor.visitNull();
|
||||
}
|
||||
@ -44,7 +44,7 @@ inline bool variantSetString(VariantData *var, TAdaptedString value,
|
||||
}
|
||||
|
||||
inline size_t variantSize(const VariantData *var) {
|
||||
return var != 0 ? var->resolve()->size() : 0;
|
||||
return var != 0 ? var->size() : 0;
|
||||
}
|
||||
|
||||
inline CollectionData *variantToArray(VariantData *var) {
|
||||
@ -90,14 +90,14 @@ NO_INLINE VariantData *variantGetOrAddMember(VariantData *var,
|
||||
}
|
||||
|
||||
inline bool variantIsNull(const VariantData *var) {
|
||||
return var == 0 || var->resolve()->isNull();
|
||||
return var == 0 || var->isNull();
|
||||
}
|
||||
|
||||
inline size_t variantNesting(const VariantData *var) {
|
||||
if (!var)
|
||||
return 0;
|
||||
|
||||
const CollectionData *collection = var->resolve()->asCollection();
|
||||
const CollectionData *collection = var->asCollection();
|
||||
if (!collection)
|
||||
return 0;
|
||||
|
||||
|
@ -117,8 +117,7 @@ class VariantConstRef : public VariantRefBase<const VariantData>,
|
||||
}
|
||||
|
||||
FORCE_INLINE VariantConstRef getElementConst(size_t index) const {
|
||||
return VariantConstRef(_data != 0 ? _data->resolve()->getElement(index)
|
||||
: 0);
|
||||
return VariantConstRef(_data != 0 ? _data->getElement(index) : 0);
|
||||
}
|
||||
|
||||
FORCE_INLINE VariantConstRef operator[](size_t index) const {
|
||||
@ -129,8 +128,7 @@ class VariantConstRef : public VariantRefBase<const VariantData>,
|
||||
// getMemberConst(const String&) const
|
||||
template <typename TString>
|
||||
FORCE_INLINE VariantConstRef getMemberConst(const TString &key) const {
|
||||
return VariantConstRef(_data ? _data->resolve()->getMember(adaptString(key))
|
||||
: 0);
|
||||
return VariantConstRef(_data ? _data->getMember(adaptString(key)) : 0);
|
||||
}
|
||||
|
||||
// getMemberConst(char*) const
|
||||
@ -138,8 +136,7 @@ class VariantConstRef : public VariantRefBase<const VariantData>,
|
||||
// getMemberConst(const __FlashStringHelper*) const
|
||||
template <typename TChar>
|
||||
FORCE_INLINE VariantConstRef getMemberConst(TChar *key) const {
|
||||
return VariantConstRef(_data ? _data->resolve()->getMember(adaptString(key))
|
||||
: 0);
|
||||
return VariantConstRef(_data ? _data->getMember(adaptString(key)) : 0);
|
||||
}
|
||||
|
||||
// operator[](const std::string&) const
|
||||
@ -281,8 +278,7 @@ class VariantRef : public VariantRefBase<VariantData>,
|
||||
}
|
||||
|
||||
FORCE_INLINE VariantConstRef getElementConst(size_t index) const {
|
||||
return VariantConstRef(_data != 0 ? _data->resolve()->getElement(index)
|
||||
: 0);
|
||||
return VariantConstRef(_data != 0 ? _data->getElement(index) : 0);
|
||||
}
|
||||
|
||||
FORCE_INLINE VariantRef getOrAddElement(size_t index) const {
|
||||
@ -310,8 +306,7 @@ class VariantRef : public VariantRefBase<VariantData>,
|
||||
// getMemberConst(const __FlashStringHelper*) const
|
||||
template <typename TChar>
|
||||
FORCE_INLINE VariantConstRef getMemberConst(TChar *key) const {
|
||||
return VariantConstRef(_data ? _data->resolve()->getMember(adaptString(key))
|
||||
: 0);
|
||||
return VariantConstRef(_data ? _data->getMember(adaptString(key)) : 0);
|
||||
}
|
||||
|
||||
// getMemberConst(const std::string&) const
|
||||
@ -320,8 +315,7 @@ class VariantRef : public VariantRefBase<VariantData>,
|
||||
FORCE_INLINE
|
||||
typename enable_if<IsString<TString>::value, VariantConstRef>::type
|
||||
getMemberConst(const TString &key) const {
|
||||
return VariantConstRef(_data ? _data->resolve()->getMember(adaptString(key))
|
||||
: 0);
|
||||
return VariantConstRef(_data ? _data->getMember(adaptString(key)) : 0);
|
||||
}
|
||||
|
||||
// getOrAddMember(char*) const
|
||||
@ -361,12 +355,12 @@ class VariantRef : public VariantRefBase<VariantData>,
|
||||
_data->remove(adaptString(key));
|
||||
}
|
||||
|
||||
inline void link(VariantConstRef target) {
|
||||
inline void shallowCopy(VariantConstRef target) {
|
||||
if (!_data)
|
||||
return;
|
||||
const VariantData *targetData = getData(target);
|
||||
if (targetData)
|
||||
_data->setPointer(targetData);
|
||||
*_data = *targetData;
|
||||
else
|
||||
_data->setNull();
|
||||
}
|
||||
|
Reference in New Issue
Block a user