mirror of
https://github.com/bblanchon/ArduinoJson.git
synced 2025-07-16 03:52:16 +02:00
Store index of slot in the pool instead of a pointer or a distance
This commit is contained in:
@ -4,8 +4,7 @@ static_assert(ARDUINOJSON_ENABLE_PROGMEM == 1, "ARDUINOJSON_ENABLE_PROGMEM");
|
||||
|
||||
static_assert(ARDUINOJSON_USE_LONG_LONG == 0, "ARDUINOJSON_USE_LONG_LONG");
|
||||
|
||||
static_assert(ARDUINOJSON_SLOT_OFFSET_SIZE == 1,
|
||||
"ARDUINOJSON_SLOT_OFFSET_SIZE");
|
||||
static_assert(ARDUINOJSON_SLOT_ID_SIZE == 1, "ARDUINOJSON_SLOT_ID_SIZE");
|
||||
|
||||
static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN");
|
||||
|
||||
|
@ -2,8 +2,7 @@
|
||||
|
||||
static_assert(ARDUINOJSON_USE_LONG_LONG == 1, "ARDUINOJSON_USE_LONG_LONG");
|
||||
|
||||
static_assert(ARDUINOJSON_SLOT_OFFSET_SIZE == 2,
|
||||
"ARDUINOJSON_SLOT_OFFSET_SIZE");
|
||||
static_assert(ARDUINOJSON_SLOT_ID_SIZE == 2, "ARDUINOJSON_SLOT_ID_SIZE");
|
||||
|
||||
static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN");
|
||||
|
||||
|
@ -2,14 +2,13 @@
|
||||
|
||||
static_assert(ARDUINOJSON_USE_LONG_LONG == 1, "ARDUINOJSON_USE_LONG_LONG");
|
||||
|
||||
static_assert(ARDUINOJSON_SLOT_OFFSET_SIZE == 4,
|
||||
"ARDUINOJSON_SLOT_OFFSET_SIZE");
|
||||
static_assert(ARDUINOJSON_SLOT_ID_SIZE == 4, "ARDUINOJSON_SLOT_ID_SIZE");
|
||||
|
||||
static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN");
|
||||
|
||||
static_assert(ARDUINOJSON_USE_DOUBLE == 1, "ARDUINOJSON_USE_DOUBLE");
|
||||
|
||||
static_assert(sizeof(ArduinoJson::detail::VariantSlot) == 32,
|
||||
static_assert(sizeof(ArduinoJson::detail::VariantSlot) == 24,
|
||||
"sizeof(VariantSlot)");
|
||||
|
||||
int main() {}
|
||||
|
@ -2,8 +2,7 @@
|
||||
|
||||
static_assert(ARDUINOJSON_USE_LONG_LONG == 1, "ARDUINOJSON_USE_LONG_LONG");
|
||||
|
||||
static_assert(ARDUINOJSON_SLOT_OFFSET_SIZE == 2,
|
||||
"ARDUINOJSON_SLOT_OFFSET_SIZE");
|
||||
static_assert(ARDUINOJSON_SLOT_ID_SIZE == 2, "ARDUINOJSON_SLOT_ID_SIZE");
|
||||
|
||||
static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN");
|
||||
|
||||
|
@ -31,7 +31,8 @@ TEST_CASE("JsonDocument assignment") {
|
||||
}
|
||||
|
||||
SECTION("Copy assignment reallocates when capacity is smaller") {
|
||||
JsonDocument doc1(4096, &spyingAllocator);
|
||||
const size_t capacity = 100 * sizeof(ArduinoJson::detail::VariantSlot);
|
||||
JsonDocument doc1(capacity, &spyingAllocator);
|
||||
deserializeJson(doc1, "[{\"hello\":\"world\"}]");
|
||||
JsonDocument doc2(sizeofArray(1), &spyingAllocator);
|
||||
spyingAllocator.clearLog();
|
||||
@ -41,14 +42,15 @@ TEST_CASE("JsonDocument assignment") {
|
||||
REQUIRE(doc2.as<std::string>() == "[{\"hello\":\"world\"}]");
|
||||
REQUIRE(spyingAllocator.log() ==
|
||||
AllocatorLog() << AllocatorLog::Deallocate(sizeofArray(1))
|
||||
<< AllocatorLog::Allocate(4096)
|
||||
<< AllocatorLog::Allocate(capacity)
|
||||
<< AllocatorLog::Allocate(sizeofString(5)) // hello
|
||||
<< AllocatorLog::Allocate(sizeofString(5)) // world
|
||||
);
|
||||
}
|
||||
|
||||
SECTION("Copy assignment reallocates when capacity is larger") {
|
||||
JsonDocument doc1(1024, &spyingAllocator);
|
||||
const size_t capacity1 = 100 * sizeof(ArduinoJson::detail::VariantSlot);
|
||||
JsonDocument doc1(capacity1, &spyingAllocator);
|
||||
deserializeJson(doc1, "{\"hello\":\"world\"}");
|
||||
JsonDocument doc2(4096, &spyingAllocator);
|
||||
spyingAllocator.clearLog();
|
||||
@ -58,7 +60,7 @@ TEST_CASE("JsonDocument assignment") {
|
||||
REQUIRE(doc2.as<std::string>() == "{\"hello\":\"world\"}");
|
||||
REQUIRE(spyingAllocator.log() ==
|
||||
AllocatorLog() << AllocatorLog::Deallocate(4096)
|
||||
<< AllocatorLog::Allocate(1024)
|
||||
<< AllocatorLog::Allocate(capacity1)
|
||||
<< AllocatorLog::Allocate(sizeofString(5)) // hello
|
||||
<< AllocatorLog::Allocate(sizeofString(5)) // world
|
||||
);
|
||||
|
@ -22,8 +22,9 @@ TEST_CASE("JsonDocument constructor") {
|
||||
}
|
||||
|
||||
SECTION("JsonDocument(const JsonDocument&)") {
|
||||
const size_t capacity = 100 * sizeof(ArduinoJson::detail::VariantSlot);
|
||||
{
|
||||
JsonDocument doc1(4096, &spyingAllocator);
|
||||
JsonDocument doc1(capacity, &spyingAllocator);
|
||||
doc1.set(std::string("The size of this string is 32!!"));
|
||||
|
||||
JsonDocument doc2(doc1);
|
||||
@ -32,14 +33,14 @@ TEST_CASE("JsonDocument constructor") {
|
||||
REQUIRE(doc2.as<std::string>() == "The size of this string is 32!!");
|
||||
}
|
||||
REQUIRE(spyingAllocator.log() ==
|
||||
AllocatorLog() << AllocatorLog::Allocate(4096)
|
||||
AllocatorLog() << AllocatorLog::Allocate(capacity)
|
||||
<< AllocatorLog::Allocate(sizeofString(31))
|
||||
<< AllocatorLog::Allocate(4096)
|
||||
<< AllocatorLog::Allocate(capacity)
|
||||
<< AllocatorLog::Allocate(sizeofString(31))
|
||||
<< AllocatorLog::Deallocate(sizeofString(31))
|
||||
<< AllocatorLog::Deallocate(4096)
|
||||
<< AllocatorLog::Deallocate(capacity)
|
||||
<< AllocatorLog::Deallocate(sizeofString(31))
|
||||
<< AllocatorLog::Deallocate(4096));
|
||||
<< AllocatorLog::Deallocate(capacity));
|
||||
}
|
||||
|
||||
SECTION("JsonDocument(JsonDocument&&)") {
|
||||
|
@ -13,9 +13,10 @@ using ArduinoJson::detail::sizeofObject;
|
||||
using ArduinoJson::detail::sizeofString;
|
||||
|
||||
TEST_CASE("JsonDocument::garbageCollect()") {
|
||||
const size_t capacity = 100 * sizeof(ArduinoJson::detail::VariantSlot);
|
||||
ControllableAllocator controllableAllocator;
|
||||
SpyingAllocator spyingAllocator(&controllableAllocator);
|
||||
JsonDocument doc(4096, &spyingAllocator);
|
||||
JsonDocument doc(capacity, &spyingAllocator);
|
||||
|
||||
SECTION("when allocation succeeds") {
|
||||
deserializeJson(doc, "{\"blanket\":1,\"dancing\":2}");
|
||||
@ -29,10 +30,10 @@ TEST_CASE("JsonDocument::garbageCollect()") {
|
||||
REQUIRE(doc.memoryUsage() == sizeofObject(1) + sizeofString(7));
|
||||
REQUIRE(doc.as<std::string>() == "{\"dancing\":2}");
|
||||
REQUIRE(spyingAllocator.log() ==
|
||||
AllocatorLog() << AllocatorLog::Allocate(4096)
|
||||
AllocatorLog() << AllocatorLog::Allocate(capacity)
|
||||
<< AllocatorLog::Allocate(sizeofString(7))
|
||||
<< AllocatorLog::Deallocate(sizeofString(7))
|
||||
<< AllocatorLog::Deallocate(4096));
|
||||
<< AllocatorLog::Deallocate(capacity));
|
||||
}
|
||||
|
||||
SECTION("when allocation fails") {
|
||||
@ -49,7 +50,7 @@ TEST_CASE("JsonDocument::garbageCollect()") {
|
||||
REQUIRE(doc.as<std::string>() == "{\"dancing\":2}");
|
||||
|
||||
REQUIRE(spyingAllocator.log() ==
|
||||
AllocatorLog() << AllocatorLog::AllocateFail(4096)
|
||||
AllocatorLog() << AllocatorLog::AllocateFail(capacity)
|
||||
<< AllocatorLog::AllocateFail(sizeofString(7)));
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
// Copyright © 2014-2023, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#define ARDUINOJSON_SLOT_ID_SIZE 4 // required to reach 65536 elements
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
@ -55,6 +57,7 @@ TEST_CASE("serialize MsgPack array") {
|
||||
const char* nil = 0;
|
||||
for (int i = 0; i < 65536; i++)
|
||||
array.add(nil);
|
||||
REQUIRE(array.size() == 65536);
|
||||
|
||||
check(array,
|
||||
std::string("\xDD\x00\x01\x00\x00", 5) + std::string(65536, '\xc0'));
|
||||
|
@ -11,13 +11,13 @@
|
||||
|
||||
using namespace ArduinoJson::detail;
|
||||
|
||||
TEST_CASE("ResourceManager::allocVariant()") {
|
||||
TEST_CASE("ResourceManager::allocSlot()") {
|
||||
SECTION("Returns different pointer") {
|
||||
ResourceManager resources(4096);
|
||||
|
||||
VariantSlot* s1 = resources.allocVariant();
|
||||
VariantSlot* s1 = resources.allocSlot();
|
||||
REQUIRE(s1 != 0);
|
||||
VariantSlot* s2 = resources.allocVariant();
|
||||
VariantSlot* s2 = resources.allocSlot();
|
||||
REQUIRE(s2 != 0);
|
||||
|
||||
REQUIRE(s1 != s2);
|
||||
@ -26,27 +26,33 @@ TEST_CASE("ResourceManager::allocVariant()") {
|
||||
SECTION("Returns aligned pointers") {
|
||||
ResourceManager resources(4096);
|
||||
|
||||
REQUIRE(isAligned(resources.allocVariant()));
|
||||
REQUIRE(isAligned(resources.allocVariant()));
|
||||
REQUIRE(isAligned(resources.allocSlot().operator VariantSlot*()));
|
||||
REQUIRE(isAligned(resources.allocSlot().operator VariantSlot*()));
|
||||
}
|
||||
|
||||
SECTION("Returns zero if capacity is 0") {
|
||||
ResourceManager resources(0);
|
||||
|
||||
REQUIRE(resources.allocVariant() == 0);
|
||||
auto variant = resources.allocSlot();
|
||||
REQUIRE(variant.id() == NULL_SLOT);
|
||||
REQUIRE(static_cast<VariantSlot*>(variant) == nullptr);
|
||||
}
|
||||
|
||||
SECTION("Returns zero if buffer is null") {
|
||||
ResourceManager resources(4096, FailingAllocator::instance());
|
||||
|
||||
REQUIRE(resources.allocVariant() == 0);
|
||||
auto variant = resources.allocSlot();
|
||||
REQUIRE(variant.id() == NULL_SLOT);
|
||||
REQUIRE(static_cast<VariantSlot*>(variant) == nullptr);
|
||||
}
|
||||
|
||||
SECTION("Returns zero if capacity is insufficient") {
|
||||
ResourceManager resources(sizeof(VariantSlot));
|
||||
|
||||
resources.allocVariant();
|
||||
resources.allocSlot();
|
||||
|
||||
REQUIRE(resources.allocVariant() == 0);
|
||||
auto variant = resources.allocSlot();
|
||||
REQUIRE(variant.id() == NULL_SLOT);
|
||||
REQUIRE(static_cast<VariantSlot*>(variant) == nullptr);
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ TEST_CASE("ResourceManager::clear()") {
|
||||
ResourceManager resources(poolCapacity);
|
||||
|
||||
SECTION("Discards allocated variants") {
|
||||
resources.allocVariant();
|
||||
resources.allocSlot();
|
||||
|
||||
resources.clear();
|
||||
REQUIRE(resources.size() == 0);
|
||||
|
@ -9,7 +9,7 @@
|
||||
using namespace ArduinoJson::detail;
|
||||
|
||||
TEST_CASE("ResourceManager::capacity()") {
|
||||
const size_t capacity = 64;
|
||||
const size_t capacity = 4 * sizeof(VariantSlot);
|
||||
ResourceManager resources(capacity);
|
||||
REQUIRE(capacity == resources.capacity());
|
||||
}
|
||||
@ -25,10 +25,10 @@ TEST_CASE("ResourceManager::size()") {
|
||||
const size_t variantCount = resources.capacity() / sizeof(VariantSlot);
|
||||
|
||||
for (size_t i = 0; i < variantCount; i++)
|
||||
resources.allocVariant();
|
||||
resources.allocSlot();
|
||||
size_t size = resources.size();
|
||||
|
||||
resources.allocVariant();
|
||||
resources.allocSlot();
|
||||
|
||||
REQUIRE(size == resources.size());
|
||||
}
|
||||
|
@ -22,12 +22,13 @@ class ArrayData : public CollectionData {
|
||||
|
||||
VariantData* getOrAddElement(size_t index, ResourceManager* resources);
|
||||
|
||||
VariantData* getElement(size_t index) const;
|
||||
VariantData* getElement(size_t index, const ResourceManager* resources) const;
|
||||
|
||||
static VariantData* getElement(const ArrayData* array, size_t index) {
|
||||
static VariantData* getElement(const ArrayData* array, size_t index,
|
||||
const ResourceManager* resources) {
|
||||
if (!array)
|
||||
return nullptr;
|
||||
return array->getElement(index);
|
||||
return array->getElement(index, resources);
|
||||
}
|
||||
|
||||
void removeElement(size_t index, ResourceManager* resources);
|
||||
@ -50,7 +51,7 @@ class ArrayData : public CollectionData {
|
||||
}
|
||||
|
||||
private:
|
||||
iterator at(size_t index) const;
|
||||
iterator at(size_t index, const ResourceManager* resources) const;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
@ -9,10 +9,11 @@
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
inline ArrayData::iterator ArrayData::at(size_t index) const {
|
||||
auto it = createIterator();
|
||||
inline ArrayData::iterator ArrayData::at(
|
||||
size_t index, const ResourceManager* resources) const {
|
||||
auto it = createIterator(resources);
|
||||
while (!it.done() && index) {
|
||||
it.next();
|
||||
it.next(resources);
|
||||
--index;
|
||||
}
|
||||
return it;
|
||||
@ -20,9 +21,9 @@ inline ArrayData::iterator ArrayData::at(size_t index) const {
|
||||
|
||||
inline VariantData* ArrayData::getOrAddElement(size_t index,
|
||||
ResourceManager* resources) {
|
||||
auto it = createIterator();
|
||||
auto it = createIterator(resources);
|
||||
while (!it.done() && index > 0) {
|
||||
it.next();
|
||||
it.next(resources);
|
||||
index--;
|
||||
}
|
||||
if (it.done())
|
||||
@ -37,12 +38,13 @@ inline VariantData* ArrayData::getOrAddElement(size_t index,
|
||||
return element;
|
||||
}
|
||||
|
||||
inline VariantData* ArrayData::getElement(size_t index) const {
|
||||
return at(index).data();
|
||||
inline VariantData* ArrayData::getElement(
|
||||
size_t index, const ResourceManager* resources) const {
|
||||
return at(index, resources).data();
|
||||
}
|
||||
|
||||
inline void ArrayData::removeElement(size_t index, ResourceManager* resources) {
|
||||
remove(at(index), resources);
|
||||
remove(at(index, resources), resources);
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
@ -45,7 +45,9 @@ class ElementProxy : public VariantRefBase<ElementProxy<TUpstream>>,
|
||||
}
|
||||
|
||||
FORCE_INLINE VariantData* getData() const {
|
||||
return VariantData::getElement(VariantAttorney::getData(upstream_), index_);
|
||||
return VariantData::getElement(
|
||||
VariantAttorney::getData(upstream_), index_,
|
||||
VariantAttorney::getResourceManager(upstream_));
|
||||
}
|
||||
|
||||
FORCE_INLINE VariantData* getOrCreateData() const {
|
||||
|
@ -68,7 +68,7 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
|
||||
FORCE_INLINE iterator begin() const {
|
||||
if (!data_)
|
||||
return iterator();
|
||||
return iterator(data_->createIterator(), resources_);
|
||||
return iterator(data_->createIterator(resources_), resources_);
|
||||
}
|
||||
|
||||
// Returns an iterator following the last element of the array.
|
||||
@ -148,19 +148,19 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
|
||||
// Returns the number of bytes occupied by the array.
|
||||
// https://arduinojson.org/v6/api/jsonarray/memoryusage/
|
||||
FORCE_INLINE size_t memoryUsage() const {
|
||||
return data_ ? data_->memoryUsage() : 0;
|
||||
return data_ ? data_->memoryUsage(resources_) : 0;
|
||||
}
|
||||
|
||||
// Returns the depth (nesting level) of the array.
|
||||
// https://arduinojson.org/v6/api/jsonarray/nesting/
|
||||
FORCE_INLINE size_t nesting() const {
|
||||
return detail::VariantData::nesting(collectionToVariant(data_));
|
||||
return detail::VariantData::nesting(collectionToVariant(data_), resources_);
|
||||
}
|
||||
|
||||
// Returns the number of elements in the array.
|
||||
// https://arduinojson.org/v6/api/jsonarray/size/
|
||||
FORCE_INLINE size_t size() const {
|
||||
return data_ ? data_->size() : 0;
|
||||
return data_ ? data_->size(resources_) : 0;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -26,7 +26,7 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
|
||||
FORCE_INLINE iterator begin() const {
|
||||
if (!data_)
|
||||
return iterator();
|
||||
return iterator(data_->createIterator(), resources_);
|
||||
return iterator(data_->createIterator(resources_), resources_);
|
||||
}
|
||||
|
||||
// Returns an iterator to the element following the last element of the array.
|
||||
@ -46,8 +46,8 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
|
||||
// Returns the element at the specified index.
|
||||
// https://arduinojson.org/v6/api/jsonarrayconst/subscript/
|
||||
FORCE_INLINE JsonVariantConst operator[](size_t index) const {
|
||||
return JsonVariantConst(detail::ArrayData::getElement(data_, index),
|
||||
resources_);
|
||||
return JsonVariantConst(
|
||||
detail::ArrayData::getElement(data_, index, resources_), resources_);
|
||||
}
|
||||
|
||||
operator JsonVariantConst() const {
|
||||
@ -69,19 +69,19 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
|
||||
// Returns the number of bytes occupied by the array.
|
||||
// https://arduinojson.org/v6/api/jsonarrayconst/memoryusage/
|
||||
FORCE_INLINE size_t memoryUsage() const {
|
||||
return data_ ? data_->memoryUsage() : 0;
|
||||
return data_ ? data_->memoryUsage(resources_) : 0;
|
||||
}
|
||||
|
||||
// Returns the depth (nesting level) of the array.
|
||||
// https://arduinojson.org/v6/api/jsonarrayconst/nesting/
|
||||
FORCE_INLINE size_t nesting() const {
|
||||
return detail::VariantData::nesting(collectionToVariant(data_));
|
||||
return detail::VariantData::nesting(collectionToVariant(data_), resources_);
|
||||
}
|
||||
|
||||
// Returns the number of elements in the array.
|
||||
// https://arduinojson.org/v6/api/jsonarrayconst/size/
|
||||
FORCE_INLINE size_t size() const {
|
||||
return data_ ? data_->size() : 0;
|
||||
return data_ ? data_->size(resources_) : 0;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -50,7 +50,7 @@ class JsonArrayIterator {
|
||||
}
|
||||
|
||||
JsonArrayIterator& operator++() {
|
||||
iterator_.next();
|
||||
iterator_.next(resources_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -84,7 +84,7 @@ class JsonArrayConstIterator {
|
||||
}
|
||||
|
||||
JsonArrayConstIterator& operator++() {
|
||||
iterator_.next();
|
||||
iterator_.next(resources_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ class CollectionIterator {
|
||||
public:
|
||||
CollectionIterator() : slot_(nullptr) {}
|
||||
|
||||
void next();
|
||||
void next(const ResourceManager* resources);
|
||||
|
||||
bool done() const {
|
||||
return slot_ == nullptr;
|
||||
@ -70,8 +70,8 @@ class CollectionIterator {
|
||||
};
|
||||
|
||||
class CollectionData {
|
||||
VariantSlot* head_ = 0;
|
||||
VariantSlot* tail_ = 0;
|
||||
SlotId head_ = NULL_SLOT;
|
||||
SlotId tail_ = NULL_SLOT;
|
||||
|
||||
public:
|
||||
// Placement new
|
||||
@ -83,13 +83,13 @@ class CollectionData {
|
||||
|
||||
using iterator = CollectionIterator;
|
||||
|
||||
iterator createIterator() const {
|
||||
return iterator(head_);
|
||||
iterator createIterator(const ResourceManager* resources) const {
|
||||
return iterator(resources->getSlot(head_));
|
||||
}
|
||||
|
||||
size_t memoryUsage() const;
|
||||
size_t size() const;
|
||||
size_t nesting() const;
|
||||
size_t memoryUsage(const ResourceManager*) const;
|
||||
size_t size(const ResourceManager*) const;
|
||||
size_t nesting(const ResourceManager*) const;
|
||||
|
||||
void clear(ResourceManager* resources);
|
||||
|
||||
@ -99,8 +99,6 @@ class CollectionData {
|
||||
collection->clear(resources);
|
||||
}
|
||||
|
||||
void movePointers(ptrdiff_t variantDistance);
|
||||
|
||||
void remove(iterator it, ResourceManager* resources);
|
||||
|
||||
static void remove(CollectionData* collection, iterator it,
|
||||
@ -113,7 +111,7 @@ class CollectionData {
|
||||
iterator addSlot(ResourceManager*);
|
||||
|
||||
private:
|
||||
VariantSlot* getPreviousSlot(VariantSlot*) const;
|
||||
SlotWithId getPreviousSlot(VariantSlot*, const ResourceManager*) const;
|
||||
static void releaseSlot(VariantSlot*, ResourceManager*);
|
||||
};
|
||||
|
||||
|
@ -34,102 +34,95 @@ inline bool CollectionIterator::ownsKey() const {
|
||||
return slot_->ownsKey();
|
||||
}
|
||||
|
||||
inline void CollectionIterator::next() {
|
||||
inline void CollectionIterator::next(const ResourceManager* resources) {
|
||||
ARDUINOJSON_ASSERT(slot_ != nullptr);
|
||||
slot_ = slot_->next();
|
||||
auto nextId = slot_->next();
|
||||
if (nextId != NULL_SLOT)
|
||||
slot_ = resources->getSlot(nextId);
|
||||
else
|
||||
slot_ = nullptr;
|
||||
}
|
||||
|
||||
inline CollectionData::iterator CollectionData::addSlot(
|
||||
ResourceManager* resources) {
|
||||
auto slot = resources->allocVariant();
|
||||
auto slot = resources->allocSlot();
|
||||
if (!slot)
|
||||
return nullptr;
|
||||
if (tail_) {
|
||||
tail_->setNextNotNull(slot);
|
||||
tail_ = slot;
|
||||
if (tail_ != NULL_SLOT) {
|
||||
auto tail = resources->getSlot(tail_);
|
||||
tail->setNext(slot.id());
|
||||
tail_ = slot.id();
|
||||
} else {
|
||||
head_ = slot;
|
||||
tail_ = slot;
|
||||
head_ = slot.id();
|
||||
tail_ = slot.id();
|
||||
}
|
||||
return slot;
|
||||
return iterator(slot);
|
||||
}
|
||||
|
||||
inline void CollectionData::clear(ResourceManager* resources) {
|
||||
for (auto slot = head_; slot; slot = slot->next())
|
||||
releaseSlot(slot, resources);
|
||||
head_ = 0;
|
||||
tail_ = 0;
|
||||
for (auto it = createIterator(resources); !it.done(); it.next(resources))
|
||||
releaseSlot(it.slot_, resources);
|
||||
head_ = NULL_SLOT;
|
||||
tail_ = NULL_SLOT;
|
||||
}
|
||||
|
||||
inline VariantSlot* CollectionData::getPreviousSlot(VariantSlot* target) const {
|
||||
VariantSlot* current = head_;
|
||||
while (current) {
|
||||
VariantSlot* next = current->next();
|
||||
if (next == target)
|
||||
return current;
|
||||
current = next;
|
||||
inline SlotWithId CollectionData::getPreviousSlot(
|
||||
VariantSlot* target, const ResourceManager* resources) const {
|
||||
auto prev = SlotWithId();
|
||||
auto currentId = head_;
|
||||
while (currentId != NULL_SLOT) {
|
||||
auto currentSlot = resources->getSlot(currentId);
|
||||
if (currentSlot == target)
|
||||
return prev;
|
||||
prev = SlotWithId(currentSlot, currentId);
|
||||
currentId = currentSlot->next();
|
||||
}
|
||||
return 0;
|
||||
return SlotWithId();
|
||||
}
|
||||
|
||||
inline void CollectionData::remove(iterator it, ResourceManager* resources) {
|
||||
if (it.done())
|
||||
return;
|
||||
auto curr = it.slot_;
|
||||
auto prev = getPreviousSlot(curr);
|
||||
auto prev = getPreviousSlot(curr, resources);
|
||||
auto next = curr->next();
|
||||
if (prev)
|
||||
prev->setNext(next);
|
||||
else
|
||||
head_ = next;
|
||||
if (!next)
|
||||
tail_ = prev;
|
||||
if (next == NULL_SLOT)
|
||||
tail_ = prev.id();
|
||||
releaseSlot(curr, resources);
|
||||
}
|
||||
|
||||
inline size_t CollectionData::memoryUsage() const {
|
||||
inline size_t CollectionData::memoryUsage(
|
||||
const ResourceManager* resources) const {
|
||||
size_t total = 0;
|
||||
for (auto it = createIterator(); !it.done(); it.next()) {
|
||||
total += sizeof(VariantSlot) + it->memoryUsage();
|
||||
for (auto it = createIterator(resources); !it.done(); it.next(resources)) {
|
||||
total += sizeof(VariantSlot) + it->memoryUsage(resources);
|
||||
if (it.ownsKey())
|
||||
total += sizeofString(strlen(it.key()));
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
inline size_t CollectionData::nesting() const {
|
||||
inline size_t CollectionData::nesting(const ResourceManager* resources) const {
|
||||
size_t maxChildNesting = 0;
|
||||
for (auto it = createIterator(); !it.done(); it.next()) {
|
||||
size_t childNesting = it->nesting();
|
||||
for (auto it = createIterator(resources); !it.done(); it.next(resources)) {
|
||||
size_t childNesting = it->nesting(resources);
|
||||
if (childNesting > maxChildNesting)
|
||||
maxChildNesting = childNesting;
|
||||
}
|
||||
return maxChildNesting + 1;
|
||||
}
|
||||
|
||||
inline size_t CollectionData::size() const {
|
||||
inline size_t CollectionData::size(const ResourceManager* resources) const {
|
||||
size_t count = 0;
|
||||
for (auto it = createIterator(); !it.done(); it.next())
|
||||
for (auto it = createIterator(resources); !it.done(); it.next(resources))
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void movePointer(T*& p, ptrdiff_t offset) {
|
||||
if (!p)
|
||||
return;
|
||||
p = reinterpret_cast<T*>(
|
||||
reinterpret_cast<void*>(reinterpret_cast<char*>(p) + offset));
|
||||
ARDUINOJSON_ASSERT(isAligned(p));
|
||||
}
|
||||
|
||||
inline void CollectionData::movePointers(ptrdiff_t variantDistance) {
|
||||
movePointer(head_, variantDistance);
|
||||
movePointer(tail_, variantDistance);
|
||||
for (VariantSlot* slot = head_; slot; slot = slot->next())
|
||||
slot->data()->movePointers(variantDistance);
|
||||
}
|
||||
|
||||
inline void CollectionData::releaseSlot(VariantSlot* slot,
|
||||
ResourceManager* resources) {
|
||||
ARDUINOJSON_ASSERT(slot != nullptr);
|
||||
|
@ -75,19 +75,18 @@
|
||||
# define ARDUINOJSON_DEFAULT_NESTING_LIMIT 10
|
||||
#endif
|
||||
|
||||
// Number of bits to store the pointer to next node
|
||||
// (saves RAM but limits the number of values in a document)
|
||||
#ifndef ARDUINOJSON_SLOT_OFFSET_SIZE
|
||||
// Number of bits to store the variant identifier
|
||||
#ifndef ARDUINOJSON_SLOT_ID_SIZE
|
||||
# if defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ <= 2
|
||||
// Address space == 16-bit => max 127 values
|
||||
# define ARDUINOJSON_SLOT_OFFSET_SIZE 1
|
||||
# define ARDUINOJSON_SLOT_ID_SIZE 1
|
||||
# elif defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ >= 8 || \
|
||||
defined(_WIN64) && _WIN64
|
||||
// Address space == 64-bit => max 2147483647 values
|
||||
# define ARDUINOJSON_SLOT_OFFSET_SIZE 4
|
||||
# define ARDUINOJSON_SLOT_ID_SIZE 4
|
||||
# else
|
||||
// Address space == 32-bit => max 32767 values
|
||||
# define ARDUINOJSON_SLOT_OFFSET_SIZE 2
|
||||
# define ARDUINOJSON_SLOT_ID_SIZE 2
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
@ -86,8 +86,7 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
||||
// Reduces the capacity of the memory pool to match the current usage.
|
||||
// https://arduinojson.org/v6/api/JsonDocument/shrinktofit/
|
||||
void shrinkToFit() {
|
||||
auto offset = resources_.shrinkToFit();
|
||||
data_.movePointers(offset);
|
||||
resources_.shrinkToFit();
|
||||
}
|
||||
|
||||
// Reclaims the memory leaked when removing and replacing values.
|
||||
@ -105,14 +104,14 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
||||
// https://arduinojson.org/v6/api/jsondocument/as/
|
||||
template <typename T>
|
||||
T as() {
|
||||
return getVariant().template as<T>();
|
||||
return getSlot().template as<T>();
|
||||
}
|
||||
|
||||
// Casts the root to the specified type.
|
||||
// https://arduinojson.org/v6/api/jsondocument/as/
|
||||
template <typename T>
|
||||
T as() const {
|
||||
return getVariant().template as<T>();
|
||||
return getSlot().template as<T>();
|
||||
}
|
||||
|
||||
// Empties the document and resets the memory pool
|
||||
@ -126,20 +125,20 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
||||
// https://arduinojson.org/v6/api/jsondocument/is/
|
||||
template <typename T>
|
||||
bool is() {
|
||||
return getVariant().template is<T>();
|
||||
return getSlot().template is<T>();
|
||||
}
|
||||
|
||||
// Returns true if the root is of the specified type.
|
||||
// https://arduinojson.org/v6/api/jsondocument/is/
|
||||
template <typename T>
|
||||
bool is() const {
|
||||
return getVariant().template is<T>();
|
||||
return getSlot().template is<T>();
|
||||
}
|
||||
|
||||
// Returns true if the root is null.
|
||||
// https://arduinojson.org/v6/api/jsondocument/isnull/
|
||||
bool isNull() const {
|
||||
return getVariant().isNull();
|
||||
return getSlot().isNull();
|
||||
}
|
||||
|
||||
// Returns the number of used bytes in the memory pool.
|
||||
@ -157,13 +156,13 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
||||
// Returns the depth (nesting level) of the array.
|
||||
// https://arduinojson.org/v6/api/jsondocument/nesting/
|
||||
size_t nesting() const {
|
||||
return data_.nesting();
|
||||
return data_.nesting(&resources_);
|
||||
}
|
||||
|
||||
// Returns the number of elements in the root array or object.
|
||||
// https://arduinojson.org/v6/api/jsondocument/size/
|
||||
size_t size() const {
|
||||
return data_.size();
|
||||
return data_.size(&resources_);
|
||||
}
|
||||
|
||||
// Copies the specified document.
|
||||
@ -186,7 +185,7 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
||||
template <typename T>
|
||||
typename detail::VariantTo<T>::type to() {
|
||||
clear();
|
||||
return getVariant().template to<T>();
|
||||
return getSlot().template to<T>();
|
||||
}
|
||||
|
||||
// Creates an array and appends it to the root array.
|
||||
@ -233,14 +232,14 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
||||
// https://arduinojson.org/v6/api/jsondocument/containskey/
|
||||
template <typename TChar>
|
||||
bool containsKey(TChar* key) const {
|
||||
return data_.getMember(detail::adaptString(key)) != 0;
|
||||
return data_.getMember(detail::adaptString(key), &resources_) != 0;
|
||||
}
|
||||
|
||||
// Returns true if the root object contains the specified key.
|
||||
// https://arduinojson.org/v6/api/jsondocument/containskey/
|
||||
template <typename TString>
|
||||
bool containsKey(const TString& key) const {
|
||||
return data_.getMember(detail::adaptString(key)) != 0;
|
||||
return data_.getMember(detail::adaptString(key), &resources_) != 0;
|
||||
}
|
||||
|
||||
// Gets or sets a root object's member.
|
||||
@ -269,8 +268,8 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
||||
FORCE_INLINE typename detail::enable_if<detail::IsString<TString>::value,
|
||||
JsonVariantConst>::type
|
||||
operator[](const TString& key) const {
|
||||
return JsonVariantConst(data_.getMember(detail::adaptString(key)),
|
||||
&resources_);
|
||||
return JsonVariantConst(
|
||||
data_.getMember(detail::adaptString(key), &resources_), &resources_);
|
||||
}
|
||||
|
||||
// Gets a root object's member.
|
||||
@ -279,8 +278,8 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
||||
FORCE_INLINE typename detail::enable_if<detail::IsString<TChar*>::value,
|
||||
JsonVariantConst>::type
|
||||
operator[](TChar* key) const {
|
||||
return JsonVariantConst(data_.getMember(detail::adaptString(key)),
|
||||
&resources_);
|
||||
return JsonVariantConst(
|
||||
data_.getMember(detail::adaptString(key), &resources_), &resources_);
|
||||
}
|
||||
|
||||
// Gets or sets a root array's element.
|
||||
@ -292,7 +291,7 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
||||
// Gets a root array's member.
|
||||
// https://arduinojson.org/v6/api/jsondocument/subscript/
|
||||
FORCE_INLINE JsonVariantConst operator[](size_t index) const {
|
||||
return JsonVariantConst(data_.getElement(index), &resources_);
|
||||
return JsonVariantConst(data_.getElement(index, &resources_), &resources_);
|
||||
}
|
||||
|
||||
// Appends a new (null) element to the root array.
|
||||
@ -345,19 +344,19 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
||||
}
|
||||
|
||||
FORCE_INLINE operator JsonVariant() {
|
||||
return getVariant();
|
||||
return getSlot();
|
||||
}
|
||||
|
||||
FORCE_INLINE operator JsonVariantConst() const {
|
||||
return getVariant();
|
||||
return getSlot();
|
||||
}
|
||||
|
||||
private:
|
||||
JsonVariant getVariant() {
|
||||
JsonVariant getSlot() {
|
||||
return JsonVariant(&data_, &resources_);
|
||||
}
|
||||
|
||||
JsonVariantConst getVariant() const {
|
||||
JsonVariantConst getSlot() const {
|
||||
return JsonVariantConst(&data_, &resources_);
|
||||
}
|
||||
|
||||
|
@ -273,7 +273,7 @@ class JsonDeserializer {
|
||||
TFilter memberFilter = filter[key.c_str()];
|
||||
|
||||
if (memberFilter.allow()) {
|
||||
auto member = object.getMember(adaptString(key.c_str()));
|
||||
auto member = object.getMember(adaptString(key.c_str()), resources_);
|
||||
if (!member) {
|
||||
// Save key in memory pool.
|
||||
auto savedKey = stringBuilder_.save();
|
||||
|
@ -16,17 +16,18 @@ class JsonSerializer : public VariantDataVisitor<size_t> {
|
||||
public:
|
||||
static const bool producesText = true;
|
||||
|
||||
JsonSerializer(TWriter writer) : formatter_(writer) {}
|
||||
JsonSerializer(TWriter writer, const ResourceManager* resources)
|
||||
: formatter_(writer), resources_(resources) {}
|
||||
|
||||
FORCE_INLINE size_t visit(const ArrayData& array) {
|
||||
write('[');
|
||||
|
||||
auto it = array.createIterator();
|
||||
auto it = array.createIterator(resources_);
|
||||
|
||||
while (!it.done()) {
|
||||
it->accept(*this);
|
||||
|
||||
it.next();
|
||||
it.next(resources_);
|
||||
if (it.done())
|
||||
break;
|
||||
|
||||
@ -40,14 +41,14 @@ class JsonSerializer : public VariantDataVisitor<size_t> {
|
||||
size_t visit(const ObjectData& object) {
|
||||
write('{');
|
||||
|
||||
auto it = object.createIterator();
|
||||
auto it = object.createIterator(resources_);
|
||||
|
||||
while (!it.done()) {
|
||||
formatter_.writeString(it.key());
|
||||
write(':');
|
||||
it->accept(*this);
|
||||
|
||||
it.next();
|
||||
it.next(resources_);
|
||||
if (it.done())
|
||||
break;
|
||||
|
||||
@ -113,6 +114,9 @@ class JsonSerializer : public VariantDataVisitor<size_t> {
|
||||
|
||||
private:
|
||||
TextFormatter<TWriter> formatter_;
|
||||
|
||||
protected:
|
||||
const ResourceManager* resources_;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
@ -16,10 +16,11 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
|
||||
typedef JsonSerializer<TWriter> base;
|
||||
|
||||
public:
|
||||
PrettyJsonSerializer(TWriter writer) : base(writer), nesting_(0) {}
|
||||
PrettyJsonSerializer(TWriter writer, const ResourceManager* resources)
|
||||
: base(writer, resources), nesting_(0) {}
|
||||
|
||||
size_t visit(const ArrayData& array) {
|
||||
auto it = array.createIterator();
|
||||
auto it = array.createIterator(base::resources_);
|
||||
if (!it.done()) {
|
||||
base::write("[\r\n");
|
||||
nesting_++;
|
||||
@ -27,7 +28,7 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
|
||||
indent();
|
||||
it->accept(*this);
|
||||
|
||||
it.next();
|
||||
it.next(base::resources_);
|
||||
base::write(it.done() ? "\r\n" : ",\r\n");
|
||||
}
|
||||
nesting_--;
|
||||
@ -40,7 +41,7 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
|
||||
}
|
||||
|
||||
size_t visit(const ObjectData& object) {
|
||||
auto it = object.createIterator();
|
||||
auto it = object.createIterator(base::resources_);
|
||||
if (!it.done()) {
|
||||
base::write("{\r\n");
|
||||
nesting_++;
|
||||
@ -50,7 +51,7 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
|
||||
base::write(": ");
|
||||
it->accept(*this);
|
||||
|
||||
it.next();
|
||||
it.next(base::resources_);
|
||||
base::write(it.done() ? "\r\n" : ",\r\n");
|
||||
}
|
||||
nesting_--;
|
||||
|
@ -67,13 +67,17 @@ class ResourceManager {
|
||||
return overflowed_;
|
||||
}
|
||||
|
||||
VariantSlot* allocVariant() {
|
||||
auto p = variantPool_.allocVariant();
|
||||
SlotWithId allocSlot() {
|
||||
auto p = variantPool_.allocSlot();
|
||||
if (!p)
|
||||
overflowed_ = true;
|
||||
return p;
|
||||
}
|
||||
|
||||
VariantSlot* getSlot(SlotId id) const {
|
||||
return variantPool_.getSlot(id);
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
StringNode* saveString(TAdaptedString str) {
|
||||
if (str.isNull())
|
||||
@ -123,8 +127,8 @@ class ResourceManager {
|
||||
stringPool_.clear(allocator_);
|
||||
}
|
||||
|
||||
ptrdiff_t shrinkToFit() {
|
||||
return variantPool_.shrinkToFit(allocator_);
|
||||
void shrinkToFit() {
|
||||
variantPool_.shrinkToFit(allocator_);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -6,10 +6,39 @@
|
||||
|
||||
#include <ArduinoJson/Memory/ResourceManager.hpp>
|
||||
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||
#include <ArduinoJson/Polyfills/integer.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
class VariantSlot;
|
||||
using SlotId = uint_t<ARDUINOJSON_SLOT_ID_SIZE * 8>::type;
|
||||
using SlotCount = SlotId;
|
||||
const SlotId NULL_SLOT = SlotId(-1);
|
||||
|
||||
class SlotWithId {
|
||||
public:
|
||||
SlotWithId() : slot_(nullptr), id_(NULL_SLOT) {}
|
||||
SlotWithId(VariantSlot* slot, SlotId id) : slot_(slot), id_(id) {
|
||||
ARDUINOJSON_ASSERT((slot == nullptr) == (id == NULL_SLOT));
|
||||
}
|
||||
|
||||
SlotId id() const {
|
||||
return id_;
|
||||
}
|
||||
|
||||
operator VariantSlot*() {
|
||||
return slot_;
|
||||
}
|
||||
|
||||
VariantSlot* operator->() {
|
||||
ARDUINOJSON_ASSERT(slot_ != nullptr);
|
||||
return slot_;
|
||||
}
|
||||
|
||||
private:
|
||||
VariantSlot* slot_;
|
||||
SlotId id_;
|
||||
};
|
||||
|
||||
class VariantPool {
|
||||
public:
|
||||
@ -30,18 +59,19 @@ class VariantPool {
|
||||
void create(size_t cap, Allocator* allocator);
|
||||
void destroy(Allocator* allocator);
|
||||
|
||||
VariantSlot* allocVariant();
|
||||
SlotWithId allocSlot();
|
||||
VariantSlot* getSlot(SlotId id) const;
|
||||
void clear();
|
||||
ptrdiff_t shrinkToFit(Allocator*);
|
||||
size_t capacity() const;
|
||||
size_t usage() const;
|
||||
void shrinkToFit(Allocator*);
|
||||
SlotCount capacity() const;
|
||||
SlotCount usage() const;
|
||||
|
||||
static size_t bytesToSlots(size_t);
|
||||
static size_t slotsToBytes(size_t);
|
||||
static SlotCount bytesToSlots(size_t);
|
||||
static size_t slotsToBytes(SlotCount);
|
||||
|
||||
private:
|
||||
size_t capacity_ = 0;
|
||||
size_t usage_ = 0;
|
||||
SlotCount capacity_ = 0;
|
||||
SlotCount usage_ = 0;
|
||||
VariantSlot* slots_ = nullptr;
|
||||
};
|
||||
|
||||
|
@ -28,29 +28,31 @@ inline void VariantPool::destroy(Allocator* allocator) {
|
||||
usage_ = 0;
|
||||
}
|
||||
|
||||
inline ptrdiff_t VariantPool::shrinkToFit(Allocator* allocator) {
|
||||
auto originalPool = slots_;
|
||||
inline void VariantPool::shrinkToFit(Allocator* allocator) {
|
||||
slots_ = reinterpret_cast<VariantSlot*>(
|
||||
allocator->reallocate(slots_, slotsToBytes(usage_)));
|
||||
if (slots_)
|
||||
capacity_ = usage_;
|
||||
return reinterpret_cast<char*>(slots_) -
|
||||
reinterpret_cast<char*>(originalPool);
|
||||
capacity_ = usage_;
|
||||
}
|
||||
|
||||
inline VariantSlot* VariantPool::allocVariant() {
|
||||
inline SlotWithId VariantPool::allocSlot() {
|
||||
if (!slots_)
|
||||
return nullptr;
|
||||
if (usage_ + 1 > capacity_)
|
||||
return nullptr;
|
||||
return new (&slots_[usage_++]) VariantSlot;
|
||||
return {};
|
||||
if (usage_ >= capacity_)
|
||||
return {};
|
||||
auto index = usage_++;
|
||||
auto slot = &slots_[index];
|
||||
return {new (slot) VariantSlot, SlotId(index)};
|
||||
}
|
||||
|
||||
inline size_t VariantPool::usage() const {
|
||||
inline VariantSlot* VariantPool::getSlot(SlotId id) const {
|
||||
return id == NULL_SLOT ? nullptr : &slots_[id];
|
||||
}
|
||||
|
||||
inline SlotCount VariantPool::usage() const {
|
||||
return usage_;
|
||||
}
|
||||
|
||||
inline size_t VariantPool::capacity() const {
|
||||
inline SlotCount VariantPool::capacity() const {
|
||||
return capacity_;
|
||||
}
|
||||
|
||||
@ -58,11 +60,11 @@ inline void VariantPool::clear() {
|
||||
usage_ = 0;
|
||||
}
|
||||
|
||||
inline size_t VariantPool::bytesToSlots(size_t n) {
|
||||
return n / sizeof(VariantSlot);
|
||||
inline SlotCount VariantPool::bytesToSlots(size_t n) {
|
||||
return static_cast<SlotCount>(n / sizeof(VariantSlot));
|
||||
}
|
||||
|
||||
inline size_t VariantPool::slotsToBytes(size_t n) {
|
||||
inline size_t VariantPool::slotsToBytes(SlotCount n) {
|
||||
return n * sizeof(VariantSlot);
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,8 @@ class MsgPackSerializer : public VariantDataVisitor<size_t> {
|
||||
public:
|
||||
static const bool producesText = false;
|
||||
|
||||
MsgPackSerializer(TWriter writer) : writer_(writer) {}
|
||||
MsgPackSerializer(TWriter writer, const ResourceManager* resources)
|
||||
: writer_(writer), resources_(resources) {}
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<is_floating_point<T>::value && sizeof(T) == 4,
|
||||
@ -48,7 +49,7 @@ class MsgPackSerializer : public VariantDataVisitor<size_t> {
|
||||
}
|
||||
|
||||
size_t visit(const ArrayData& array) {
|
||||
size_t n = array.size();
|
||||
size_t n = array.size(resources_);
|
||||
if (n < 0x10) {
|
||||
writeByte(uint8_t(0x90 + n));
|
||||
} else if (n < 0x10000) {
|
||||
@ -58,14 +59,15 @@ class MsgPackSerializer : public VariantDataVisitor<size_t> {
|
||||
writeByte(0xDD);
|
||||
writeInteger(uint32_t(n));
|
||||
}
|
||||
for (auto it = array.createIterator(); !it.done(); it.next()) {
|
||||
for (auto it = array.createIterator(resources_); !it.done();
|
||||
it.next(resources_)) {
|
||||
it->accept(*this);
|
||||
}
|
||||
return bytesWritten();
|
||||
}
|
||||
|
||||
size_t visit(const ObjectData& object) {
|
||||
size_t n = object.size();
|
||||
size_t n = object.size(resources_);
|
||||
if (n < 0x10) {
|
||||
writeByte(uint8_t(0x80 + n));
|
||||
} else if (n < 0x10000) {
|
||||
@ -75,7 +77,8 @@ class MsgPackSerializer : public VariantDataVisitor<size_t> {
|
||||
writeByte(0xDF);
|
||||
writeInteger(uint32_t(n));
|
||||
}
|
||||
for (auto it = object.createIterator(); !it.done(); it.next()) {
|
||||
for (auto it = object.createIterator(resources_); !it.done();
|
||||
it.next(resources_)) {
|
||||
visit(it.key());
|
||||
it->accept(*this);
|
||||
}
|
||||
@ -200,6 +203,7 @@ class MsgPackSerializer : public VariantDataVisitor<size_t> {
|
||||
}
|
||||
|
||||
CountingDecorator<TWriter> writer_;
|
||||
const ResourceManager* resources_;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
@ -19,7 +19,7 @@
|
||||
ARDUINOJSON_ENABLE_INFINITY, \
|
||||
ARDUINOJSON_ENABLE_COMMENTS, \
|
||||
ARDUINOJSON_DECODE_UNICODE), \
|
||||
ARDUINOJSON_SLOT_OFFSET_SIZE)
|
||||
ARDUINOJSON_SLOT_ID_SIZE)
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -56,19 +56,19 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
|
||||
// Returns the number of bytes occupied by the object.
|
||||
// https://arduinojson.org/v6/api/jsonobject/memoryusage/
|
||||
FORCE_INLINE size_t memoryUsage() const {
|
||||
return data_ ? data_->memoryUsage() : 0;
|
||||
return data_ ? data_->memoryUsage(resources_) : 0;
|
||||
}
|
||||
|
||||
// Returns the depth (nesting level) of the object.
|
||||
// https://arduinojson.org/v6/api/jsonobject/nesting/
|
||||
FORCE_INLINE size_t nesting() const {
|
||||
return detail::VariantData::nesting(collectionToVariant(data_));
|
||||
return detail::VariantData::nesting(collectionToVariant(data_), resources_);
|
||||
}
|
||||
|
||||
// Returns the number of members in the object.
|
||||
// https://arduinojson.org/v6/api/jsonobject/size/
|
||||
FORCE_INLINE size_t size() const {
|
||||
return data_ ? data_->size() : 0;
|
||||
return data_ ? data_->size(resources_) : 0;
|
||||
}
|
||||
|
||||
// Returns an iterator to the first key-value pair of the object.
|
||||
@ -76,7 +76,7 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
|
||||
FORCE_INLINE iterator begin() const {
|
||||
if (!data_)
|
||||
return iterator();
|
||||
return iterator(data_->createIterator(), resources_);
|
||||
return iterator(data_->createIterator(resources_), resources_);
|
||||
}
|
||||
|
||||
// Returns an iterator following the last key-value pair of the object.
|
||||
@ -158,7 +158,8 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
|
||||
FORCE_INLINE
|
||||
typename detail::enable_if<detail::IsString<TString>::value, bool>::type
|
||||
containsKey(const TString& key) const {
|
||||
return detail::ObjectData::getMember(data_, detail::adaptString(key)) != 0;
|
||||
return detail::ObjectData::getMember(data_, detail::adaptString(key),
|
||||
resources_) != 0;
|
||||
}
|
||||
|
||||
// Returns true if the object contains the specified key.
|
||||
@ -167,7 +168,8 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
|
||||
FORCE_INLINE
|
||||
typename detail::enable_if<detail::IsString<TChar*>::value, bool>::type
|
||||
containsKey(TChar* key) const {
|
||||
return detail::ObjectData::getMember(data_, detail::adaptString(key)) != 0;
|
||||
return detail::ObjectData::getMember(data_, detail::adaptString(key),
|
||||
resources_) != 0;
|
||||
}
|
||||
|
||||
// Creates an array and adds it to the object.
|
||||
|
@ -45,19 +45,19 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
|
||||
// Returns the number of bytes occupied by the object.
|
||||
// https://arduinojson.org/v6/api/jsonobjectconst/memoryusage/
|
||||
FORCE_INLINE size_t memoryUsage() const {
|
||||
return data_ ? data_->memoryUsage() : 0;
|
||||
return data_ ? data_->memoryUsage(resources_) : 0;
|
||||
}
|
||||
|
||||
// Returns the depth (nesting level) of the object.
|
||||
// https://arduinojson.org/v6/api/jsonobjectconst/nesting/
|
||||
FORCE_INLINE size_t nesting() const {
|
||||
return detail::VariantData::nesting(collectionToVariant(data_));
|
||||
return detail::VariantData::nesting(collectionToVariant(data_), resources_);
|
||||
}
|
||||
|
||||
// Returns the number of members in the object.
|
||||
// https://arduinojson.org/v6/api/jsonobjectconst/size/
|
||||
FORCE_INLINE size_t size() const {
|
||||
return data_ ? data_->size() : 0;
|
||||
return data_ ? data_->size(resources_) : 0;
|
||||
}
|
||||
|
||||
// Returns an iterator to the first key-value pair of the object.
|
||||
@ -65,7 +65,7 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
|
||||
FORCE_INLINE iterator begin() const {
|
||||
if (!data_)
|
||||
return iterator();
|
||||
return iterator(data_->createIterator(), resources_);
|
||||
return iterator(data_->createIterator(resources_), resources_);
|
||||
}
|
||||
|
||||
// Returns an iterator following the last key-value pair of the object.
|
||||
@ -78,14 +78,16 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
|
||||
// https://arduinojson.org/v6/api/jsonobjectconst/containskey/
|
||||
template <typename TString>
|
||||
FORCE_INLINE bool containsKey(const TString& key) const {
|
||||
return detail::ObjectData::getMember(data_, detail::adaptString(key)) != 0;
|
||||
return detail::ObjectData::getMember(data_, detail::adaptString(key),
|
||||
resources_) != 0;
|
||||
}
|
||||
|
||||
// Returns true if the object contains the specified key.
|
||||
// https://arduinojson.org/v6/api/jsonobjectconst/containskey/
|
||||
template <typename TChar>
|
||||
FORCE_INLINE bool containsKey(TChar* key) const {
|
||||
return detail::ObjectData::getMember(data_, detail::adaptString(key)) != 0;
|
||||
return detail::ObjectData::getMember(data_, detail::adaptString(key),
|
||||
resources_) != 0;
|
||||
}
|
||||
|
||||
// Gets the member with specified key.
|
||||
@ -94,9 +96,9 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
|
||||
FORCE_INLINE typename detail::enable_if<detail::IsString<TString>::value,
|
||||
JsonVariantConst>::type
|
||||
operator[](const TString& key) const {
|
||||
return JsonVariantConst(
|
||||
detail::ObjectData::getMember(data_, detail::adaptString(key)),
|
||||
resources_);
|
||||
return JsonVariantConst(detail::ObjectData::getMember(
|
||||
data_, detail::adaptString(key), resources_),
|
||||
resources_);
|
||||
}
|
||||
|
||||
// Gets the member with specified key.
|
||||
|
@ -54,16 +54,16 @@ template <typename TDerived>
|
||||
template <typename TString>
|
||||
inline typename enable_if<IsString<TString>::value, bool>::type
|
||||
VariantRefBase<TDerived>::containsKey(const TString& key) const {
|
||||
return VariantData::getMember(VariantAttorney::getData(derived()),
|
||||
adaptString(key)) != 0;
|
||||
return VariantData::getMember(getData(), adaptString(key),
|
||||
getResourceManager()) != 0;
|
||||
}
|
||||
|
||||
template <typename TDerived>
|
||||
template <typename TChar>
|
||||
inline typename enable_if<IsString<TChar*>::value, bool>::type
|
||||
VariantRefBase<TDerived>::containsKey(TChar* key) const {
|
||||
return VariantData::getMember(VariantAttorney::getData(derived()),
|
||||
adaptString(key)) != 0;
|
||||
return VariantData::getMember(getData(), adaptString(key),
|
||||
getResourceManager()) != 0;
|
||||
}
|
||||
|
||||
template <typename TDerived>
|
||||
|
@ -34,7 +34,7 @@ class JsonObjectIterator {
|
||||
}
|
||||
|
||||
JsonObjectIterator& operator++() {
|
||||
iterator_.next();
|
||||
iterator_.next(resources_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -69,7 +69,7 @@ class JsonObjectConstIterator {
|
||||
}
|
||||
|
||||
JsonObjectConstIterator& operator++() {
|
||||
iterator_.next();
|
||||
iterator_.next(resources_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -46,8 +46,9 @@ class MemberProxy
|
||||
}
|
||||
|
||||
FORCE_INLINE VariantData* getData() const {
|
||||
return VariantData::getMember(VariantAttorney::getData(upstream_),
|
||||
adaptString(key_));
|
||||
return VariantData::getMember(
|
||||
VariantAttorney::getData(upstream_), adaptString(key_),
|
||||
VariantAttorney::getResourceManager(upstream_));
|
||||
}
|
||||
|
||||
FORCE_INLINE VariantData* getOrCreateData() const {
|
||||
|
@ -43,13 +43,15 @@ class ObjectData : public CollectionData {
|
||||
VariantData* getOrAddMember(TAdaptedString key, ResourceManager* resources);
|
||||
|
||||
template <typename TAdaptedString>
|
||||
VariantData* getMember(TAdaptedString key) const;
|
||||
VariantData* getMember(TAdaptedString key,
|
||||
const ResourceManager* resources) const;
|
||||
|
||||
template <typename TAdaptedString>
|
||||
static VariantData* getMember(const ObjectData* object, TAdaptedString key) {
|
||||
static VariantData* getMember(const ObjectData* object, TAdaptedString key,
|
||||
const ResourceManager* resources) {
|
||||
if (!object)
|
||||
return nullptr;
|
||||
return object->getMember(key);
|
||||
return object->getMember(key, resources);
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
@ -65,7 +67,7 @@ class ObjectData : public CollectionData {
|
||||
|
||||
private:
|
||||
template <typename TAdaptedString>
|
||||
iterator findKey(TAdaptedString key) const;
|
||||
iterator findKey(TAdaptedString key, const ResourceManager* resources) const;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
@ -10,24 +10,26 @@
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <typename TAdaptedString>
|
||||
inline VariantData* ObjectData::getMember(TAdaptedString key) const {
|
||||
return findKey(key).data();
|
||||
inline VariantData* ObjectData::getMember(
|
||||
TAdaptedString key, const ResourceManager* resources) const {
|
||||
return findKey(key, resources).data();
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
VariantData* ObjectData::getOrAddMember(TAdaptedString key,
|
||||
ResourceManager* resources) {
|
||||
auto it = findKey(key);
|
||||
auto it = findKey(key, resources);
|
||||
if (!it.done())
|
||||
return it.data();
|
||||
return addMember(key, resources);
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
inline ObjectData::iterator ObjectData::findKey(TAdaptedString key) const {
|
||||
inline ObjectData::iterator ObjectData::findKey(
|
||||
TAdaptedString key, const ResourceManager* resources) const {
|
||||
if (key.isNull())
|
||||
return iterator();
|
||||
for (auto it = createIterator(); !it.done(); it.next()) {
|
||||
for (auto it = createIterator(resources); !it.done(); it.next(resources)) {
|
||||
if (stringEquals(key, adaptString(it.key())))
|
||||
return it;
|
||||
}
|
||||
@ -37,7 +39,7 @@ inline ObjectData::iterator ObjectData::findKey(TAdaptedString key) const {
|
||||
template <typename TAdaptedString>
|
||||
inline void ObjectData::removeMember(TAdaptedString key,
|
||||
ResourceManager* resources) {
|
||||
remove(findKey(key), resources);
|
||||
remove(findKey(key, resources), resources);
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
@ -11,21 +11,21 @@
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <int Bits>
|
||||
struct int_t;
|
||||
struct uint_t;
|
||||
|
||||
template <>
|
||||
struct int_t<8> {
|
||||
typedef int8_t type;
|
||||
struct uint_t<8> {
|
||||
typedef uint8_t type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct int_t<16> {
|
||||
typedef int16_t type;
|
||||
struct uint_t<16> {
|
||||
typedef uint16_t type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct int_t<32> {
|
||||
typedef int32_t type;
|
||||
struct uint_t<32> {
|
||||
typedef uint32_t type;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
@ -11,7 +11,8 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
template <template <typename> class TSerializer>
|
||||
size_t measure(ArduinoJson::JsonVariantConst source) {
|
||||
DummyWriter dp;
|
||||
TSerializer<DummyWriter> serializer(dp);
|
||||
TSerializer<DummyWriter> serializer(
|
||||
dp, VariantAttorney::getResourceManager(source));
|
||||
return VariantData::accept(VariantAttorney::getData(source), serializer);
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,8 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <template <typename> class TSerializer, typename TWriter>
|
||||
size_t doSerialize(ArduinoJson::JsonVariantConst source, TWriter writer) {
|
||||
TSerializer<TWriter> serializer(writer);
|
||||
TSerializer<TWriter> serializer(writer,
|
||||
VariantAttorney::getResourceManager(source));
|
||||
return VariantData::accept(VariantAttorney::getData(source), serializer);
|
||||
}
|
||||
|
||||
|
@ -94,7 +94,7 @@ inline JsonVariant VariantRefBase<TDerived>::add() const {
|
||||
}
|
||||
|
||||
template <typename TDerived>
|
||||
inline JsonVariant VariantRefBase<TDerived>::getVariant() const {
|
||||
inline JsonVariant VariantRefBase<TDerived>::getSlot() const {
|
||||
return JsonVariant(getData(), getResourceManager());
|
||||
}
|
||||
|
||||
|
@ -50,19 +50,19 @@ class JsonVariantConst : public detail::VariantTag,
|
||||
// Returns the number of bytes occupied by the value.
|
||||
// https://arduinojson.org/v6/api/jsonvariantconst/memoryusage/
|
||||
FORCE_INLINE size_t memoryUsage() const {
|
||||
return data_ ? data_->memoryUsage() : 0;
|
||||
return data_ ? data_->memoryUsage(resources_) : 0;
|
||||
}
|
||||
|
||||
// Returns the depth (nesting level) of the value.
|
||||
// https://arduinojson.org/v6/api/jsonvariantconst/nesting/
|
||||
FORCE_INLINE size_t nesting() const {
|
||||
return detail::VariantData::nesting(data_);
|
||||
return detail::VariantData::nesting(data_, resources_);
|
||||
}
|
||||
|
||||
// Returns the size of the array or object.
|
||||
// https://arduinojson.org/v6/api/jsonvariantconst/size/
|
||||
size_t size() const {
|
||||
return detail::VariantData::size(data_);
|
||||
return detail::VariantData::size(data_, resources_);
|
||||
}
|
||||
|
||||
// Casts the value to the specified type.
|
||||
@ -93,8 +93,8 @@ class JsonVariantConst : public detail::VariantTag,
|
||||
// Gets array's element at specified index.
|
||||
// https://arduinojson.org/v6/api/jsonvariantconst/subscript/
|
||||
FORCE_INLINE JsonVariantConst operator[](size_t index) const {
|
||||
return JsonVariantConst(detail::VariantData::getElement(data_, index),
|
||||
resources_);
|
||||
return JsonVariantConst(
|
||||
detail::VariantData::getElement(data_, index, resources_), resources_);
|
||||
}
|
||||
|
||||
// Gets object's member with specified key.
|
||||
@ -103,9 +103,9 @@ class JsonVariantConst : public detail::VariantTag,
|
||||
FORCE_INLINE typename detail::enable_if<detail::IsString<TString>::value,
|
||||
JsonVariantConst>::type
|
||||
operator[](const TString& key) const {
|
||||
return JsonVariantConst(
|
||||
detail::VariantData::getMember(data_, detail::adaptString(key)),
|
||||
resources_);
|
||||
return JsonVariantConst(detail::VariantData::getMember(
|
||||
data_, detail::adaptString(key), resources_),
|
||||
resources_);
|
||||
}
|
||||
|
||||
// Gets object's member with specified key.
|
||||
@ -114,9 +114,9 @@ class JsonVariantConst : public detail::VariantTag,
|
||||
FORCE_INLINE typename detail::enable_if<detail::IsString<TChar*>::value,
|
||||
JsonVariantConst>::type
|
||||
operator[](TChar* key) const {
|
||||
return JsonVariantConst(
|
||||
detail::VariantData::getMember(data_, detail::adaptString(key)),
|
||||
resources_);
|
||||
return JsonVariantConst(detail::VariantData::getMember(
|
||||
data_, detail::adaptString(key), resources_),
|
||||
resources_);
|
||||
}
|
||||
|
||||
// Returns true if tge object contains the specified key.
|
||||
@ -125,8 +125,8 @@ class JsonVariantConst : public detail::VariantTag,
|
||||
FORCE_INLINE
|
||||
typename detail::enable_if<detail::IsString<TString>::value, bool>::type
|
||||
containsKey(const TString& key) const {
|
||||
return detail::VariantData::getMember(getData(),
|
||||
detail::adaptString(key)) != 0;
|
||||
return detail::VariantData::getMember(getData(), detail::adaptString(key),
|
||||
resources_) != 0;
|
||||
}
|
||||
|
||||
// Returns true if tge object contains the specified key.
|
||||
@ -135,8 +135,8 @@ class JsonVariantConst : public detail::VariantTag,
|
||||
FORCE_INLINE
|
||||
typename detail::enable_if<detail::IsString<TChar*>::value, bool>::type
|
||||
containsKey(TChar* key) const {
|
||||
return detail::VariantData::getMember(getData(),
|
||||
detail::adaptString(key)) != 0;
|
||||
return detail::VariantData::getMember(getData(), detail::adaptString(key),
|
||||
resources_) != 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -185,30 +185,28 @@ class VariantData {
|
||||
}
|
||||
}
|
||||
|
||||
VariantData* getElement(size_t index) const {
|
||||
auto array = asArray();
|
||||
if (!array)
|
||||
return nullptr;
|
||||
return array->getElement(index);
|
||||
VariantData* getElement(size_t index,
|
||||
const ResourceManager* resources) const {
|
||||
return ArrayData::getElement(asArray(), index, resources);
|
||||
}
|
||||
|
||||
static VariantData* getElement(const VariantData* var, size_t index) {
|
||||
return var != 0 ? var->getElement(index) : 0;
|
||||
static VariantData* getElement(const VariantData* var, size_t index,
|
||||
const ResourceManager* resources) {
|
||||
return var != 0 ? var->getElement(index, resources) : 0;
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
VariantData* getMember(TAdaptedString key) const {
|
||||
auto object = asObject();
|
||||
if (!object)
|
||||
return nullptr;
|
||||
return object->getMember(key);
|
||||
VariantData* getMember(TAdaptedString key,
|
||||
const ResourceManager* resources) const {
|
||||
return ObjectData::getMember(asObject(), key, resources);
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
static VariantData* getMember(const VariantData* var, TAdaptedString key) {
|
||||
static VariantData* getMember(const VariantData* var, TAdaptedString key,
|
||||
const ResourceManager* resources) {
|
||||
if (!var)
|
||||
return 0;
|
||||
return var->getMember(key);
|
||||
return var->getMember(key, resources);
|
||||
}
|
||||
|
||||
VariantData* getOrAddElement(size_t index, ResourceManager* resources) {
|
||||
@ -276,36 +274,32 @@ class VariantData {
|
||||
return type() == VALUE_IS_LINKED_STRING || type() == VALUE_IS_OWNED_STRING;
|
||||
}
|
||||
|
||||
size_t memoryUsage() const {
|
||||
size_t memoryUsage(const ResourceManager* resources) const {
|
||||
switch (type()) {
|
||||
case VALUE_IS_OWNED_STRING:
|
||||
case VALUE_IS_RAW_STRING:
|
||||
return sizeofString(content_.asOwnedString->length);
|
||||
case VALUE_IS_OBJECT:
|
||||
case VALUE_IS_ARRAY:
|
||||
return content_.asCollection.memoryUsage();
|
||||
return content_.asCollection.memoryUsage(resources);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void movePointers(ptrdiff_t variantDistance) {
|
||||
if (flags_ & COLLECTION_MASK)
|
||||
content_.asCollection.movePointers(variantDistance);
|
||||
}
|
||||
|
||||
size_t nesting() const {
|
||||
size_t nesting(const ResourceManager* resources) const {
|
||||
auto collection = asCollection();
|
||||
if (collection)
|
||||
return collection->nesting();
|
||||
return collection->nesting(resources);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t nesting(const VariantData* var) {
|
||||
static size_t nesting(const VariantData* var,
|
||||
const ResourceManager* resources) {
|
||||
if (!var)
|
||||
return 0;
|
||||
return var->nesting();
|
||||
return var->nesting(resources);
|
||||
}
|
||||
|
||||
void operator=(const VariantData& src) {
|
||||
@ -455,12 +449,12 @@ class VariantData {
|
||||
content_.asOwnedString = s;
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return isCollection() ? content_.asCollection.size() : 0;
|
||||
size_t size(const ResourceManager* resources) const {
|
||||
return isCollection() ? content_.asCollection.size(resources) : 0;
|
||||
}
|
||||
|
||||
static size_t size(const VariantData* var) {
|
||||
return var != 0 ? var->size() : 0;
|
||||
static size_t size(const VariantData* var, const ResourceManager* resources) {
|
||||
return var != 0 ? var->size(resources) : 0;
|
||||
}
|
||||
|
||||
ArrayData& toArray() {
|
||||
|
@ -58,7 +58,7 @@ class VariantRefBase : public VariantTag {
|
||||
template <typename T>
|
||||
FORCE_INLINE typename enable_if<ConverterNeedsWriteableRef<T>::value, T>::type
|
||||
as() const {
|
||||
return Converter<T>::fromJson(getVariant());
|
||||
return Converter<T>::fromJson(getSlot());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -92,7 +92,7 @@ class VariantRefBase : public VariantTag {
|
||||
FORCE_INLINE
|
||||
typename enable_if<ConverterNeedsWriteableRef<T>::value, bool>::type
|
||||
is() const {
|
||||
return Converter<T>::checkJson(getVariant());
|
||||
return Converter<T>::checkJson(getSlot());
|
||||
}
|
||||
|
||||
// Returns true if the value is of the specified type.
|
||||
@ -127,20 +127,20 @@ class VariantRefBase : public VariantTag {
|
||||
// Returns the size of the array or object.
|
||||
// https://arduinojson.org/v6/api/jsonvariant/size/
|
||||
FORCE_INLINE size_t size() const {
|
||||
return VariantData::size(getData());
|
||||
return VariantData::size(getData(), getResourceManager());
|
||||
}
|
||||
|
||||
// Returns the number of bytes occupied by the value.
|
||||
// https://arduinojson.org/v6/api/jsonvariant/memoryusage/
|
||||
FORCE_INLINE size_t memoryUsage() const {
|
||||
VariantData* data = getData();
|
||||
return data ? data->memoryUsage() : 0;
|
||||
return data ? data->memoryUsage(getResourceManager()) : 0;
|
||||
}
|
||||
|
||||
// Returns the depth (nesting level) of the value.
|
||||
// https://arduinojson.org/v6/api/jsonvariant/nesting/
|
||||
FORCE_INLINE size_t nesting() const {
|
||||
return VariantData::nesting(getData());
|
||||
return VariantData::nesting(getData(), getResourceManager());
|
||||
}
|
||||
|
||||
// Appends a new (null) element to the array.
|
||||
@ -269,7 +269,7 @@ class VariantRefBase : public VariantTag {
|
||||
}
|
||||
|
||||
private:
|
||||
FORCE_INLINE ArduinoJson::JsonVariant getVariant() const;
|
||||
FORCE_INLINE ArduinoJson::JsonVariant getSlot() const;
|
||||
|
||||
FORCE_INLINE ArduinoJson::JsonVariantConst getVariantConst() const {
|
||||
return ArduinoJson::JsonVariantConst(getData(), getResourceManager());
|
||||
|
@ -5,7 +5,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Memory/ResourceManager.hpp>
|
||||
#include <ArduinoJson/Polyfills/integer.hpp>
|
||||
#include <ArduinoJson/Polyfills/limits.hpp>
|
||||
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||
#include <ArduinoJson/Variant/VariantContent.hpp>
|
||||
@ -14,15 +13,13 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
struct StringNode;
|
||||
|
||||
typedef int_t<ARDUINOJSON_SLOT_OFFSET_SIZE * 8>::type VariantSlotDiff;
|
||||
|
||||
class VariantSlot {
|
||||
// CAUTION: same layout as VariantData
|
||||
// we cannot use composition because it adds padding
|
||||
// (+20% on ESP8266 for example)
|
||||
VariantContent content_;
|
||||
uint8_t flags_;
|
||||
VariantSlotDiff next_;
|
||||
SlotId next_;
|
||||
const char* key_;
|
||||
|
||||
public:
|
||||
@ -33,7 +30,7 @@ class VariantSlot {
|
||||
|
||||
static void operator delete(void*, void*) noexcept {}
|
||||
|
||||
VariantSlot() : flags_(0), next_(0), key_(0) {}
|
||||
VariantSlot() : flags_(0), next_(NULL_SLOT), key_(0) {}
|
||||
|
||||
VariantData* data() {
|
||||
return reinterpret_cast<VariantData*>(&content_);
|
||||
@ -43,29 +40,12 @@ class VariantSlot {
|
||||
return reinterpret_cast<const VariantData*>(&content_);
|
||||
}
|
||||
|
||||
VariantSlot* next() {
|
||||
return next_ ? this + next_ : 0;
|
||||
SlotId next() const {
|
||||
return next_;
|
||||
}
|
||||
|
||||
const VariantSlot* next() const {
|
||||
return const_cast<VariantSlot*>(this)->next();
|
||||
}
|
||||
|
||||
void setNext(VariantSlot* slot) {
|
||||
ARDUINOJSON_ASSERT(!slot || slot - this >=
|
||||
numeric_limits<VariantSlotDiff>::lowest());
|
||||
ARDUINOJSON_ASSERT(!slot || slot - this <=
|
||||
numeric_limits<VariantSlotDiff>::highest());
|
||||
next_ = VariantSlotDiff(slot ? slot - this : 0);
|
||||
}
|
||||
|
||||
void setNextNotNull(VariantSlot* slot) {
|
||||
ARDUINOJSON_ASSERT(slot != 0);
|
||||
ARDUINOJSON_ASSERT(slot - this >=
|
||||
numeric_limits<VariantSlotDiff>::lowest());
|
||||
ARDUINOJSON_ASSERT(slot - this <=
|
||||
numeric_limits<VariantSlotDiff>::highest());
|
||||
next_ = VariantSlotDiff(slot - this);
|
||||
void setNext(SlotId slot) {
|
||||
next_ = slot;
|
||||
}
|
||||
|
||||
void setKey(const char* k) {
|
||||
|
Reference in New Issue
Block a user