mirror of
https://github.com/bblanchon/ArduinoJson.git
synced 2025-07-30 18:57:32 +02:00
Decouple VariantImpl
from ArrayImpl
and ObjectImpl
This commit is contained in:
@ -24,10 +24,11 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
|
|||||||
|
|
||||||
// INTERNAL USE ONLY
|
// INTERNAL USE ONLY
|
||||||
JsonArray(detail::VariantData* data, detail::ResourceManager* resources)
|
JsonArray(detail::VariantData* data, detail::ResourceManager* resources)
|
||||||
: impl_(detail::VariantImpl(data, resources).asArray()) {}
|
: impl_(data ? data->asArray() : nullptr, resources) {}
|
||||||
|
|
||||||
// INTERNAL USE ONLY
|
// INTERNAL USE ONLY
|
||||||
JsonArray(const detail::ArrayImpl& impl) : impl_(impl) {}
|
JsonArray(detail::CollectionData* data, detail::ResourceManager* resources)
|
||||||
|
: impl_(data, resources) {}
|
||||||
|
|
||||||
// Returns a JsonVariant pointing to the array.
|
// Returns a JsonVariant pointing to the array.
|
||||||
// https://arduinojson.org/v7/api/jsonvariant/
|
// https://arduinojson.org/v7/api/jsonvariant/
|
||||||
|
@ -38,7 +38,7 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
|
|||||||
|
|
||||||
// INTERNAL USE ONLY
|
// INTERNAL USE ONLY
|
||||||
JsonArrayConst(detail::VariantData* data, detail::ResourceManager* resources)
|
JsonArrayConst(detail::VariantData* data, detail::ResourceManager* resources)
|
||||||
: impl_(detail::VariantImpl(data, resources).asArray()) {}
|
: impl_(data ? data->asArray() : nullptr, resources) {}
|
||||||
|
|
||||||
// INTERNAL USE ONLY
|
// INTERNAL USE ONLY
|
||||||
JsonArrayConst(const detail::ArrayImpl& impl) : impl_(impl) {}
|
JsonArrayConst(const detail::ArrayImpl& impl) : impl_(impl) {}
|
||||||
|
@ -64,6 +64,8 @@ class JsonDeserializer {
|
|||||||
DeserializationOption::NestingLimit nestingLimit) {
|
DeserializationOption::NestingLimit nestingLimit) {
|
||||||
DeserializationError::Code err;
|
DeserializationError::Code err;
|
||||||
|
|
||||||
|
ARDUINOJSON_ASSERT(variant != nullptr);
|
||||||
|
|
||||||
err = skipSpacesAndComments();
|
err = skipSpacesAndComments();
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
@ -71,15 +73,13 @@ class JsonDeserializer {
|
|||||||
switch (current()) {
|
switch (current()) {
|
||||||
case '[':
|
case '[':
|
||||||
if (filter.allowArray())
|
if (filter.allowArray())
|
||||||
return parseArray(VariantImpl(variant, resources_).toArray(), filter,
|
return parseArray(variant->toArray(), filter, nestingLimit);
|
||||||
nestingLimit);
|
|
||||||
else
|
else
|
||||||
return skipArray(nestingLimit);
|
return skipArray(nestingLimit);
|
||||||
|
|
||||||
case '{':
|
case '{':
|
||||||
if (filter.allowObject())
|
if (filter.allowObject())
|
||||||
return parseObject(VariantImpl(variant, resources_).toObject(),
|
return parseObject(variant->toObject(), filter, nestingLimit);
|
||||||
filter, nestingLimit);
|
|
||||||
else
|
else
|
||||||
return skipObject(nestingLimit);
|
return skipObject(nestingLimit);
|
||||||
|
|
||||||
@ -148,7 +148,7 @@ class JsonDeserializer {
|
|||||||
|
|
||||||
template <typename TFilter>
|
template <typename TFilter>
|
||||||
DeserializationError::Code parseArray(
|
DeserializationError::Code parseArray(
|
||||||
ArrayImpl array, TFilter filter,
|
CollectionData* arrayData, TFilter filter,
|
||||||
DeserializationOption::NestingLimit nestingLimit) {
|
DeserializationOption::NestingLimit nestingLimit) {
|
||||||
DeserializationError::Code err;
|
DeserializationError::Code err;
|
||||||
|
|
||||||
@ -173,6 +173,8 @@ class JsonDeserializer {
|
|||||||
// Read each value
|
// Read each value
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (elementFilter.allow()) {
|
if (elementFilter.allow()) {
|
||||||
|
ArrayImpl array(arrayData, resources_);
|
||||||
|
|
||||||
// Allocate slot in array
|
// Allocate slot in array
|
||||||
VariantData* value = array.addElement();
|
VariantData* value = array.addElement();
|
||||||
if (!value)
|
if (!value)
|
||||||
@ -234,7 +236,7 @@ class JsonDeserializer {
|
|||||||
|
|
||||||
template <typename TFilter>
|
template <typename TFilter>
|
||||||
DeserializationError::Code parseObject(
|
DeserializationError::Code parseObject(
|
||||||
ObjectImpl object, TFilter filter,
|
CollectionData* objectData, TFilter filter,
|
||||||
DeserializationOption::NestingLimit nestingLimit) {
|
DeserializationOption::NestingLimit nestingLimit) {
|
||||||
DeserializationError::Code err;
|
DeserializationError::Code err;
|
||||||
|
|
||||||
@ -275,6 +277,7 @@ class JsonDeserializer {
|
|||||||
TFilter memberFilter = filter[key];
|
TFilter memberFilter = filter[key];
|
||||||
|
|
||||||
if (memberFilter.allow()) {
|
if (memberFilter.allow()) {
|
||||||
|
ObjectImpl object(objectData, resources_);
|
||||||
auto member = object.getMember(adaptString(key));
|
auto member = object.getMember(adaptString(key));
|
||||||
if (!member) {
|
if (!member) {
|
||||||
auto keyVariant = object.addPair(&member);
|
auto keyVariant = object.addPair(&member);
|
||||||
|
@ -352,7 +352,7 @@ class MsgPackDeserializer {
|
|||||||
ArrayImpl array;
|
ArrayImpl array;
|
||||||
if (allowArray) {
|
if (allowArray) {
|
||||||
ARDUINOJSON_ASSERT(variant != 0);
|
ARDUINOJSON_ASSERT(variant != 0);
|
||||||
array = VariantImpl(variant, resources_).toArray();
|
array = ArrayImpl(variant->toArray(), resources_);
|
||||||
}
|
}
|
||||||
|
|
||||||
TFilter elementFilter = filter[0U];
|
TFilter elementFilter = filter[0U];
|
||||||
@ -388,7 +388,7 @@ class MsgPackDeserializer {
|
|||||||
ObjectImpl object;
|
ObjectImpl object;
|
||||||
if (filter.allowObject()) {
|
if (filter.allowObject()) {
|
||||||
ARDUINOJSON_ASSERT(variant != 0);
|
ARDUINOJSON_ASSERT(variant != 0);
|
||||||
object = VariantImpl(variant, resources_).toObject();
|
object = ObjectImpl(variant->toObject(), resources_);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; n; --n) {
|
for (; n; --n) {
|
||||||
|
@ -23,11 +23,12 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
|
|||||||
JsonObject() {}
|
JsonObject() {}
|
||||||
|
|
||||||
// INTERNAL USE ONLY
|
// INTERNAL USE ONLY
|
||||||
JsonObject(const detail::ObjectImpl& impl) : impl_(impl) {}
|
JsonObject(detail::CollectionData* data, detail::ResourceManager* resource)
|
||||||
|
: impl_(data, resource) {}
|
||||||
|
|
||||||
// INTERNAL USE ONLY
|
// INTERNAL USE ONLY
|
||||||
JsonObject(detail::VariantData* data, detail::ResourceManager* resource)
|
JsonObject(detail::VariantData* data, detail::ResourceManager* resource)
|
||||||
: impl_(detail::VariantImpl(data, resource).asObject()) {}
|
: impl_(data ? data->asObject() : nullptr, resource) {}
|
||||||
|
|
||||||
operator JsonVariant() const {
|
operator JsonVariant() const {
|
||||||
return JsonVariant(getData(), getResourceManager());
|
return JsonVariant(getData(), getResourceManager());
|
||||||
|
@ -23,7 +23,7 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
|
|||||||
|
|
||||||
// INTERNAL USE ONLY
|
// INTERNAL USE ONLY
|
||||||
JsonObjectConst(detail::VariantData* data, detail::ResourceManager* resources)
|
JsonObjectConst(detail::VariantData* data, detail::ResourceManager* resources)
|
||||||
: impl_(detail::VariantImpl(data, resources).asObject()) {}
|
: impl_(data ? data->asObject() : nullptr, resources) {}
|
||||||
|
|
||||||
// INTERNAL USE ONLY
|
// INTERNAL USE ONLY
|
||||||
JsonObjectConst(const detail::ObjectImpl& impl) : impl_(impl) {}
|
JsonObjectConst(const detail::ObjectImpl& impl) : impl_(impl) {}
|
||||||
|
@ -71,6 +71,19 @@ struct VariantData {
|
|||||||
content.asOwnedString = s;
|
content.asOwnedString = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CollectionData* asCollection() {
|
||||||
|
return type & VariantTypeBits::CollectionMask ? &content.asCollection
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
CollectionData* asArray() {
|
||||||
|
return type == VariantType::Array ? &content.asCollection : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
CollectionData* asObject() {
|
||||||
|
return type == VariantType::Object ? &content.asCollection : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
bool isFloat() const {
|
bool isFloat() const {
|
||||||
return type & VariantTypeBits::NumberBit;
|
return type & VariantTypeBits::NumberBit;
|
||||||
}
|
}
|
||||||
@ -79,6 +92,40 @@ struct VariantData {
|
|||||||
return type == VariantType::LinkedString ||
|
return type == VariantType::LinkedString ||
|
||||||
type == VariantType::OwnedString || type == VariantType::TinyString;
|
type == VariantType::OwnedString || type == VariantType::TinyString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CollectionData* toArray() {
|
||||||
|
ARDUINOJSON_ASSERT(type == VariantType::Null);
|
||||||
|
type = VariantType::Array;
|
||||||
|
return new (&content.asCollection) CollectionData();
|
||||||
|
}
|
||||||
|
|
||||||
|
CollectionData* toObject() {
|
||||||
|
ARDUINOJSON_ASSERT(type == VariantType::Null);
|
||||||
|
type = VariantType::Object;
|
||||||
|
return new (&content.asCollection) CollectionData();
|
||||||
|
}
|
||||||
|
|
||||||
|
CollectionData* getOrCreateArray() {
|
||||||
|
switch (type) {
|
||||||
|
case VariantType::Null:
|
||||||
|
return toArray();
|
||||||
|
case VariantType::Array:
|
||||||
|
return &content.asCollection;
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CollectionData* getOrCreateObject() {
|
||||||
|
switch (type) {
|
||||||
|
case VariantType::Null:
|
||||||
|
return toObject();
|
||||||
|
case VariantType::Object:
|
||||||
|
return &content.asCollection;
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||||
|
@ -46,10 +46,11 @@ class VariantImpl {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
case VariantType::Array:
|
case VariantType::Array:
|
||||||
return visit.visit(asArray());
|
return visit.visit(ArrayImpl(&data_->content.asCollection, resources_));
|
||||||
|
|
||||||
case VariantType::Object:
|
case VariantType::Object:
|
||||||
return visit.visit(asObject());
|
return visit.visit(
|
||||||
|
ObjectImpl(&data_->content.asCollection, resources_));
|
||||||
|
|
||||||
case VariantType::TinyString:
|
case VariantType::TinyString:
|
||||||
return visit.visit(JsonString(data_->content.asTinyString));
|
return visit.visit(JsonString(data_->content.asTinyString));
|
||||||
@ -88,14 +89,16 @@ class VariantImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
VariantData* addElement() {
|
VariantData* addElement() {
|
||||||
auto array = isNull() ? toArray() : asArray();
|
if (!data_)
|
||||||
return array.addElement();
|
return nullptr;
|
||||||
|
return ArrayImpl(data_->getOrCreateArray(), resources_).addElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool addValue(const T& value) {
|
bool addValue(const T& value) {
|
||||||
auto array = isNull() ? toArray() : asArray();
|
if (!data_)
|
||||||
return array.addValue(value);
|
return false;
|
||||||
|
return ArrayImpl(data_->getOrCreateArray(), resources_).addValue(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool asBoolean() const {
|
bool asBoolean() const {
|
||||||
@ -129,16 +132,6 @@ class VariantImpl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayImpl asArray() {
|
|
||||||
return ArrayImpl(isArray() ? &data_->content.asCollection : nullptr,
|
|
||||||
resources_);
|
|
||||||
}
|
|
||||||
|
|
||||||
CollectionImpl asCollection() {
|
|
||||||
return CollectionImpl(
|
|
||||||
isCollection() ? &data_->content.asCollection : nullptr, resources_);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T asFloat() const {
|
T asFloat() const {
|
||||||
if (!data_)
|
if (!data_)
|
||||||
@ -231,11 +224,6 @@ class VariantImpl {
|
|||||||
return parseNumber<T>(str);
|
return parseNumber<T>(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectImpl asObject() {
|
|
||||||
return ObjectImpl(isObject() ? &data_->content.asCollection : nullptr,
|
|
||||||
resources_);
|
|
||||||
}
|
|
||||||
|
|
||||||
JsonString asRawString() const {
|
JsonString asRawString() const {
|
||||||
switch (type()) {
|
switch (type()) {
|
||||||
case VariantType::RawString:
|
case VariantType::RawString:
|
||||||
@ -274,25 +262,33 @@ class VariantImpl {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
VariantData* getElement(size_t index) {
|
VariantData* getElement(size_t index) {
|
||||||
return asArray().getElement(index);
|
if (!data_)
|
||||||
|
return nullptr;
|
||||||
|
return ArrayImpl(data_->asArray(), resources_).getElement(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TAdaptedString>
|
template <typename TAdaptedString>
|
||||||
VariantData* getMember(TAdaptedString key) {
|
VariantData* getMember(TAdaptedString key) {
|
||||||
return asObject().getMember(key);
|
if (!data_)
|
||||||
|
return nullptr;
|
||||||
|
return ObjectImpl(data_->asObject(), resources_).getMember(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
VariantData* getOrAddElement(size_t index) {
|
VariantData* getOrAddElement(size_t index) {
|
||||||
auto array = isNull() ? toArray() : asArray();
|
if (!data_)
|
||||||
return array.getOrAddElement(index);
|
return nullptr;
|
||||||
|
return ArrayImpl(data_->getOrCreateArray(), resources_)
|
||||||
|
.getOrAddElement(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TAdaptedString>
|
template <typename TAdaptedString>
|
||||||
VariantData* getOrAddMember(TAdaptedString key) {
|
VariantData* getOrAddMember(TAdaptedString key) {
|
||||||
if (key.isNull())
|
if (key.isNull())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
auto obj = isNull() ? toObject() : asObject();
|
if (!data_)
|
||||||
return obj.getOrAddMember(key);
|
return nullptr;
|
||||||
|
return ObjectImpl(data_->getOrCreateObject(), resources_)
|
||||||
|
.getOrAddMember(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isArray() const {
|
bool isArray() const {
|
||||||
@ -352,16 +348,22 @@ class VariantImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t nesting() {
|
size_t nesting() {
|
||||||
return asCollection().nesting();
|
if (!data_)
|
||||||
|
return 0;
|
||||||
|
return CollectionImpl(data_->asCollection(), resources_).nesting();
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeElement(size_t index) {
|
void removeElement(size_t index) {
|
||||||
asArray().removeElement(index);
|
if (!data_)
|
||||||
|
return;
|
||||||
|
ArrayImpl(data_->asArray(), resources_).removeElement(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TAdaptedString>
|
template <typename TAdaptedString>
|
||||||
void removeMember(TAdaptedString key) {
|
void removeMember(TAdaptedString key) {
|
||||||
asObject().removeMember(key);
|
if (!data_)
|
||||||
|
return;
|
||||||
|
ObjectImpl(data_->asObject(), resources_).removeMember(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool setBoolean(bool value) {
|
bool setBoolean(bool value) {
|
||||||
@ -466,31 +468,15 @@ class VariantImpl {
|
|||||||
bool setLinkedString(const char* s);
|
bool setLinkedString(const char* s);
|
||||||
|
|
||||||
size_t size() {
|
size_t size() {
|
||||||
if (isObject())
|
if (!data_)
|
||||||
return asObject().size();
|
|
||||||
|
|
||||||
if (isArray())
|
|
||||||
return asArray().size();
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
ArrayImpl toArray() {
|
auto size = CollectionImpl(data_->asCollection(), resources_).size();
|
||||||
ARDUINOJSON_ASSERT(type() == VariantType::Null); // must call clear() first
|
|
||||||
if (!data_)
|
|
||||||
return ArrayImpl();
|
|
||||||
data_->type = VariantType::Array;
|
|
||||||
return ArrayImpl(new (&data_->content.asCollection) CollectionData(),
|
|
||||||
resources_);
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjectImpl toObject() {
|
if (data_->type == VariantType::Object)
|
||||||
ARDUINOJSON_ASSERT(type() == VariantType::Null); // must call clear() first
|
size /= 2;
|
||||||
if (!data_)
|
|
||||||
return ObjectImpl();
|
return size;
|
||||||
data_->type = VariantType::Object;
|
|
||||||
return ObjectImpl(new (&data_->content.asCollection) CollectionData(),
|
|
||||||
resources_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VariantType type() const {
|
VariantType type() const {
|
||||||
@ -566,7 +552,7 @@ inline void VariantImpl::clear() {
|
|||||||
resources_->freeEightByte(data_->content.asSlotId);
|
resources_->freeEightByte(data_->content.asSlotId);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
asCollection().clear();
|
CollectionImpl(data_->asCollection(), resources_).clear();
|
||||||
|
|
||||||
data_->type = VariantType::Null;
|
data_->type = VariantType::Null;
|
||||||
}
|
}
|
||||||
|
@ -147,17 +147,23 @@ inline bool VariantRefBase<TDerived>::doSet(const T& value, true_type) const {
|
|||||||
template <typename TDerived>
|
template <typename TDerived>
|
||||||
template <typename T, enable_if_t<is_same<T, JsonArray>::value, int>>
|
template <typename T, enable_if_t<is_same<T, JsonArray>::value, int>>
|
||||||
inline JsonArray VariantRefBase<TDerived>::to() const {
|
inline JsonArray VariantRefBase<TDerived>::to() const {
|
||||||
auto variant = getOrCreateVariantImpl();
|
auto data = getOrCreateData();
|
||||||
variant.clear();
|
if (!data)
|
||||||
return JsonArray(variant.toArray());
|
return JsonArray();
|
||||||
|
auto resources = getResourceManager();
|
||||||
|
VariantImpl(data, resources).clear();
|
||||||
|
return JsonArray(data->toArray(), resources);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TDerived>
|
template <typename TDerived>
|
||||||
template <typename T, enable_if_t<is_same<T, JsonObject>::value, int>>
|
template <typename T, enable_if_t<is_same<T, JsonObject>::value, int>>
|
||||||
JsonObject VariantRefBase<TDerived>::to() const {
|
JsonObject VariantRefBase<TDerived>::to() const {
|
||||||
auto variant = getOrCreateVariantImpl();
|
auto data = getOrCreateData();
|
||||||
variant.clear();
|
if (!data)
|
||||||
return JsonObject(variant.toObject());
|
return JsonObject();
|
||||||
|
auto resources = getResourceManager();
|
||||||
|
VariantImpl(data, resources).clear();
|
||||||
|
return JsonObject(data->toObject(), resources);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TDerived>
|
template <typename TDerived>
|
||||||
|
Reference in New Issue
Block a user