forked from bblanchon/ArduinoJson
Decouple VariantData
from MemoryPool
This commit is contained in:
@ -10,6 +10,8 @@
|
||||
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Allocators.hpp"
|
||||
|
||||
using ArduinoJson::detail::sizeofArray;
|
||||
using ArduinoJson::detail::sizeofObject;
|
||||
using ArduinoJson::detail::sizeofString;
|
||||
@ -388,3 +390,19 @@ TEST_CASE("Deduplicate keys") {
|
||||
CHECK(key1 == key2);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("MemberProxy under memory constraints") {
|
||||
ControllableAllocator allocator;
|
||||
JsonDocument doc(4096, &allocator);
|
||||
|
||||
SECTION("key allocation fails") {
|
||||
allocator.disable();
|
||||
|
||||
doc[std::string("hello")] = "world";
|
||||
|
||||
REQUIRE(doc.is<JsonObject>());
|
||||
REQUIRE(doc.size() == 0);
|
||||
REQUIRE(doc.memoryUsage() == sizeofObject(1));
|
||||
REQUIRE(doc.overflowed() == true);
|
||||
}
|
||||
}
|
||||
|
@ -4,12 +4,15 @@
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
#include "Allocators.hpp"
|
||||
|
||||
using ArduinoJson::detail::sizeofString;
|
||||
|
||||
TEST_CASE("JsonVariant::set(JsonVariant)") {
|
||||
JsonDocument doc1(4096);
|
||||
JsonDocument doc2(4096);
|
||||
ControllableAllocator allocator;
|
||||
SpyingAllocator spyingAllocator(&allocator);
|
||||
JsonDocument doc1(4096, &spyingAllocator);
|
||||
JsonDocument doc2(4096, &spyingAllocator);
|
||||
JsonVariant var1 = doc1.to<JsonVariant>();
|
||||
JsonVariant var2 = doc2.to<JsonVariant>();
|
||||
|
||||
@ -37,53 +40,103 @@ TEST_CASE("JsonVariant::set(JsonVariant)") {
|
||||
|
||||
SECTION("stores const char* by reference") {
|
||||
var1.set("hello!!");
|
||||
spyingAllocator.clearLog();
|
||||
|
||||
var2.set(var1);
|
||||
|
||||
REQUIRE(doc1.memoryUsage() == 0);
|
||||
REQUIRE(doc2.memoryUsage() == 0);
|
||||
REQUIRE(spyingAllocator.log() == AllocatorLog());
|
||||
}
|
||||
|
||||
SECTION("stores char* by copy") {
|
||||
char str[] = "hello!!";
|
||||
|
||||
var1.set(str);
|
||||
spyingAllocator.clearLog();
|
||||
|
||||
var2.set(var1);
|
||||
|
||||
REQUIRE(doc1.memoryUsage() == sizeofString(7));
|
||||
REQUIRE(doc2.memoryUsage() == sizeofString(7));
|
||||
REQUIRE(spyingAllocator.log() ==
|
||||
AllocatorLog() << AllocatorLog::Allocate(sizeofString((7))));
|
||||
}
|
||||
|
||||
SECTION("fails gracefully if string allocation fails") {
|
||||
char str[] = "hello!!";
|
||||
var1.set(str);
|
||||
allocator.disable();
|
||||
spyingAllocator.clearLog();
|
||||
|
||||
var2.set(var1);
|
||||
|
||||
REQUIRE(doc1.memoryUsage() == sizeofString(7));
|
||||
REQUIRE(doc2.memoryUsage() == 0);
|
||||
REQUIRE(doc2.overflowed() == true);
|
||||
REQUIRE(spyingAllocator.log() ==
|
||||
AllocatorLog() << AllocatorLog::AllocateFail(sizeofString((7))));
|
||||
}
|
||||
|
||||
SECTION("stores std::string by copy") {
|
||||
var1.set(std::string("hello!!"));
|
||||
spyingAllocator.clearLog();
|
||||
|
||||
var2.set(var1);
|
||||
|
||||
REQUIRE(doc1.memoryUsage() == sizeofString(7));
|
||||
REQUIRE(doc2.memoryUsage() == sizeofString(7));
|
||||
REQUIRE(spyingAllocator.log() ==
|
||||
AllocatorLog() << AllocatorLog::Allocate(sizeofString((7))));
|
||||
}
|
||||
|
||||
SECTION("stores Serialized<const char*> by reference") {
|
||||
var1.set(serialized("hello!!", 8));
|
||||
spyingAllocator.clearLog();
|
||||
|
||||
var2.set(var1);
|
||||
|
||||
REQUIRE(doc1.memoryUsage() == 0);
|
||||
REQUIRE(doc2.memoryUsage() == 0);
|
||||
REQUIRE(spyingAllocator.log() == AllocatorLog());
|
||||
}
|
||||
|
||||
SECTION("stores Serialized<char*> by copy") {
|
||||
char str[] = "hello!!";
|
||||
var1.set(serialized(str, 7));
|
||||
spyingAllocator.clearLog();
|
||||
|
||||
var2.set(var1);
|
||||
|
||||
REQUIRE(doc1.memoryUsage() == sizeofString(7));
|
||||
REQUIRE(doc2.memoryUsage() == sizeofString(7));
|
||||
REQUIRE(spyingAllocator.log() ==
|
||||
AllocatorLog() << AllocatorLog::Allocate(sizeofString((7))));
|
||||
}
|
||||
|
||||
SECTION("stores Serialized<std::string> by copy") {
|
||||
var1.set(serialized(std::string("hello!!")));
|
||||
spyingAllocator.clearLog();
|
||||
|
||||
var2.set(var1);
|
||||
|
||||
REQUIRE(doc1.memoryUsage() == sizeofString(7));
|
||||
REQUIRE(doc2.memoryUsage() == sizeofString(7));
|
||||
REQUIRE(spyingAllocator.log() ==
|
||||
AllocatorLog() << AllocatorLog::Allocate(sizeofString((7))));
|
||||
}
|
||||
|
||||
SECTION("fails gracefully if raw string allocation fails") {
|
||||
var1.set(serialized(std::string("hello!!")));
|
||||
allocator.disable();
|
||||
spyingAllocator.clearLog();
|
||||
|
||||
var2.set(var1);
|
||||
|
||||
REQUIRE(doc1.memoryUsage() == sizeofString(7));
|
||||
REQUIRE(doc2.memoryUsage() == 0);
|
||||
REQUIRE(doc2.overflowed() == true);
|
||||
REQUIRE(spyingAllocator.log() ==
|
||||
AllocatorLog() << AllocatorLog::AllocateFail(sizeofString((7))));
|
||||
}
|
||||
|
||||
SECTION("destination is unbound") {
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include <ArduinoJson/Array/ElementProxy.hpp>
|
||||
#include <ArduinoJson/Array/JsonArrayConst.hpp>
|
||||
#include <ArduinoJson/Collection/CollectionFunctions.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
|
||||
@ -43,9 +44,7 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
|
||||
// Returns a reference to the new element.
|
||||
// https://arduinojson.org/v6/api/jsonarray/add/
|
||||
JsonVariant add() const {
|
||||
if (!_data)
|
||||
return JsonVariant();
|
||||
return JsonVariant(_pool, _data->addElement(_pool));
|
||||
return JsonVariant(_pool, collectionAddElement(_data, _pool));
|
||||
}
|
||||
|
||||
// Appends a value to the array.
|
||||
@ -79,9 +78,7 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
|
||||
// Copies an array.
|
||||
// https://arduinojson.org/v6/api/jsonarray/set/
|
||||
FORCE_INLINE bool set(JsonArrayConst src) const {
|
||||
if (!_data || !src._data)
|
||||
return false;
|
||||
return _data->copyFrom(*src._data, _pool);
|
||||
return collectionCopy(_data, src._data, _pool);
|
||||
}
|
||||
|
||||
// Compares the content of two arrays.
|
||||
@ -93,27 +90,21 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
|
||||
// ⚠️ Doesn't release the memory associated with the removed element.
|
||||
// https://arduinojson.org/v6/api/jsonarray/remove/
|
||||
FORCE_INLINE void remove(iterator it) const {
|
||||
if (!_data)
|
||||
return;
|
||||
_data->removeSlot(it._slot);
|
||||
collectionRemove(_data, it._slot, _pool);
|
||||
}
|
||||
|
||||
// Removes the element at the specified index.
|
||||
// ⚠️ Doesn't release the memory associated with the removed element.
|
||||
// https://arduinojson.org/v6/api/jsonarray/remove/
|
||||
FORCE_INLINE void remove(size_t index) const {
|
||||
if (!_data)
|
||||
return;
|
||||
_data->removeElement(index);
|
||||
collectionRemoveElement(_data, index, _pool);
|
||||
}
|
||||
|
||||
// Removes all the elements of the array.
|
||||
// ⚠️ Doesn't release the memory associated with the removed elements.
|
||||
// https://arduinojson.org/v6/api/jsonarray/clear/
|
||||
void clear() const {
|
||||
if (!_data)
|
||||
return;
|
||||
_data->clear();
|
||||
collectionClear(_data, _pool);
|
||||
}
|
||||
|
||||
// Gets or sets the element at the specified index.
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
class MemoryPool;
|
||||
class VariantData;
|
||||
class VariantSlot;
|
||||
|
||||
@ -28,30 +27,13 @@ class CollectionData {
|
||||
|
||||
// Array only
|
||||
|
||||
VariantData* addElement(MemoryPool* pool);
|
||||
|
||||
VariantData* getElement(size_t index) const;
|
||||
|
||||
VariantData* getOrAddElement(size_t index, MemoryPool* pool);
|
||||
|
||||
void removeElement(size_t index);
|
||||
|
||||
// Object only
|
||||
|
||||
template <typename TAdaptedString>
|
||||
VariantData* addMember(TAdaptedString key, MemoryPool* pool);
|
||||
|
||||
template <typename TAdaptedString>
|
||||
VariantData* getMember(TAdaptedString key) const;
|
||||
|
||||
template <typename TAdaptedString>
|
||||
VariantData* getOrAddMember(TAdaptedString key, MemoryPool* pool);
|
||||
|
||||
template <typename TAdaptedString>
|
||||
void removeMember(TAdaptedString key) {
|
||||
removeSlot(getSlot(key));
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
bool containsKey(const TAdaptedString& key) const;
|
||||
|
||||
@ -61,23 +43,21 @@ class CollectionData {
|
||||
size_t memoryUsage() const;
|
||||
size_t size() const;
|
||||
|
||||
VariantSlot* addSlot(MemoryPool*);
|
||||
void addSlot(VariantSlot*);
|
||||
void removeSlot(VariantSlot* slot);
|
||||
|
||||
bool copyFrom(const CollectionData& src, MemoryPool* pool);
|
||||
|
||||
VariantSlot* head() const {
|
||||
return _head;
|
||||
}
|
||||
|
||||
void movePointers(ptrdiff_t variantDistance);
|
||||
|
||||
private:
|
||||
VariantSlot* getSlot(size_t index) const;
|
||||
|
||||
template <typename TAdaptedString>
|
||||
VariantSlot* getSlot(TAdaptedString key) const;
|
||||
|
||||
private:
|
||||
VariantSlot* getPreviousSlot(VariantSlot*) const;
|
||||
};
|
||||
|
||||
|
93
src/ArduinoJson/Collection/CollectionFunctions.hpp
Normal file
93
src/ArduinoJson/Collection/CollectionFunctions.hpp
Normal file
@ -0,0 +1,93 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Collection/CollectionData.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
inline VariantData* collectionAddElement(CollectionData* array,
|
||||
MemoryPool* pool) {
|
||||
if (!array)
|
||||
return nullptr;
|
||||
auto slot = pool->allocVariant();
|
||||
if (!slot)
|
||||
return nullptr;
|
||||
array->addSlot(slot);
|
||||
return slot->data();
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
inline VariantData* collectionAddMember(CollectionData* obj, TAdaptedString key,
|
||||
MemoryPool* pool) {
|
||||
ARDUINOJSON_ASSERT(!key.isNull());
|
||||
ARDUINOJSON_ASSERT(obj != nullptr);
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
auto slot = pool->allocVariant();
|
||||
if (!slot)
|
||||
return nullptr;
|
||||
auto storedKey = storeString(pool, key);
|
||||
if (!storedKey)
|
||||
return nullptr;
|
||||
slot->setKey(storedKey);
|
||||
obj->addSlot(slot);
|
||||
return slot->data();
|
||||
}
|
||||
|
||||
inline void collectionClear(CollectionData* c, MemoryPool* pool) {
|
||||
if (!c)
|
||||
return;
|
||||
for (auto slot = c->head(); slot; slot = slot->next())
|
||||
slotRelease(slot, pool);
|
||||
c->clear();
|
||||
}
|
||||
|
||||
inline bool collectionCopy(CollectionData* dst, const CollectionData* src,
|
||||
MemoryPool* pool) {
|
||||
if (!dst || !src)
|
||||
return false;
|
||||
|
||||
collectionClear(dst, pool);
|
||||
|
||||
for (VariantSlot* s = src->head(); s; s = s->next()) {
|
||||
VariantData* var;
|
||||
if (s->key() != 0) {
|
||||
JsonString key(s->key(),
|
||||
s->ownsKey() ? JsonString::Copied : JsonString::Linked);
|
||||
var = collectionAddMember(dst, adaptString(key), pool);
|
||||
} else {
|
||||
var = collectionAddElement(dst, pool);
|
||||
}
|
||||
if (!variantCopyFrom(var, s->data(), pool))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void collectionRemove(CollectionData* data, VariantSlot* slot,
|
||||
MemoryPool* pool) {
|
||||
if (!data || !slot)
|
||||
return;
|
||||
data->removeSlot(slot);
|
||||
slotRelease(slot, pool);
|
||||
}
|
||||
|
||||
inline void collectionRemoveElement(CollectionData* array, size_t index,
|
||||
MemoryPool* pool) {
|
||||
if (!array)
|
||||
return;
|
||||
collectionRemove(array, array->getSlot(index), pool);
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
inline void collectionRemoveMember(CollectionData* obj, TAdaptedString key,
|
||||
MemoryPool* pool) {
|
||||
if (!obj)
|
||||
return;
|
||||
collectionRemove(obj, obj->getSlot(key), pool);
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
@ -11,41 +11,16 @@
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
inline VariantSlot* CollectionData::addSlot(MemoryPool* pool) {
|
||||
VariantSlot* slot = pool->allocVariant();
|
||||
if (!slot)
|
||||
return 0;
|
||||
inline void CollectionData::addSlot(VariantSlot* slot) {
|
||||
ARDUINOJSON_ASSERT(slot != nullptr);
|
||||
|
||||
if (_tail) {
|
||||
ARDUINOJSON_ASSERT(pool->owns(_tail)); // Can't alter a linked array/object
|
||||
_tail->setNextNotNull(slot);
|
||||
_tail = slot;
|
||||
} else {
|
||||
_head = slot;
|
||||
_tail = slot;
|
||||
}
|
||||
|
||||
slot->clear();
|
||||
return slot;
|
||||
}
|
||||
|
||||
inline VariantData* CollectionData::addElement(MemoryPool* pool) {
|
||||
return slotData(addSlot(pool));
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
inline VariantData* CollectionData::addMember(TAdaptedString key,
|
||||
MemoryPool* pool) {
|
||||
VariantSlot* slot = addSlot(pool);
|
||||
if (!slot)
|
||||
return 0;
|
||||
auto storedKey = storeString(pool, key);
|
||||
if (!storedKey) {
|
||||
removeSlot(slot);
|
||||
return 0;
|
||||
}
|
||||
slot->setKey(storedKey);
|
||||
return slot->data();
|
||||
}
|
||||
|
||||
inline void CollectionData::clear() {
|
||||
@ -58,26 +33,6 @@ inline bool CollectionData::containsKey(const TAdaptedString& key) const {
|
||||
return getSlot(key) != 0;
|
||||
}
|
||||
|
||||
inline bool CollectionData::copyFrom(const CollectionData& src,
|
||||
MemoryPool* pool) {
|
||||
clear();
|
||||
for (VariantSlot* s = src._head; s; s = s->next()) {
|
||||
VariantData* var;
|
||||
if (s->key() != 0) {
|
||||
JsonString key(s->key(),
|
||||
s->ownsKey() ? JsonString::Copied : JsonString::Linked);
|
||||
var = addMember(adaptString(key), pool);
|
||||
} else {
|
||||
var = addElement(pool);
|
||||
}
|
||||
if (!var)
|
||||
return false;
|
||||
if (!var->copyFrom(*s->data(), pool))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
inline VariantSlot* CollectionData::getSlot(TAdaptedString key) const {
|
||||
if (key.isNull())
|
||||
@ -114,42 +69,11 @@ inline VariantData* CollectionData::getMember(TAdaptedString key) const {
|
||||
return slot ? slot->data() : 0;
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
inline VariantData* CollectionData::getOrAddMember(TAdaptedString key,
|
||||
MemoryPool* pool) {
|
||||
// ignore null key
|
||||
if (key.isNull())
|
||||
return 0;
|
||||
|
||||
// search a matching key
|
||||
VariantSlot* slot = getSlot(key);
|
||||
if (slot)
|
||||
return slot->data();
|
||||
|
||||
return addMember(key, pool);
|
||||
}
|
||||
|
||||
inline VariantData* CollectionData::getElement(size_t index) const {
|
||||
VariantSlot* slot = getSlot(index);
|
||||
return slot ? slot->data() : 0;
|
||||
}
|
||||
|
||||
inline VariantData* CollectionData::getOrAddElement(size_t index,
|
||||
MemoryPool* pool) {
|
||||
VariantSlot* slot = _head;
|
||||
while (slot && index > 0) {
|
||||
slot = slot->next();
|
||||
index--;
|
||||
}
|
||||
if (!slot)
|
||||
index++;
|
||||
while (index > 0) {
|
||||
slot = addSlot(pool);
|
||||
index--;
|
||||
}
|
||||
return slotData(slot);
|
||||
}
|
||||
|
||||
inline void CollectionData::removeSlot(VariantSlot* slot) {
|
||||
if (!slot)
|
||||
return;
|
||||
@ -163,10 +87,6 @@ inline void CollectionData::removeSlot(VariantSlot* slot) {
|
||||
_tail = prev;
|
||||
}
|
||||
|
||||
inline void CollectionData::removeElement(size_t index) {
|
||||
removeSlot(getSlot(index));
|
||||
}
|
||||
|
||||
inline size_t CollectionData::memoryUsage() const {
|
||||
size_t total = 0;
|
||||
for (VariantSlot* s = _head; s; s = s->next()) {
|
||||
|
@ -119,7 +119,7 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
||||
// https://arduinojson.org/v6/api/jsondocument/clear/
|
||||
void clear() {
|
||||
_pool.clear();
|
||||
_data.setNull();
|
||||
_data.reset();
|
||||
}
|
||||
|
||||
// Returns true if the root is of the specified type.
|
||||
@ -297,7 +297,7 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
||||
// Returns a reference to the new element.
|
||||
// https://arduinojson.org/v6/api/jsondocument/add/
|
||||
FORCE_INLINE JsonVariant add() {
|
||||
return JsonVariant(&_pool, _data.addElement(&_pool));
|
||||
return JsonVariant(&_pool, variantAddElement(&_data, &_pool));
|
||||
}
|
||||
|
||||
// Appends a value to the root array.
|
||||
@ -318,7 +318,7 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
||||
// ⚠️ Doesn't release the memory associated with the removed element.
|
||||
// https://arduinojson.org/v6/api/jsondocument/remove/
|
||||
FORCE_INLINE void remove(size_t index) {
|
||||
_data.remove(index);
|
||||
variantRemoveElement(getData(), index, getPool());
|
||||
}
|
||||
|
||||
// Removes a member of the root object.
|
||||
@ -327,7 +327,7 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
||||
template <typename TChar>
|
||||
FORCE_INLINE typename detail::enable_if<detail::IsString<TChar*>::value>::type
|
||||
remove(TChar* key) {
|
||||
_data.remove(detail::adaptString(key));
|
||||
variantRemoveMember(getData(), detail::adaptString(key), getPool());
|
||||
}
|
||||
|
||||
// Removes a member of the root object.
|
||||
@ -337,7 +337,7 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
||||
FORCE_INLINE
|
||||
typename detail::enable_if<detail::IsString<TString>::value>::type
|
||||
remove(const TString& key) {
|
||||
_data.remove(detail::adaptString(key));
|
||||
variantRemoveMember(getData(), detail::adaptString(key), getPool());
|
||||
}
|
||||
|
||||
FORCE_INLINE operator JsonVariant() {
|
||||
@ -364,7 +364,7 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
||||
|
||||
void moveAssignFrom(JsonDocument& src) {
|
||||
_data = src._data;
|
||||
src._data.setNull();
|
||||
src._data.reset();
|
||||
_pool = move(src._pool);
|
||||
}
|
||||
|
||||
|
@ -173,7 +173,7 @@ class JsonDeserializer {
|
||||
for (;;) {
|
||||
if (memberFilter.allow()) {
|
||||
// Allocate slot in array
|
||||
VariantData* value = array.addElement(_pool);
|
||||
VariantData* value = collectionAddElement(&array, _pool);
|
||||
if (!value)
|
||||
return DeserializationError::NoMemory;
|
||||
|
||||
@ -280,11 +280,12 @@ class JsonDeserializer {
|
||||
key = _stringStorage.save();
|
||||
|
||||
// Allocate slot in object
|
||||
VariantSlot* slot = object.addSlot(_pool);
|
||||
VariantSlot* slot = _pool->allocVariant();
|
||||
if (!slot)
|
||||
return DeserializationError::NoMemory;
|
||||
|
||||
slot->setKey(key);
|
||||
object.addSlot(slot);
|
||||
|
||||
variant = slot->data();
|
||||
}
|
||||
|
@ -99,7 +99,10 @@ class MemoryPool {
|
||||
}
|
||||
|
||||
VariantSlot* allocVariant() {
|
||||
return allocRight<VariantSlot>();
|
||||
auto slot = allocRight<VariantSlot>();
|
||||
if (slot)
|
||||
slot->clear();
|
||||
return slot;
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
|
@ -435,7 +435,7 @@ class MsgPackDeserializer {
|
||||
|
||||
if (memberFilter.allow()) {
|
||||
ARDUINOJSON_ASSERT(array != 0);
|
||||
value = array->addElement(_pool);
|
||||
value = collectionAddElement(array, _pool);
|
||||
if (!value)
|
||||
return DeserializationError::NoMemory;
|
||||
} else {
|
||||
@ -496,11 +496,12 @@ class MsgPackDeserializer {
|
||||
// Save key in memory pool.
|
||||
key = _stringStorage.save();
|
||||
|
||||
VariantSlot* slot = object->addSlot(_pool);
|
||||
VariantSlot* slot = _pool->allocVariant();
|
||||
if (!slot)
|
||||
return DeserializationError::NoMemory;
|
||||
|
||||
slot->setKey(key);
|
||||
object->addSlot(slot);
|
||||
|
||||
member = slot->data();
|
||||
} else {
|
||||
|
@ -87,17 +87,13 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
|
||||
// ⚠️ Doesn't release the memory associated with the removed members.
|
||||
// https://arduinojson.org/v6/api/jsonobject/clear/
|
||||
void clear() const {
|
||||
if (!_data)
|
||||
return;
|
||||
_data->clear();
|
||||
collectionClear(_data, _pool);
|
||||
}
|
||||
|
||||
// Copies an object.
|
||||
// https://arduinojson.org/v6/api/jsonobject/set/
|
||||
FORCE_INLINE bool set(JsonObjectConst src) {
|
||||
if (!_data || !src._data)
|
||||
return false;
|
||||
return _data->copyFrom(*src._data, _pool);
|
||||
return collectionCopy(_data, src._data, _pool);
|
||||
}
|
||||
|
||||
// Compares the content of two objects.
|
||||
@ -129,9 +125,7 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
|
||||
// ⚠️ Doesn't release the memory associated with the removed member.
|
||||
// https://arduinojson.org/v6/api/jsonobject/remove/
|
||||
FORCE_INLINE void remove(iterator it) const {
|
||||
if (!_data)
|
||||
return;
|
||||
_data->removeSlot(it._slot);
|
||||
collectionRemove(_data, it._slot, _pool);
|
||||
}
|
||||
|
||||
// Removes the member with the specified key.
|
||||
@ -139,7 +133,7 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
|
||||
// https://arduinojson.org/v6/api/jsonobject/remove/
|
||||
template <typename TString>
|
||||
FORCE_INLINE void remove(const TString& key) const {
|
||||
removeMember(detail::adaptString(key));
|
||||
collectionRemoveMember(_data, detail::adaptString(key), _pool);
|
||||
}
|
||||
|
||||
// Removes the member with the specified key.
|
||||
@ -147,7 +141,7 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
|
||||
// https://arduinojson.org/v6/api/jsonobject/remove/
|
||||
template <typename TChar>
|
||||
FORCE_INLINE void remove(TChar* key) const {
|
||||
removeMember(detail::adaptString(key));
|
||||
collectionRemoveMember(_data, detail::adaptString(key), _pool);
|
||||
}
|
||||
|
||||
// Returns true if the object contains the specified key.
|
||||
@ -214,9 +208,7 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
|
||||
|
||||
template <typename TAdaptedString>
|
||||
void removeMember(TAdaptedString key) const {
|
||||
if (!_data)
|
||||
return;
|
||||
_data->removeMember(key);
|
||||
collectionRemove(_data, _data->getSlot(key), _pool);
|
||||
}
|
||||
|
||||
detail::CollectionData* _data;
|
||||
|
@ -42,10 +42,8 @@ struct Converter<
|
||||
!detail::is_same<char, T>::value>::type>
|
||||
: private detail::VariantAttorney {
|
||||
static void toJson(T src, JsonVariant dst) {
|
||||
auto data = getData(dst);
|
||||
ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T);
|
||||
if (data)
|
||||
data->setInteger(src);
|
||||
variantSetInteger(getData(dst), src, getPool(dst));
|
||||
}
|
||||
|
||||
static T fromJson(JsonVariantConst src) {
|
||||
@ -81,9 +79,7 @@ struct Converter<T, typename detail::enable_if<detail::is_enum<T>::value>::type>
|
||||
template <>
|
||||
struct Converter<bool> : private detail::VariantAttorney {
|
||||
static void toJson(bool src, JsonVariant dst) {
|
||||
auto data = getData(dst);
|
||||
if (data)
|
||||
data->setBoolean(src);
|
||||
variantSetBoolean(getData(dst), src, getPool(dst));
|
||||
}
|
||||
|
||||
static bool fromJson(JsonVariantConst src) {
|
||||
@ -102,9 +98,7 @@ struct Converter<
|
||||
T, typename detail::enable_if<detail::is_floating_point<T>::value>::type>
|
||||
: private detail::VariantAttorney {
|
||||
static void toJson(T src, JsonVariant dst) {
|
||||
auto data = getData(dst);
|
||||
if (data)
|
||||
data->setFloat(static_cast<JsonFloat>(src));
|
||||
variantSetFloat(getData(dst), static_cast<JsonFloat>(src), getPool(dst));
|
||||
}
|
||||
|
||||
static T fromJson(JsonVariantConst src) {
|
||||
@ -165,9 +159,7 @@ template <>
|
||||
struct Converter<SerializedValue<const char*>>
|
||||
: private detail::VariantAttorney {
|
||||
static void toJson(SerializedValue<const char*> src, JsonVariant dst) {
|
||||
auto data = getData(dst);
|
||||
if (data)
|
||||
data->setLinkedRaw(src);
|
||||
variantSetLinkedRaw(getData(dst), src, getPool(dst));
|
||||
}
|
||||
};
|
||||
|
||||
@ -180,17 +172,14 @@ struct Converter<
|
||||
typename detail::enable_if<!detail::is_same<const char*, T>::value>::type>
|
||||
: private detail::VariantAttorney {
|
||||
static void toJson(SerializedValue<T> src, JsonVariant dst) {
|
||||
auto data = getData(dst);
|
||||
auto pool = getPool(dst);
|
||||
if (data)
|
||||
data->storeOwnedRaw(src, pool);
|
||||
variantSetOwnedRaw(getData(dst), src, getPool(dst));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Converter<decltype(nullptr)> : private detail::VariantAttorney {
|
||||
static void toJson(decltype(nullptr), JsonVariant dst) {
|
||||
variantSetNull(getData(dst));
|
||||
variantSetNull(getData(dst), getPool(dst));
|
||||
}
|
||||
static decltype(nullptr) fromJson(JsonVariantConst) {
|
||||
return nullptr;
|
||||
|
@ -21,4 +21,10 @@ inline size_t slotSize(const VariantSlot* var) {
|
||||
inline VariantData* slotData(VariantSlot* slot) {
|
||||
return reinterpret_cast<VariantData*>(slot);
|
||||
}
|
||||
|
||||
inline void slotRelease(const VariantSlot* slot, MemoryPool* pool) {
|
||||
ARDUINOJSON_ASSERT(slot != nullptr);
|
||||
variantRelease(slot->data(), pool);
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Memory/MemoryPool.hpp>
|
||||
#include <ArduinoJson/Misc/SerializedValue.hpp>
|
||||
#include <ArduinoJson/Numbers/convertNumber.hpp>
|
||||
#include <ArduinoJson/Strings/JsonString.hpp>
|
||||
@ -20,6 +19,10 @@ class VariantData {
|
||||
public:
|
||||
VariantData() : _flags(VALUE_IS_NULL) {}
|
||||
|
||||
void reset() {
|
||||
_flags = VALUE_IS_NULL;
|
||||
}
|
||||
|
||||
void operator=(const VariantData& src) {
|
||||
_content = src._content;
|
||||
_flags = uint8_t((_flags & OWNED_KEY_BIT) | (src._flags & ~OWNED_KEY_BIT));
|
||||
@ -68,9 +71,17 @@ class VariantData {
|
||||
T asFloat() const;
|
||||
|
||||
JsonString asString() const;
|
||||
JsonString asRaw() const;
|
||||
|
||||
bool asBoolean() const;
|
||||
|
||||
const char* getOwnedString() const {
|
||||
if (_flags & OWNED_VALUE_BIT)
|
||||
return _content.asString.data;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CollectionData* asArray() {
|
||||
return isArray() ? &_content.asCollection : 0;
|
||||
}
|
||||
@ -91,8 +102,6 @@ class VariantData {
|
||||
return const_cast<VariantData*>(this)->asObject();
|
||||
}
|
||||
|
||||
bool copyFrom(const VariantData& src, MemoryPool* pool);
|
||||
|
||||
bool isArray() const {
|
||||
return (_flags & VALUE_IS_ARRAY) != 0;
|
||||
}
|
||||
@ -139,17 +148,6 @@ class VariantData {
|
||||
return !isFloat();
|
||||
}
|
||||
|
||||
void remove(size_t index) {
|
||||
if (isArray())
|
||||
_content.asCollection.removeElement(index);
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
void remove(TAdaptedString key) {
|
||||
if (isObject())
|
||||
_content.asCollection.removeMember(key);
|
||||
}
|
||||
|
||||
void setBoolean(bool value) {
|
||||
setType(VALUE_IS_BOOLEAN);
|
||||
_content.asBoolean = value;
|
||||
@ -160,28 +158,16 @@ class VariantData {
|
||||
_content.asFloat = value;
|
||||
}
|
||||
|
||||
void setLinkedRaw(SerializedValue<const char*> value) {
|
||||
if (value.data()) {
|
||||
setType(VALUE_IS_LINKED_RAW);
|
||||
_content.asString.data = value.data();
|
||||
_content.asString.size = value.size();
|
||||
} else {
|
||||
setType(VALUE_IS_NULL);
|
||||
}
|
||||
void setLinkedRaw(const char* data, size_t n) {
|
||||
setType(VALUE_IS_LINKED_RAW);
|
||||
_content.asString.data = data;
|
||||
_content.asString.size = n;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool storeOwnedRaw(SerializedValue<T> value, MemoryPool* pool) {
|
||||
const char* dup = pool->saveString(adaptString(value.data(), value.size()));
|
||||
if (dup) {
|
||||
setType(VALUE_IS_OWNED_RAW);
|
||||
_content.asString.data = dup;
|
||||
_content.asString.size = value.size();
|
||||
return true;
|
||||
} else {
|
||||
setType(VALUE_IS_NULL);
|
||||
return false;
|
||||
}
|
||||
void setOwnedRaw(const char* data, size_t n) {
|
||||
setType(VALUE_IS_OWNED_RAW);
|
||||
_content.asString.data = data;
|
||||
_content.asString.size = n;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -239,42 +225,17 @@ class VariantData {
|
||||
return isCollection() ? _content.asCollection.size() : 0;
|
||||
}
|
||||
|
||||
VariantData* addElement(MemoryPool* pool) {
|
||||
if (isNull())
|
||||
toArray();
|
||||
if (!isArray())
|
||||
return 0;
|
||||
return _content.asCollection.addElement(pool);
|
||||
}
|
||||
|
||||
VariantData* getElement(size_t index) const {
|
||||
const CollectionData* col = asArray();
|
||||
return col ? col->getElement(index) : 0;
|
||||
}
|
||||
|
||||
VariantData* getOrAddElement(size_t index, MemoryPool* pool) {
|
||||
if (isNull())
|
||||
toArray();
|
||||
if (!isArray())
|
||||
return 0;
|
||||
return _content.asCollection.getOrAddElement(index, pool);
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
VariantData* getMember(TAdaptedString key) const {
|
||||
const CollectionData* col = asObject();
|
||||
return col ? col->getMember(key) : 0;
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
VariantData* getOrAddMember(TAdaptedString key, MemoryPool* pool) {
|
||||
if (isNull())
|
||||
toObject();
|
||||
if (!isObject())
|
||||
return 0;
|
||||
return _content.asCollection.getOrAddMember(key, pool);
|
||||
}
|
||||
|
||||
void movePointers(ptrdiff_t variantDistance) {
|
||||
if (_flags & COLLECTION_MASK)
|
||||
_content.asCollection.movePointers(variantDistance);
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||
#include <ArduinoJson/Polyfills/attributes.hpp>
|
||||
#include <ArduinoJson/Strings/StoragePolicy.hpp>
|
||||
#include <ArduinoJson/Variant/VariantData.hpp>
|
||||
@ -11,6 +12,16 @@
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
void slotRelease(const VariantSlot* slot, MemoryPool* pool);
|
||||
bool collectionCopy(CollectionData* dst, const CollectionData* src,
|
||||
MemoryPool* pool);
|
||||
VariantData* collectionAddElement(CollectionData* array, MemoryPool* pool);
|
||||
void collectionRemoveElement(CollectionData* data, size_t index,
|
||||
MemoryPool* pool);
|
||||
template <typename TAdaptedString>
|
||||
void collectionRemoveMember(CollectionData* data, TAdaptedString key,
|
||||
MemoryPool* pool);
|
||||
|
||||
template <typename TVisitor>
|
||||
inline typename TVisitor::result_type variantAccept(const VariantData* var,
|
||||
TVisitor& visitor) {
|
||||
@ -20,6 +31,15 @@ inline typename TVisitor::result_type variantAccept(const VariantData* var,
|
||||
return visitor.visitNull();
|
||||
}
|
||||
|
||||
inline void variantRelease(const VariantData* var, MemoryPool* pool) {
|
||||
ARDUINOJSON_ASSERT(var != nullptr);
|
||||
auto c = var->asCollection();
|
||||
if (c) {
|
||||
for (auto slot = c->head(); slot; slot = slot->next())
|
||||
slotRelease(slot, pool);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool variantCopyFrom(VariantData* dst, const VariantData* src,
|
||||
MemoryPool* pool) {
|
||||
if (!dst)
|
||||
@ -28,20 +48,69 @@ inline bool variantCopyFrom(VariantData* dst, const VariantData* src,
|
||||
dst->setNull();
|
||||
return true;
|
||||
}
|
||||
return dst->copyFrom(*src, pool);
|
||||
switch (src->type()) {
|
||||
case VALUE_IS_ARRAY:
|
||||
return collectionCopy(&dst->toArray(), src->asArray(), pool);
|
||||
case VALUE_IS_OBJECT:
|
||||
return collectionCopy(&dst->toObject(), src->asObject(), pool);
|
||||
case VALUE_IS_OWNED_STRING: {
|
||||
auto str = adaptString(src->asString());
|
||||
auto dup = storeString(pool, str, StringStoragePolicy::Copy());
|
||||
if (!dup)
|
||||
return false;
|
||||
dst->setString(dup);
|
||||
return true;
|
||||
}
|
||||
case VALUE_IS_OWNED_RAW: {
|
||||
auto str = adaptString(src->asRaw());
|
||||
auto dup = storeString(pool, str, StringStoragePolicy::Copy());
|
||||
if (!dup)
|
||||
return false;
|
||||
dst->setOwnedRaw(dup.c_str(), str.size());
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
*dst = *src;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
inline void variantSetNull(VariantData* var) {
|
||||
inline void variantSetNull(VariantData* var, MemoryPool* pool) {
|
||||
if (!var)
|
||||
return;
|
||||
variantRelease(var, pool);
|
||||
var->setNull();
|
||||
}
|
||||
|
||||
inline void variantSetBoolean(VariantData* var, bool value, MemoryPool* pool) {
|
||||
if (!var)
|
||||
return;
|
||||
variantRelease(var, pool);
|
||||
var->setBoolean(value);
|
||||
}
|
||||
|
||||
inline void variantSetFloat(VariantData* var, JsonFloat value,
|
||||
MemoryPool* pool) {
|
||||
if (!var)
|
||||
return;
|
||||
variantRelease(var, pool);
|
||||
var->setFloat(value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void variantSetInteger(VariantData* var, T value, MemoryPool* pool) {
|
||||
if (!var)
|
||||
return;
|
||||
variantRelease(var, pool);
|
||||
var->setInteger(value);
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
inline void variantSetString(VariantData* var, TAdaptedString value,
|
||||
MemoryPool* pool) {
|
||||
if (!var)
|
||||
return;
|
||||
variantRelease(var, pool);
|
||||
JsonString str = storeString(pool, value);
|
||||
if (str)
|
||||
var->setString(str);
|
||||
@ -49,19 +118,46 @@ inline void variantSetString(VariantData* var, TAdaptedString value,
|
||||
var->setNull();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void variantSetOwnedRaw(VariantData* var, SerializedValue<T> value,
|
||||
MemoryPool* pool) {
|
||||
if (!var)
|
||||
return;
|
||||
variantRelease(var, pool);
|
||||
const char* dup = pool->saveString(adaptString(value.data(), value.size()));
|
||||
if (dup)
|
||||
var->setOwnedRaw(dup, value.size());
|
||||
else
|
||||
var->setNull();
|
||||
}
|
||||
|
||||
inline void variantSetLinkedRaw(VariantData* var,
|
||||
SerializedValue<const char*> value,
|
||||
MemoryPool* pool) {
|
||||
if (!var)
|
||||
return;
|
||||
variantRelease(var, pool);
|
||||
if (value.data())
|
||||
var->setLinkedRaw(value.data(), value.size());
|
||||
else
|
||||
var->setNull();
|
||||
}
|
||||
|
||||
inline size_t variantSize(const VariantData* var) {
|
||||
return var != 0 ? var->size() : 0;
|
||||
}
|
||||
|
||||
inline CollectionData* variantToArray(VariantData* var) {
|
||||
inline CollectionData* variantToArray(VariantData* var, MemoryPool* pool) {
|
||||
if (!var)
|
||||
return 0;
|
||||
variantRelease(var, pool);
|
||||
return &var->toArray();
|
||||
}
|
||||
|
||||
inline CollectionData* variantToObject(VariantData* var) {
|
||||
inline CollectionData* variantToObject(VariantData* var, MemoryPool* pool) {
|
||||
if (!var)
|
||||
return 0;
|
||||
variantRelease(var, pool);
|
||||
return &var->toObject();
|
||||
}
|
||||
|
||||
@ -69,15 +165,43 @@ inline VariantData* variantGetElement(const VariantData* var, size_t index) {
|
||||
return var != 0 ? var->getElement(index) : 0;
|
||||
}
|
||||
|
||||
inline NO_INLINE VariantData* variantAddElement(VariantData* var,
|
||||
MemoryPool* pool) {
|
||||
return var != 0 ? var->addElement(pool) : 0;
|
||||
inline VariantData* variantAddElement(VariantData* var, MemoryPool* pool) {
|
||||
if (!var)
|
||||
return nullptr;
|
||||
auto array = var->isNull() ? &var->toArray() : var->asArray();
|
||||
return collectionAddElement(array, pool);
|
||||
}
|
||||
|
||||
inline NO_INLINE VariantData* variantGetOrAddElement(VariantData* var,
|
||||
size_t index,
|
||||
MemoryPool* pool) {
|
||||
return var != 0 ? var->getOrAddElement(index, pool) : 0;
|
||||
if (!var)
|
||||
return nullptr;
|
||||
auto array = var->isNull() ? &var->toArray() : var->asArray();
|
||||
if (!array)
|
||||
return nullptr;
|
||||
VariantSlot* slot = array->head();
|
||||
while (slot && index > 0) {
|
||||
slot = slot->next();
|
||||
index--;
|
||||
}
|
||||
if (!slot)
|
||||
index++;
|
||||
while (index > 0) {
|
||||
slot = pool->allocVariant();
|
||||
if (!slot)
|
||||
return nullptr;
|
||||
array->addSlot(slot);
|
||||
index--;
|
||||
}
|
||||
return slot->data();
|
||||
}
|
||||
|
||||
inline void variantRemoveElement(VariantData* var, size_t index,
|
||||
MemoryPool* pool) {
|
||||
if (!var)
|
||||
return;
|
||||
collectionRemoveElement(var->asArray(), index, pool);
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
@ -90,9 +214,23 @@ VariantData* variantGetMember(const VariantData* var, TAdaptedString key) {
|
||||
template <typename TAdaptedString>
|
||||
VariantData* variantGetOrAddMember(VariantData* var, TAdaptedString key,
|
||||
MemoryPool* pool) {
|
||||
if (!var || key.isNull())
|
||||
return nullptr;
|
||||
auto obj = var->isNull() ? &var->toObject() : var->asObject();
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
auto slot = obj->getSlot(key);
|
||||
if (slot)
|
||||
return slot->data();
|
||||
return collectionAddMember(obj, key, pool);
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
void variantRemoveMember(VariantData* var, TAdaptedString key,
|
||||
MemoryPool* pool) {
|
||||
if (!var)
|
||||
return 0;
|
||||
return var->getOrAddMember(key, pool);
|
||||
return;
|
||||
collectionRemoveMember(var->asObject(), key, pool);
|
||||
}
|
||||
|
||||
inline bool variantIsNull(const VariantData* var) {
|
||||
|
@ -83,26 +83,16 @@ inline JsonString VariantData::asString() const {
|
||||
}
|
||||
}
|
||||
|
||||
inline bool VariantData::copyFrom(const VariantData& src, MemoryPool* pool) {
|
||||
switch (src.type()) {
|
||||
case VALUE_IS_ARRAY:
|
||||
return toArray().copyFrom(src._content.asCollection, pool);
|
||||
case VALUE_IS_OBJECT:
|
||||
return toObject().copyFrom(src._content.asCollection, pool);
|
||||
case VALUE_IS_OWNED_STRING: {
|
||||
auto str = storeString(pool, adaptString(src.asString()),
|
||||
StringStoragePolicy::Copy());
|
||||
setString(str);
|
||||
return !str.isNull();
|
||||
}
|
||||
inline JsonString VariantData::asRaw() const {
|
||||
switch (type()) {
|
||||
case VALUE_IS_LINKED_RAW:
|
||||
return JsonString(_content.asString.data, _content.asString.size,
|
||||
JsonString::Linked);
|
||||
case VALUE_IS_OWNED_RAW:
|
||||
return storeOwnedRaw(
|
||||
serialized(src._content.asString.data, src._content.asString.size),
|
||||
pool);
|
||||
return JsonString(_content.asString.data, _content.asString.size,
|
||||
JsonString::Copied);
|
||||
default:
|
||||
setType(src.type());
|
||||
_content = src._content;
|
||||
return true;
|
||||
return JsonString();
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,21 +116,21 @@ template <typename TDerived>
|
||||
template <typename T>
|
||||
inline typename enable_if<is_same<T, JsonArray>::value, JsonArray>::type
|
||||
VariantRefBase<TDerived>::to() const {
|
||||
return JsonArray(getPool(), variantToArray(getOrCreateData()));
|
||||
return JsonArray(getPool(), variantToArray(getOrCreateData(), getPool()));
|
||||
}
|
||||
|
||||
template <typename TDerived>
|
||||
template <typename T>
|
||||
typename enable_if<is_same<T, JsonObject>::value, JsonObject>::type
|
||||
VariantRefBase<TDerived>::to() const {
|
||||
return JsonObject(getPool(), variantToObject(getOrCreateData()));
|
||||
return JsonObject(getPool(), variantToObject(getOrCreateData(), getPool()));
|
||||
}
|
||||
|
||||
template <typename TDerived>
|
||||
template <typename T>
|
||||
typename enable_if<is_same<T, JsonVariant>::value, JsonVariant>::type
|
||||
VariantRefBase<TDerived>::to() const {
|
||||
variantSetNull(getOrCreateData());
|
||||
variantSetNull(getOrCreateData(), getPool());
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,7 @@ class VariantRefBase : public VariantTag {
|
||||
// ⚠️ Doesn't release the memory associated with the previous value.
|
||||
// https://arduinojson.org/v6/api/jsonvariant/clear/
|
||||
FORCE_INLINE void clear() const {
|
||||
variantSetNull(getData());
|
||||
variantSetNull(getOrCreateData(), getPool());
|
||||
}
|
||||
|
||||
// Returns true if the value is null or the reference is unbound.
|
||||
@ -112,11 +112,10 @@ class VariantRefBase : public VariantTag {
|
||||
VariantData* data = getOrCreateData();
|
||||
if (!data)
|
||||
return;
|
||||
variantSetNull(data, getPool());
|
||||
const VariantData* targetData = VariantAttorney::getData(target);
|
||||
if (targetData)
|
||||
*data = *targetData;
|
||||
else
|
||||
data->setNull();
|
||||
}
|
||||
|
||||
// Copies the specified value.
|
||||
@ -179,9 +178,7 @@ class VariantRefBase : public VariantTag {
|
||||
// ⚠️ Doesn't release the memory associated with the removed element.
|
||||
// https://arduinojson.org/v6/api/jsonvariant/remove/
|
||||
FORCE_INLINE void remove(size_t index) const {
|
||||
VariantData* data = getData();
|
||||
if (data)
|
||||
data->remove(index);
|
||||
variantRemoveElement(getData(), index, getPool());
|
||||
}
|
||||
|
||||
// Removes a member of the object.
|
||||
@ -190,9 +187,7 @@ class VariantRefBase : public VariantTag {
|
||||
template <typename TChar>
|
||||
FORCE_INLINE typename enable_if<IsString<TChar*>::value>::type remove(
|
||||
TChar* key) const {
|
||||
VariantData* data = getData();
|
||||
if (data)
|
||||
data->remove(adaptString(key));
|
||||
variantRemoveMember(getData(), adaptString(key), getPool());
|
||||
}
|
||||
|
||||
// Removes a member of the object.
|
||||
@ -201,9 +196,7 @@ class VariantRefBase : public VariantTag {
|
||||
template <typename TString>
|
||||
FORCE_INLINE typename enable_if<IsString<TString>::value>::type remove(
|
||||
const TString& key) const {
|
||||
VariantData* data = getData();
|
||||
if (data)
|
||||
data->remove(adaptString(key));
|
||||
variantRemoveMember(getData(), adaptString(key), getPool());
|
||||
}
|
||||
|
||||
// Creates an array and appends it to the array.
|
||||
|
Reference in New Issue
Block a user