Store index of slot in the pool instead of a pointer or a distance

This commit is contained in:
Benoit Blanchon
2023-06-14 11:57:31 +02:00
parent 068c40d6ed
commit c4e5051a7a
44 changed files with 343 additions and 310 deletions

View File

@ -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_USE_LONG_LONG == 0, "ARDUINOJSON_USE_LONG_LONG");
static_assert(ARDUINOJSON_SLOT_OFFSET_SIZE == 1, static_assert(ARDUINOJSON_SLOT_ID_SIZE == 1, "ARDUINOJSON_SLOT_ID_SIZE");
"ARDUINOJSON_SLOT_OFFSET_SIZE");
static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN"); static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN");

View File

@ -2,8 +2,7 @@
static_assert(ARDUINOJSON_USE_LONG_LONG == 1, "ARDUINOJSON_USE_LONG_LONG"); static_assert(ARDUINOJSON_USE_LONG_LONG == 1, "ARDUINOJSON_USE_LONG_LONG");
static_assert(ARDUINOJSON_SLOT_OFFSET_SIZE == 2, static_assert(ARDUINOJSON_SLOT_ID_SIZE == 2, "ARDUINOJSON_SLOT_ID_SIZE");
"ARDUINOJSON_SLOT_OFFSET_SIZE");
static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN"); static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN");

View File

@ -2,14 +2,13 @@
static_assert(ARDUINOJSON_USE_LONG_LONG == 1, "ARDUINOJSON_USE_LONG_LONG"); static_assert(ARDUINOJSON_USE_LONG_LONG == 1, "ARDUINOJSON_USE_LONG_LONG");
static_assert(ARDUINOJSON_SLOT_OFFSET_SIZE == 4, static_assert(ARDUINOJSON_SLOT_ID_SIZE == 4, "ARDUINOJSON_SLOT_ID_SIZE");
"ARDUINOJSON_SLOT_OFFSET_SIZE");
static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN"); static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN");
static_assert(ARDUINOJSON_USE_DOUBLE == 1, "ARDUINOJSON_USE_DOUBLE"); 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)"); "sizeof(VariantSlot)");
int main() {} int main() {}

View File

@ -2,8 +2,7 @@
static_assert(ARDUINOJSON_USE_LONG_LONG == 1, "ARDUINOJSON_USE_LONG_LONG"); static_assert(ARDUINOJSON_USE_LONG_LONG == 1, "ARDUINOJSON_USE_LONG_LONG");
static_assert(ARDUINOJSON_SLOT_OFFSET_SIZE == 2, static_assert(ARDUINOJSON_SLOT_ID_SIZE == 2, "ARDUINOJSON_SLOT_ID_SIZE");
"ARDUINOJSON_SLOT_OFFSET_SIZE");
static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN"); static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN");

View File

@ -31,7 +31,8 @@ TEST_CASE("JsonDocument assignment") {
} }
SECTION("Copy assignment reallocates when capacity is smaller") { 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\"}]"); deserializeJson(doc1, "[{\"hello\":\"world\"}]");
JsonDocument doc2(sizeofArray(1), &spyingAllocator); JsonDocument doc2(sizeofArray(1), &spyingAllocator);
spyingAllocator.clearLog(); spyingAllocator.clearLog();
@ -41,14 +42,15 @@ TEST_CASE("JsonDocument assignment") {
REQUIRE(doc2.as<std::string>() == "[{\"hello\":\"world\"}]"); REQUIRE(doc2.as<std::string>() == "[{\"hello\":\"world\"}]");
REQUIRE(spyingAllocator.log() == REQUIRE(spyingAllocator.log() ==
AllocatorLog() << AllocatorLog::Deallocate(sizeofArray(1)) AllocatorLog() << AllocatorLog::Deallocate(sizeofArray(1))
<< AllocatorLog::Allocate(4096) << AllocatorLog::Allocate(capacity)
<< AllocatorLog::Allocate(sizeofString(5)) // hello << AllocatorLog::Allocate(sizeofString(5)) // hello
<< AllocatorLog::Allocate(sizeofString(5)) // world << AllocatorLog::Allocate(sizeofString(5)) // world
); );
} }
SECTION("Copy assignment reallocates when capacity is larger") { 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\"}"); deserializeJson(doc1, "{\"hello\":\"world\"}");
JsonDocument doc2(4096, &spyingAllocator); JsonDocument doc2(4096, &spyingAllocator);
spyingAllocator.clearLog(); spyingAllocator.clearLog();
@ -58,7 +60,7 @@ TEST_CASE("JsonDocument assignment") {
REQUIRE(doc2.as<std::string>() == "{\"hello\":\"world\"}"); REQUIRE(doc2.as<std::string>() == "{\"hello\":\"world\"}");
REQUIRE(spyingAllocator.log() == REQUIRE(spyingAllocator.log() ==
AllocatorLog() << AllocatorLog::Deallocate(4096) AllocatorLog() << AllocatorLog::Deallocate(4096)
<< AllocatorLog::Allocate(1024) << AllocatorLog::Allocate(capacity1)
<< AllocatorLog::Allocate(sizeofString(5)) // hello << AllocatorLog::Allocate(sizeofString(5)) // hello
<< AllocatorLog::Allocate(sizeofString(5)) // world << AllocatorLog::Allocate(sizeofString(5)) // world
); );

View File

@ -22,8 +22,9 @@ TEST_CASE("JsonDocument constructor") {
} }
SECTION("JsonDocument(const JsonDocument&)") { 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!!")); doc1.set(std::string("The size of this string is 32!!"));
JsonDocument doc2(doc1); JsonDocument doc2(doc1);
@ -32,14 +33,14 @@ TEST_CASE("JsonDocument constructor") {
REQUIRE(doc2.as<std::string>() == "The size of this string is 32!!"); REQUIRE(doc2.as<std::string>() == "The size of this string is 32!!");
} }
REQUIRE(spyingAllocator.log() == REQUIRE(spyingAllocator.log() ==
AllocatorLog() << AllocatorLog::Allocate(4096) AllocatorLog() << AllocatorLog::Allocate(capacity)
<< AllocatorLog::Allocate(sizeofString(31)) << AllocatorLog::Allocate(sizeofString(31))
<< AllocatorLog::Allocate(4096) << AllocatorLog::Allocate(capacity)
<< AllocatorLog::Allocate(sizeofString(31)) << AllocatorLog::Allocate(sizeofString(31))
<< AllocatorLog::Deallocate(sizeofString(31)) << AllocatorLog::Deallocate(sizeofString(31))
<< AllocatorLog::Deallocate(4096) << AllocatorLog::Deallocate(capacity)
<< AllocatorLog::Deallocate(sizeofString(31)) << AllocatorLog::Deallocate(sizeofString(31))
<< AllocatorLog::Deallocate(4096)); << AllocatorLog::Deallocate(capacity));
} }
SECTION("JsonDocument(JsonDocument&&)") { SECTION("JsonDocument(JsonDocument&&)") {

View File

@ -13,9 +13,10 @@ using ArduinoJson::detail::sizeofObject;
using ArduinoJson::detail::sizeofString; using ArduinoJson::detail::sizeofString;
TEST_CASE("JsonDocument::garbageCollect()") { TEST_CASE("JsonDocument::garbageCollect()") {
const size_t capacity = 100 * sizeof(ArduinoJson::detail::VariantSlot);
ControllableAllocator controllableAllocator; ControllableAllocator controllableAllocator;
SpyingAllocator spyingAllocator(&controllableAllocator); SpyingAllocator spyingAllocator(&controllableAllocator);
JsonDocument doc(4096, &spyingAllocator); JsonDocument doc(capacity, &spyingAllocator);
SECTION("when allocation succeeds") { SECTION("when allocation succeeds") {
deserializeJson(doc, "{\"blanket\":1,\"dancing\":2}"); deserializeJson(doc, "{\"blanket\":1,\"dancing\":2}");
@ -29,10 +30,10 @@ TEST_CASE("JsonDocument::garbageCollect()") {
REQUIRE(doc.memoryUsage() == sizeofObject(1) + sizeofString(7)); REQUIRE(doc.memoryUsage() == sizeofObject(1) + sizeofString(7));
REQUIRE(doc.as<std::string>() == "{\"dancing\":2}"); REQUIRE(doc.as<std::string>() == "{\"dancing\":2}");
REQUIRE(spyingAllocator.log() == REQUIRE(spyingAllocator.log() ==
AllocatorLog() << AllocatorLog::Allocate(4096) AllocatorLog() << AllocatorLog::Allocate(capacity)
<< AllocatorLog::Allocate(sizeofString(7)) << AllocatorLog::Allocate(sizeofString(7))
<< AllocatorLog::Deallocate(sizeofString(7)) << AllocatorLog::Deallocate(sizeofString(7))
<< AllocatorLog::Deallocate(4096)); << AllocatorLog::Deallocate(capacity));
} }
SECTION("when allocation fails") { SECTION("when allocation fails") {
@ -49,7 +50,7 @@ TEST_CASE("JsonDocument::garbageCollect()") {
REQUIRE(doc.as<std::string>() == "{\"dancing\":2}"); REQUIRE(doc.as<std::string>() == "{\"dancing\":2}");
REQUIRE(spyingAllocator.log() == REQUIRE(spyingAllocator.log() ==
AllocatorLog() << AllocatorLog::AllocateFail(4096) AllocatorLog() << AllocatorLog::AllocateFail(capacity)
<< AllocatorLog::AllocateFail(sizeofString(7))); << AllocatorLog::AllocateFail(sizeofString(7)));
} }
} }

View File

@ -2,6 +2,8 @@
// Copyright © 2014-2023, Benoit BLANCHON // Copyright © 2014-2023, Benoit BLANCHON
// MIT License // MIT License
#define ARDUINOJSON_SLOT_ID_SIZE 4 // required to reach 65536 elements
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <catch.hpp> #include <catch.hpp>
@ -55,6 +57,7 @@ TEST_CASE("serialize MsgPack array") {
const char* nil = 0; const char* nil = 0;
for (int i = 0; i < 65536; i++) for (int i = 0; i < 65536; i++)
array.add(nil); array.add(nil);
REQUIRE(array.size() == 65536);
check(array, check(array,
std::string("\xDD\x00\x01\x00\x00", 5) + std::string(65536, '\xc0')); std::string("\xDD\x00\x01\x00\x00", 5) + std::string(65536, '\xc0'));

View File

@ -11,13 +11,13 @@
using namespace ArduinoJson::detail; using namespace ArduinoJson::detail;
TEST_CASE("ResourceManager::allocVariant()") { TEST_CASE("ResourceManager::allocSlot()") {
SECTION("Returns different pointer") { SECTION("Returns different pointer") {
ResourceManager resources(4096); ResourceManager resources(4096);
VariantSlot* s1 = resources.allocVariant(); VariantSlot* s1 = resources.allocSlot();
REQUIRE(s1 != 0); REQUIRE(s1 != 0);
VariantSlot* s2 = resources.allocVariant(); VariantSlot* s2 = resources.allocSlot();
REQUIRE(s2 != 0); REQUIRE(s2 != 0);
REQUIRE(s1 != s2); REQUIRE(s1 != s2);
@ -26,27 +26,33 @@ TEST_CASE("ResourceManager::allocVariant()") {
SECTION("Returns aligned pointers") { SECTION("Returns aligned pointers") {
ResourceManager resources(4096); ResourceManager resources(4096);
REQUIRE(isAligned(resources.allocVariant())); REQUIRE(isAligned(resources.allocSlot().operator VariantSlot*()));
REQUIRE(isAligned(resources.allocVariant())); REQUIRE(isAligned(resources.allocSlot().operator VariantSlot*()));
} }
SECTION("Returns zero if capacity is 0") { SECTION("Returns zero if capacity is 0") {
ResourceManager resources(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") { SECTION("Returns zero if buffer is null") {
ResourceManager resources(4096, FailingAllocator::instance()); 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") { SECTION("Returns zero if capacity is insufficient") {
ResourceManager resources(sizeof(VariantSlot)); 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);
} }
} }

View File

@ -15,7 +15,7 @@ TEST_CASE("ResourceManager::clear()") {
ResourceManager resources(poolCapacity); ResourceManager resources(poolCapacity);
SECTION("Discards allocated variants") { SECTION("Discards allocated variants") {
resources.allocVariant(); resources.allocSlot();
resources.clear(); resources.clear();
REQUIRE(resources.size() == 0); REQUIRE(resources.size() == 0);

View File

@ -9,7 +9,7 @@
using namespace ArduinoJson::detail; using namespace ArduinoJson::detail;
TEST_CASE("ResourceManager::capacity()") { TEST_CASE("ResourceManager::capacity()") {
const size_t capacity = 64; const size_t capacity = 4 * sizeof(VariantSlot);
ResourceManager resources(capacity); ResourceManager resources(capacity);
REQUIRE(capacity == resources.capacity()); REQUIRE(capacity == resources.capacity());
} }
@ -25,10 +25,10 @@ TEST_CASE("ResourceManager::size()") {
const size_t variantCount = resources.capacity() / sizeof(VariantSlot); const size_t variantCount = resources.capacity() / sizeof(VariantSlot);
for (size_t i = 0; i < variantCount; i++) for (size_t i = 0; i < variantCount; i++)
resources.allocVariant(); resources.allocSlot();
size_t size = resources.size(); size_t size = resources.size();
resources.allocVariant(); resources.allocSlot();
REQUIRE(size == resources.size()); REQUIRE(size == resources.size());
} }

View File

@ -22,12 +22,13 @@ class ArrayData : public CollectionData {
VariantData* getOrAddElement(size_t index, ResourceManager* resources); 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) if (!array)
return nullptr; return nullptr;
return array->getElement(index); return array->getElement(index, resources);
} }
void removeElement(size_t index, ResourceManager* resources); void removeElement(size_t index, ResourceManager* resources);
@ -50,7 +51,7 @@ class ArrayData : public CollectionData {
} }
private: private:
iterator at(size_t index) const; iterator at(size_t index, const ResourceManager* resources) const;
}; };
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@ -9,10 +9,11 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
inline ArrayData::iterator ArrayData::at(size_t index) const { inline ArrayData::iterator ArrayData::at(
auto it = createIterator(); size_t index, const ResourceManager* resources) const {
auto it = createIterator(resources);
while (!it.done() && index) { while (!it.done() && index) {
it.next(); it.next(resources);
--index; --index;
} }
return it; return it;
@ -20,9 +21,9 @@ inline ArrayData::iterator ArrayData::at(size_t index) const {
inline VariantData* ArrayData::getOrAddElement(size_t index, inline VariantData* ArrayData::getOrAddElement(size_t index,
ResourceManager* resources) { ResourceManager* resources) {
auto it = createIterator(); auto it = createIterator(resources);
while (!it.done() && index > 0) { while (!it.done() && index > 0) {
it.next(); it.next(resources);
index--; index--;
} }
if (it.done()) if (it.done())
@ -37,12 +38,13 @@ inline VariantData* ArrayData::getOrAddElement(size_t index,
return element; return element;
} }
inline VariantData* ArrayData::getElement(size_t index) const { inline VariantData* ArrayData::getElement(
return at(index).data(); size_t index, const ResourceManager* resources) const {
return at(index, resources).data();
} }
inline void ArrayData::removeElement(size_t index, ResourceManager* resources) { inline void ArrayData::removeElement(size_t index, ResourceManager* resources) {
remove(at(index), resources); remove(at(index, resources), resources);
} }
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@ -45,7 +45,9 @@ class ElementProxy : public VariantRefBase<ElementProxy<TUpstream>>,
} }
FORCE_INLINE VariantData* getData() const { 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 { FORCE_INLINE VariantData* getOrCreateData() const {

View File

@ -68,7 +68,7 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
FORCE_INLINE iterator begin() const { FORCE_INLINE iterator begin() const {
if (!data_) if (!data_)
return iterator(); return iterator();
return iterator(data_->createIterator(), resources_); return iterator(data_->createIterator(resources_), resources_);
} }
// Returns an iterator following the last element of the array. // 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. // Returns the number of bytes occupied by the array.
// https://arduinojson.org/v6/api/jsonarray/memoryusage/ // https://arduinojson.org/v6/api/jsonarray/memoryusage/
FORCE_INLINE size_t memoryUsage() const { 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. // Returns the depth (nesting level) of the array.
// https://arduinojson.org/v6/api/jsonarray/nesting/ // https://arduinojson.org/v6/api/jsonarray/nesting/
FORCE_INLINE size_t nesting() const { 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. // Returns the number of elements in the array.
// https://arduinojson.org/v6/api/jsonarray/size/ // https://arduinojson.org/v6/api/jsonarray/size/
FORCE_INLINE size_t size() const { FORCE_INLINE size_t size() const {
return data_ ? data_->size() : 0; return data_ ? data_->size(resources_) : 0;
} }
private: private:

View File

@ -26,7 +26,7 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
FORCE_INLINE iterator begin() const { FORCE_INLINE iterator begin() const {
if (!data_) if (!data_)
return iterator(); 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. // 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. // Returns the element at the specified index.
// https://arduinojson.org/v6/api/jsonarrayconst/subscript/ // https://arduinojson.org/v6/api/jsonarrayconst/subscript/
FORCE_INLINE JsonVariantConst operator[](size_t index) const { FORCE_INLINE JsonVariantConst operator[](size_t index) const {
return JsonVariantConst(detail::ArrayData::getElement(data_, index), return JsonVariantConst(
resources_); detail::ArrayData::getElement(data_, index, resources_), resources_);
} }
operator JsonVariantConst() const { operator JsonVariantConst() const {
@ -69,19 +69,19 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
// Returns the number of bytes occupied by the array. // Returns the number of bytes occupied by the array.
// https://arduinojson.org/v6/api/jsonarrayconst/memoryusage/ // https://arduinojson.org/v6/api/jsonarrayconst/memoryusage/
FORCE_INLINE size_t memoryUsage() const { 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. // Returns the depth (nesting level) of the array.
// https://arduinojson.org/v6/api/jsonarrayconst/nesting/ // https://arduinojson.org/v6/api/jsonarrayconst/nesting/
FORCE_INLINE size_t nesting() const { 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. // Returns the number of elements in the array.
// https://arduinojson.org/v6/api/jsonarrayconst/size/ // https://arduinojson.org/v6/api/jsonarrayconst/size/
FORCE_INLINE size_t size() const { FORCE_INLINE size_t size() const {
return data_ ? data_->size() : 0; return data_ ? data_->size(resources_) : 0;
} }
private: private:

View File

@ -50,7 +50,7 @@ class JsonArrayIterator {
} }
JsonArrayIterator& operator++() { JsonArrayIterator& operator++() {
iterator_.next(); iterator_.next(resources_);
return *this; return *this;
} }
@ -84,7 +84,7 @@ class JsonArrayConstIterator {
} }
JsonArrayConstIterator& operator++() { JsonArrayConstIterator& operator++() {
iterator_.next(); iterator_.next(resources_);
return *this; return *this;
} }

View File

@ -20,7 +20,7 @@ class CollectionIterator {
public: public:
CollectionIterator() : slot_(nullptr) {} CollectionIterator() : slot_(nullptr) {}
void next(); void next(const ResourceManager* resources);
bool done() const { bool done() const {
return slot_ == nullptr; return slot_ == nullptr;
@ -70,8 +70,8 @@ class CollectionIterator {
}; };
class CollectionData { class CollectionData {
VariantSlot* head_ = 0; SlotId head_ = NULL_SLOT;
VariantSlot* tail_ = 0; SlotId tail_ = NULL_SLOT;
public: public:
// Placement new // Placement new
@ -83,13 +83,13 @@ class CollectionData {
using iterator = CollectionIterator; using iterator = CollectionIterator;
iterator createIterator() const { iterator createIterator(const ResourceManager* resources) const {
return iterator(head_); return iterator(resources->getSlot(head_));
} }
size_t memoryUsage() const; size_t memoryUsage(const ResourceManager*) const;
size_t size() const; size_t size(const ResourceManager*) const;
size_t nesting() const; size_t nesting(const ResourceManager*) const;
void clear(ResourceManager* resources); void clear(ResourceManager* resources);
@ -99,8 +99,6 @@ class CollectionData {
collection->clear(resources); collection->clear(resources);
} }
void movePointers(ptrdiff_t variantDistance);
void remove(iterator it, ResourceManager* resources); void remove(iterator it, ResourceManager* resources);
static void remove(CollectionData* collection, iterator it, static void remove(CollectionData* collection, iterator it,
@ -113,7 +111,7 @@ class CollectionData {
iterator addSlot(ResourceManager*); iterator addSlot(ResourceManager*);
private: private:
VariantSlot* getPreviousSlot(VariantSlot*) const; SlotWithId getPreviousSlot(VariantSlot*, const ResourceManager*) const;
static void releaseSlot(VariantSlot*, ResourceManager*); static void releaseSlot(VariantSlot*, ResourceManager*);
}; };

View File

@ -34,102 +34,95 @@ inline bool CollectionIterator::ownsKey() const {
return slot_->ownsKey(); return slot_->ownsKey();
} }
inline void CollectionIterator::next() { inline void CollectionIterator::next(const ResourceManager* resources) {
ARDUINOJSON_ASSERT(slot_ != nullptr); 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( inline CollectionData::iterator CollectionData::addSlot(
ResourceManager* resources) { ResourceManager* resources) {
auto slot = resources->allocVariant(); auto slot = resources->allocSlot();
if (!slot) if (!slot)
return nullptr; return nullptr;
if (tail_) { if (tail_ != NULL_SLOT) {
tail_->setNextNotNull(slot); auto tail = resources->getSlot(tail_);
tail_ = slot; tail->setNext(slot.id());
tail_ = slot.id();
} else { } else {
head_ = slot; head_ = slot.id();
tail_ = slot; tail_ = slot.id();
} }
return slot; return iterator(slot);
} }
inline void CollectionData::clear(ResourceManager* resources) { inline void CollectionData::clear(ResourceManager* resources) {
for (auto slot = head_; slot; slot = slot->next()) for (auto it = createIterator(resources); !it.done(); it.next(resources))
releaseSlot(slot, resources); releaseSlot(it.slot_, resources);
head_ = 0; head_ = NULL_SLOT;
tail_ = 0; tail_ = NULL_SLOT;
} }
inline VariantSlot* CollectionData::getPreviousSlot(VariantSlot* target) const { inline SlotWithId CollectionData::getPreviousSlot(
VariantSlot* current = head_; VariantSlot* target, const ResourceManager* resources) const {
while (current) { auto prev = SlotWithId();
VariantSlot* next = current->next(); auto currentId = head_;
if (next == target) while (currentId != NULL_SLOT) {
return current; auto currentSlot = resources->getSlot(currentId);
current = next; if (currentSlot == target)
return prev;
prev = SlotWithId(currentSlot, currentId);
currentId = currentSlot->next();
} }
return 0; return SlotWithId();
} }
inline void CollectionData::remove(iterator it, ResourceManager* resources) { inline void CollectionData::remove(iterator it, ResourceManager* resources) {
if (it.done()) if (it.done())
return; return;
auto curr = it.slot_; auto curr = it.slot_;
auto prev = getPreviousSlot(curr); auto prev = getPreviousSlot(curr, resources);
auto next = curr->next(); auto next = curr->next();
if (prev) if (prev)
prev->setNext(next); prev->setNext(next);
else else
head_ = next; head_ = next;
if (!next) if (next == NULL_SLOT)
tail_ = prev; tail_ = prev.id();
releaseSlot(curr, resources); releaseSlot(curr, resources);
} }
inline size_t CollectionData::memoryUsage() const { inline size_t CollectionData::memoryUsage(
const ResourceManager* resources) const {
size_t total = 0; size_t total = 0;
for (auto it = createIterator(); !it.done(); it.next()) { for (auto it = createIterator(resources); !it.done(); it.next(resources)) {
total += sizeof(VariantSlot) + it->memoryUsage(); total += sizeof(VariantSlot) + it->memoryUsage(resources);
if (it.ownsKey()) if (it.ownsKey())
total += sizeofString(strlen(it.key())); total += sizeofString(strlen(it.key()));
} }
return total; return total;
} }
inline size_t CollectionData::nesting() const { inline size_t CollectionData::nesting(const ResourceManager* resources) const {
size_t maxChildNesting = 0; size_t maxChildNesting = 0;
for (auto it = createIterator(); !it.done(); it.next()) { for (auto it = createIterator(resources); !it.done(); it.next(resources)) {
size_t childNesting = it->nesting(); size_t childNesting = it->nesting(resources);
if (childNesting > maxChildNesting) if (childNesting > maxChildNesting)
maxChildNesting = childNesting; maxChildNesting = childNesting;
} }
return maxChildNesting + 1; return maxChildNesting + 1;
} }
inline size_t CollectionData::size() const { inline size_t CollectionData::size(const ResourceManager* resources) const {
size_t count = 0; size_t count = 0;
for (auto it = createIterator(); !it.done(); it.next()) for (auto it = createIterator(resources); !it.done(); it.next(resources))
count++; count++;
return 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, inline void CollectionData::releaseSlot(VariantSlot* slot,
ResourceManager* resources) { ResourceManager* resources) {
ARDUINOJSON_ASSERT(slot != nullptr); ARDUINOJSON_ASSERT(slot != nullptr);

View File

@ -75,19 +75,18 @@
# define ARDUINOJSON_DEFAULT_NESTING_LIMIT 10 # define ARDUINOJSON_DEFAULT_NESTING_LIMIT 10
#endif #endif
// Number of bits to store the pointer to next node // Number of bits to store the variant identifier
// (saves RAM but limits the number of values in a document) #ifndef ARDUINOJSON_SLOT_ID_SIZE
#ifndef ARDUINOJSON_SLOT_OFFSET_SIZE
# if defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ <= 2 # if defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ <= 2
// Address space == 16-bit => max 127 values // 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 || \ # elif defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ >= 8 || \
defined(_WIN64) && _WIN64 defined(_WIN64) && _WIN64
// Address space == 64-bit => max 2147483647 values // Address space == 64-bit => max 2147483647 values
# define ARDUINOJSON_SLOT_OFFSET_SIZE 4 # define ARDUINOJSON_SLOT_ID_SIZE 4
# else # else
// Address space == 32-bit => max 32767 values // Address space == 32-bit => max 32767 values
# define ARDUINOJSON_SLOT_OFFSET_SIZE 2 # define ARDUINOJSON_SLOT_ID_SIZE 2
# endif # endif
#endif #endif

View File

@ -86,8 +86,7 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
// Reduces the capacity of the memory pool to match the current usage. // Reduces the capacity of the memory pool to match the current usage.
// https://arduinojson.org/v6/api/JsonDocument/shrinktofit/ // https://arduinojson.org/v6/api/JsonDocument/shrinktofit/
void shrinkToFit() { void shrinkToFit() {
auto offset = resources_.shrinkToFit(); resources_.shrinkToFit();
data_.movePointers(offset);
} }
// Reclaims the memory leaked when removing and replacing values. // 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/ // https://arduinojson.org/v6/api/jsondocument/as/
template <typename T> template <typename T>
T as() { T as() {
return getVariant().template as<T>(); return getSlot().template as<T>();
} }
// Casts the root to the specified type. // Casts the root to the specified type.
// https://arduinojson.org/v6/api/jsondocument/as/ // https://arduinojson.org/v6/api/jsondocument/as/
template <typename T> template <typename T>
T as() const { T as() const {
return getVariant().template as<T>(); return getSlot().template as<T>();
} }
// Empties the document and resets the memory pool // 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/ // https://arduinojson.org/v6/api/jsondocument/is/
template <typename T> template <typename T>
bool is() { bool is() {
return getVariant().template is<T>(); return getSlot().template is<T>();
} }
// Returns true if the root is of the specified type. // Returns true if the root is of the specified type.
// https://arduinojson.org/v6/api/jsondocument/is/ // https://arduinojson.org/v6/api/jsondocument/is/
template <typename T> template <typename T>
bool is() const { bool is() const {
return getVariant().template is<T>(); return getSlot().template is<T>();
} }
// Returns true if the root is null. // Returns true if the root is null.
// https://arduinojson.org/v6/api/jsondocument/isnull/ // https://arduinojson.org/v6/api/jsondocument/isnull/
bool isNull() const { bool isNull() const {
return getVariant().isNull(); return getSlot().isNull();
} }
// Returns the number of used bytes in the memory pool. // 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. // Returns the depth (nesting level) of the array.
// https://arduinojson.org/v6/api/jsondocument/nesting/ // https://arduinojson.org/v6/api/jsondocument/nesting/
size_t nesting() const { size_t nesting() const {
return data_.nesting(); return data_.nesting(&resources_);
} }
// Returns the number of elements in the root array or object. // Returns the number of elements in the root array or object.
// https://arduinojson.org/v6/api/jsondocument/size/ // https://arduinojson.org/v6/api/jsondocument/size/
size_t size() const { size_t size() const {
return data_.size(); return data_.size(&resources_);
} }
// Copies the specified document. // Copies the specified document.
@ -186,7 +185,7 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
template <typename T> template <typename T>
typename detail::VariantTo<T>::type to() { typename detail::VariantTo<T>::type to() {
clear(); clear();
return getVariant().template to<T>(); return getSlot().template to<T>();
} }
// Creates an array and appends it to the root array. // 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/ // https://arduinojson.org/v6/api/jsondocument/containskey/
template <typename TChar> template <typename TChar>
bool containsKey(TChar* key) const { 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. // Returns true if the root object contains the specified key.
// https://arduinojson.org/v6/api/jsondocument/containskey/ // https://arduinojson.org/v6/api/jsondocument/containskey/
template <typename TString> template <typename TString>
bool containsKey(const TString& key) const { 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. // 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, FORCE_INLINE typename detail::enable_if<detail::IsString<TString>::value,
JsonVariantConst>::type JsonVariantConst>::type
operator[](const TString& key) const { operator[](const TString& key) const {
return JsonVariantConst(data_.getMember(detail::adaptString(key)), return JsonVariantConst(
&resources_); data_.getMember(detail::adaptString(key), &resources_), &resources_);
} }
// Gets a root object's member. // 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, FORCE_INLINE typename detail::enable_if<detail::IsString<TChar*>::value,
JsonVariantConst>::type JsonVariantConst>::type
operator[](TChar* key) const { operator[](TChar* key) const {
return JsonVariantConst(data_.getMember(detail::adaptString(key)), return JsonVariantConst(
&resources_); data_.getMember(detail::adaptString(key), &resources_), &resources_);
} }
// Gets or sets a root array's element. // 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. // Gets a root array's member.
// https://arduinojson.org/v6/api/jsondocument/subscript/ // https://arduinojson.org/v6/api/jsondocument/subscript/
FORCE_INLINE JsonVariantConst operator[](size_t index) const { 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. // Appends a new (null) element to the root array.
@ -345,19 +344,19 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
} }
FORCE_INLINE operator JsonVariant() { FORCE_INLINE operator JsonVariant() {
return getVariant(); return getSlot();
} }
FORCE_INLINE operator JsonVariantConst() const { FORCE_INLINE operator JsonVariantConst() const {
return getVariant(); return getSlot();
} }
private: private:
JsonVariant getVariant() { JsonVariant getSlot() {
return JsonVariant(&data_, &resources_); return JsonVariant(&data_, &resources_);
} }
JsonVariantConst getVariant() const { JsonVariantConst getSlot() const {
return JsonVariantConst(&data_, &resources_); return JsonVariantConst(&data_, &resources_);
} }

View File

@ -273,7 +273,7 @@ class JsonDeserializer {
TFilter memberFilter = filter[key.c_str()]; TFilter memberFilter = filter[key.c_str()];
if (memberFilter.allow()) { if (memberFilter.allow()) {
auto member = object.getMember(adaptString(key.c_str())); auto member = object.getMember(adaptString(key.c_str()), resources_);
if (!member) { if (!member) {
// Save key in memory pool. // Save key in memory pool.
auto savedKey = stringBuilder_.save(); auto savedKey = stringBuilder_.save();

View File

@ -16,17 +16,18 @@ class JsonSerializer : public VariantDataVisitor<size_t> {
public: public:
static const bool producesText = true; 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) { FORCE_INLINE size_t visit(const ArrayData& array) {
write('['); write('[');
auto it = array.createIterator(); auto it = array.createIterator(resources_);
while (!it.done()) { while (!it.done()) {
it->accept(*this); it->accept(*this);
it.next(); it.next(resources_);
if (it.done()) if (it.done())
break; break;
@ -40,14 +41,14 @@ class JsonSerializer : public VariantDataVisitor<size_t> {
size_t visit(const ObjectData& object) { size_t visit(const ObjectData& object) {
write('{'); write('{');
auto it = object.createIterator(); auto it = object.createIterator(resources_);
while (!it.done()) { while (!it.done()) {
formatter_.writeString(it.key()); formatter_.writeString(it.key());
write(':'); write(':');
it->accept(*this); it->accept(*this);
it.next(); it.next(resources_);
if (it.done()) if (it.done())
break; break;
@ -113,6 +114,9 @@ class JsonSerializer : public VariantDataVisitor<size_t> {
private: private:
TextFormatter<TWriter> formatter_; TextFormatter<TWriter> formatter_;
protected:
const ResourceManager* resources_;
}; };
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@ -16,10 +16,11 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
typedef JsonSerializer<TWriter> base; typedef JsonSerializer<TWriter> base;
public: 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) { size_t visit(const ArrayData& array) {
auto it = array.createIterator(); auto it = array.createIterator(base::resources_);
if (!it.done()) { if (!it.done()) {
base::write("[\r\n"); base::write("[\r\n");
nesting_++; nesting_++;
@ -27,7 +28,7 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
indent(); indent();
it->accept(*this); it->accept(*this);
it.next(); it.next(base::resources_);
base::write(it.done() ? "\r\n" : ",\r\n"); base::write(it.done() ? "\r\n" : ",\r\n");
} }
nesting_--; nesting_--;
@ -40,7 +41,7 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
} }
size_t visit(const ObjectData& object) { size_t visit(const ObjectData& object) {
auto it = object.createIterator(); auto it = object.createIterator(base::resources_);
if (!it.done()) { if (!it.done()) {
base::write("{\r\n"); base::write("{\r\n");
nesting_++; nesting_++;
@ -50,7 +51,7 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
base::write(": "); base::write(": ");
it->accept(*this); it->accept(*this);
it.next(); it.next(base::resources_);
base::write(it.done() ? "\r\n" : ",\r\n"); base::write(it.done() ? "\r\n" : ",\r\n");
} }
nesting_--; nesting_--;

View File

@ -67,13 +67,17 @@ class ResourceManager {
return overflowed_; return overflowed_;
} }
VariantSlot* allocVariant() { SlotWithId allocSlot() {
auto p = variantPool_.allocVariant(); auto p = variantPool_.allocSlot();
if (!p) if (!p)
overflowed_ = true; overflowed_ = true;
return p; return p;
} }
VariantSlot* getSlot(SlotId id) const {
return variantPool_.getSlot(id);
}
template <typename TAdaptedString> template <typename TAdaptedString>
StringNode* saveString(TAdaptedString str) { StringNode* saveString(TAdaptedString str) {
if (str.isNull()) if (str.isNull())
@ -123,8 +127,8 @@ class ResourceManager {
stringPool_.clear(allocator_); stringPool_.clear(allocator_);
} }
ptrdiff_t shrinkToFit() { void shrinkToFit() {
return variantPool_.shrinkToFit(allocator_); variantPool_.shrinkToFit(allocator_);
} }
private: private:

View File

@ -6,10 +6,39 @@
#include <ArduinoJson/Memory/ResourceManager.hpp> #include <ArduinoJson/Memory/ResourceManager.hpp>
#include <ArduinoJson/Polyfills/assert.hpp> #include <ArduinoJson/Polyfills/assert.hpp>
#include <ArduinoJson/Polyfills/integer.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
class VariantSlot; 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 { class VariantPool {
public: public:
@ -30,18 +59,19 @@ class VariantPool {
void create(size_t cap, Allocator* allocator); void create(size_t cap, Allocator* allocator);
void destroy(Allocator* allocator); void destroy(Allocator* allocator);
VariantSlot* allocVariant(); SlotWithId allocSlot();
VariantSlot* getSlot(SlotId id) const;
void clear(); void clear();
ptrdiff_t shrinkToFit(Allocator*); void shrinkToFit(Allocator*);
size_t capacity() const; SlotCount capacity() const;
size_t usage() const; SlotCount usage() const;
static size_t bytesToSlots(size_t); static SlotCount bytesToSlots(size_t);
static size_t slotsToBytes(size_t); static size_t slotsToBytes(SlotCount);
private: private:
size_t capacity_ = 0; SlotCount capacity_ = 0;
size_t usage_ = 0; SlotCount usage_ = 0;
VariantSlot* slots_ = nullptr; VariantSlot* slots_ = nullptr;
}; };

View File

@ -28,29 +28,31 @@ inline void VariantPool::destroy(Allocator* allocator) {
usage_ = 0; usage_ = 0;
} }
inline ptrdiff_t VariantPool::shrinkToFit(Allocator* allocator) { inline void VariantPool::shrinkToFit(Allocator* allocator) {
auto originalPool = slots_;
slots_ = reinterpret_cast<VariantSlot*>( slots_ = reinterpret_cast<VariantSlot*>(
allocator->reallocate(slots_, slotsToBytes(usage_))); allocator->reallocate(slots_, slotsToBytes(usage_)));
if (slots_) capacity_ = usage_;
capacity_ = usage_;
return reinterpret_cast<char*>(slots_) -
reinterpret_cast<char*>(originalPool);
} }
inline VariantSlot* VariantPool::allocVariant() { inline SlotWithId VariantPool::allocSlot() {
if (!slots_) if (!slots_)
return nullptr; return {};
if (usage_ + 1 > capacity_) if (usage_ >= capacity_)
return nullptr; return {};
return new (&slots_[usage_++]) VariantSlot; 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_; return usage_;
} }
inline size_t VariantPool::capacity() const { inline SlotCount VariantPool::capacity() const {
return capacity_; return capacity_;
} }
@ -58,11 +60,11 @@ inline void VariantPool::clear() {
usage_ = 0; usage_ = 0;
} }
inline size_t VariantPool::bytesToSlots(size_t n) { inline SlotCount VariantPool::bytesToSlots(size_t n) {
return n / sizeof(VariantSlot); 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); return n * sizeof(VariantSlot);
} }

View File

@ -19,7 +19,8 @@ class MsgPackSerializer : public VariantDataVisitor<size_t> {
public: public:
static const bool producesText = false; static const bool producesText = false;
MsgPackSerializer(TWriter writer) : writer_(writer) {} MsgPackSerializer(TWriter writer, const ResourceManager* resources)
: writer_(writer), resources_(resources) {}
template <typename T> template <typename T>
typename enable_if<is_floating_point<T>::value && sizeof(T) == 4, 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 visit(const ArrayData& array) {
size_t n = array.size(); size_t n = array.size(resources_);
if (n < 0x10) { if (n < 0x10) {
writeByte(uint8_t(0x90 + n)); writeByte(uint8_t(0x90 + n));
} else if (n < 0x10000) { } else if (n < 0x10000) {
@ -58,14 +59,15 @@ class MsgPackSerializer : public VariantDataVisitor<size_t> {
writeByte(0xDD); writeByte(0xDD);
writeInteger(uint32_t(n)); 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); it->accept(*this);
} }
return bytesWritten(); return bytesWritten();
} }
size_t visit(const ObjectData& object) { size_t visit(const ObjectData& object) {
size_t n = object.size(); size_t n = object.size(resources_);
if (n < 0x10) { if (n < 0x10) {
writeByte(uint8_t(0x80 + n)); writeByte(uint8_t(0x80 + n));
} else if (n < 0x10000) { } else if (n < 0x10000) {
@ -75,7 +77,8 @@ class MsgPackSerializer : public VariantDataVisitor<size_t> {
writeByte(0xDF); writeByte(0xDF);
writeInteger(uint32_t(n)); 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()); visit(it.key());
it->accept(*this); it->accept(*this);
} }
@ -200,6 +203,7 @@ class MsgPackSerializer : public VariantDataVisitor<size_t> {
} }
CountingDecorator<TWriter> writer_; CountingDecorator<TWriter> writer_;
const ResourceManager* resources_;
}; };
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@ -19,7 +19,7 @@
ARDUINOJSON_ENABLE_INFINITY, \ ARDUINOJSON_ENABLE_INFINITY, \
ARDUINOJSON_ENABLE_COMMENTS, \ ARDUINOJSON_ENABLE_COMMENTS, \
ARDUINOJSON_DECODE_UNICODE), \ ARDUINOJSON_DECODE_UNICODE), \
ARDUINOJSON_SLOT_OFFSET_SIZE) ARDUINOJSON_SLOT_ID_SIZE)
#endif #endif

View File

@ -56,19 +56,19 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
// Returns the number of bytes occupied by the object. // Returns the number of bytes occupied by the object.
// https://arduinojson.org/v6/api/jsonobject/memoryusage/ // https://arduinojson.org/v6/api/jsonobject/memoryusage/
FORCE_INLINE size_t memoryUsage() const { 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. // Returns the depth (nesting level) of the object.
// https://arduinojson.org/v6/api/jsonobject/nesting/ // https://arduinojson.org/v6/api/jsonobject/nesting/
FORCE_INLINE size_t nesting() const { 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. // Returns the number of members in the object.
// https://arduinojson.org/v6/api/jsonobject/size/ // https://arduinojson.org/v6/api/jsonobject/size/
FORCE_INLINE size_t size() const { 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. // 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 { FORCE_INLINE iterator begin() const {
if (!data_) if (!data_)
return iterator(); 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. // Returns an iterator following the last key-value pair of the object.
@ -158,7 +158,8 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
FORCE_INLINE FORCE_INLINE
typename detail::enable_if<detail::IsString<TString>::value, bool>::type typename detail::enable_if<detail::IsString<TString>::value, bool>::type
containsKey(const TString& key) const { 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. // Returns true if the object contains the specified key.
@ -167,7 +168,8 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
FORCE_INLINE FORCE_INLINE
typename detail::enable_if<detail::IsString<TChar*>::value, bool>::type typename detail::enable_if<detail::IsString<TChar*>::value, bool>::type
containsKey(TChar* key) const { 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. // Creates an array and adds it to the object.

View File

@ -45,19 +45,19 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
// Returns the number of bytes occupied by the object. // Returns the number of bytes occupied by the object.
// https://arduinojson.org/v6/api/jsonobjectconst/memoryusage/ // https://arduinojson.org/v6/api/jsonobjectconst/memoryusage/
FORCE_INLINE size_t memoryUsage() const { 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. // Returns the depth (nesting level) of the object.
// https://arduinojson.org/v6/api/jsonobjectconst/nesting/ // https://arduinojson.org/v6/api/jsonobjectconst/nesting/
FORCE_INLINE size_t nesting() const { 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. // Returns the number of members in the object.
// https://arduinojson.org/v6/api/jsonobjectconst/size/ // https://arduinojson.org/v6/api/jsonobjectconst/size/
FORCE_INLINE size_t size() const { 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. // 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 { FORCE_INLINE iterator begin() const {
if (!data_) if (!data_)
return iterator(); 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. // 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/ // https://arduinojson.org/v6/api/jsonobjectconst/containskey/
template <typename TString> template <typename TString>
FORCE_INLINE bool containsKey(const TString& key) const { 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. // Returns true if the object contains the specified key.
// https://arduinojson.org/v6/api/jsonobjectconst/containskey/ // https://arduinojson.org/v6/api/jsonobjectconst/containskey/
template <typename TChar> template <typename TChar>
FORCE_INLINE bool containsKey(TChar* key) const { 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. // 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, FORCE_INLINE typename detail::enable_if<detail::IsString<TString>::value,
JsonVariantConst>::type JsonVariantConst>::type
operator[](const TString& key) const { operator[](const TString& key) const {
return JsonVariantConst( return JsonVariantConst(detail::ObjectData::getMember(
detail::ObjectData::getMember(data_, detail::adaptString(key)), data_, detail::adaptString(key), resources_),
resources_); resources_);
} }
// Gets the member with specified key. // Gets the member with specified key.

View File

@ -54,16 +54,16 @@ template <typename TDerived>
template <typename TString> template <typename TString>
inline typename enable_if<IsString<TString>::value, bool>::type inline typename enable_if<IsString<TString>::value, bool>::type
VariantRefBase<TDerived>::containsKey(const TString& key) const { VariantRefBase<TDerived>::containsKey(const TString& key) const {
return VariantData::getMember(VariantAttorney::getData(derived()), return VariantData::getMember(getData(), adaptString(key),
adaptString(key)) != 0; getResourceManager()) != 0;
} }
template <typename TDerived> template <typename TDerived>
template <typename TChar> template <typename TChar>
inline typename enable_if<IsString<TChar*>::value, bool>::type inline typename enable_if<IsString<TChar*>::value, bool>::type
VariantRefBase<TDerived>::containsKey(TChar* key) const { VariantRefBase<TDerived>::containsKey(TChar* key) const {
return VariantData::getMember(VariantAttorney::getData(derived()), return VariantData::getMember(getData(), adaptString(key),
adaptString(key)) != 0; getResourceManager()) != 0;
} }
template <typename TDerived> template <typename TDerived>

View File

@ -34,7 +34,7 @@ class JsonObjectIterator {
} }
JsonObjectIterator& operator++() { JsonObjectIterator& operator++() {
iterator_.next(); iterator_.next(resources_);
return *this; return *this;
} }
@ -69,7 +69,7 @@ class JsonObjectConstIterator {
} }
JsonObjectConstIterator& operator++() { JsonObjectConstIterator& operator++() {
iterator_.next(); iterator_.next(resources_);
return *this; return *this;
} }

View File

@ -46,8 +46,9 @@ class MemberProxy
} }
FORCE_INLINE VariantData* getData() const { FORCE_INLINE VariantData* getData() const {
return VariantData::getMember(VariantAttorney::getData(upstream_), return VariantData::getMember(
adaptString(key_)); VariantAttorney::getData(upstream_), adaptString(key_),
VariantAttorney::getResourceManager(upstream_));
} }
FORCE_INLINE VariantData* getOrCreateData() const { FORCE_INLINE VariantData* getOrCreateData() const {

View File

@ -43,13 +43,15 @@ class ObjectData : public CollectionData {
VariantData* getOrAddMember(TAdaptedString key, ResourceManager* resources); VariantData* getOrAddMember(TAdaptedString key, ResourceManager* resources);
template <typename TAdaptedString> template <typename TAdaptedString>
VariantData* getMember(TAdaptedString key) const; VariantData* getMember(TAdaptedString key,
const ResourceManager* resources) const;
template <typename TAdaptedString> template <typename TAdaptedString>
static VariantData* getMember(const ObjectData* object, TAdaptedString key) { static VariantData* getMember(const ObjectData* object, TAdaptedString key,
const ResourceManager* resources) {
if (!object) if (!object)
return nullptr; return nullptr;
return object->getMember(key); return object->getMember(key, resources);
} }
template <typename TAdaptedString> template <typename TAdaptedString>
@ -65,7 +67,7 @@ class ObjectData : public CollectionData {
private: private:
template <typename TAdaptedString> template <typename TAdaptedString>
iterator findKey(TAdaptedString key) const; iterator findKey(TAdaptedString key, const ResourceManager* resources) const;
}; };
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@ -10,24 +10,26 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename TAdaptedString> template <typename TAdaptedString>
inline VariantData* ObjectData::getMember(TAdaptedString key) const { inline VariantData* ObjectData::getMember(
return findKey(key).data(); TAdaptedString key, const ResourceManager* resources) const {
return findKey(key, resources).data();
} }
template <typename TAdaptedString> template <typename TAdaptedString>
VariantData* ObjectData::getOrAddMember(TAdaptedString key, VariantData* ObjectData::getOrAddMember(TAdaptedString key,
ResourceManager* resources) { ResourceManager* resources) {
auto it = findKey(key); auto it = findKey(key, resources);
if (!it.done()) if (!it.done())
return it.data(); return it.data();
return addMember(key, resources); return addMember(key, resources);
} }
template <typename TAdaptedString> 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()) if (key.isNull())
return iterator(); 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()))) if (stringEquals(key, adaptString(it.key())))
return it; return it;
} }
@ -37,7 +39,7 @@ inline ObjectData::iterator ObjectData::findKey(TAdaptedString key) const {
template <typename TAdaptedString> template <typename TAdaptedString>
inline void ObjectData::removeMember(TAdaptedString key, inline void ObjectData::removeMember(TAdaptedString key,
ResourceManager* resources) { ResourceManager* resources) {
remove(findKey(key), resources); remove(findKey(key, resources), resources);
} }
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@ -11,21 +11,21 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <int Bits> template <int Bits>
struct int_t; struct uint_t;
template <> template <>
struct int_t<8> { struct uint_t<8> {
typedef int8_t type; typedef uint8_t type;
}; };
template <> template <>
struct int_t<16> { struct uint_t<16> {
typedef int16_t type; typedef uint16_t type;
}; };
template <> template <>
struct int_t<32> { struct uint_t<32> {
typedef int32_t type; typedef uint32_t type;
}; };
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@ -11,7 +11,8 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <template <typename> class TSerializer> template <template <typename> class TSerializer>
size_t measure(ArduinoJson::JsonVariantConst source) { size_t measure(ArduinoJson::JsonVariantConst source) {
DummyWriter dp; DummyWriter dp;
TSerializer<DummyWriter> serializer(dp); TSerializer<DummyWriter> serializer(
dp, VariantAttorney::getResourceManager(source));
return VariantData::accept(VariantAttorney::getData(source), serializer); return VariantData::accept(VariantAttorney::getData(source), serializer);
} }

View File

@ -10,7 +10,8 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <template <typename> class TSerializer, typename TWriter> template <template <typename> class TSerializer, typename TWriter>
size_t doSerialize(ArduinoJson::JsonVariantConst source, TWriter writer) { 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); return VariantData::accept(VariantAttorney::getData(source), serializer);
} }

View File

@ -94,7 +94,7 @@ inline JsonVariant VariantRefBase<TDerived>::add() const {
} }
template <typename TDerived> template <typename TDerived>
inline JsonVariant VariantRefBase<TDerived>::getVariant() const { inline JsonVariant VariantRefBase<TDerived>::getSlot() const {
return JsonVariant(getData(), getResourceManager()); return JsonVariant(getData(), getResourceManager());
} }

View File

@ -50,19 +50,19 @@ class JsonVariantConst : public detail::VariantTag,
// Returns the number of bytes occupied by the value. // Returns the number of bytes occupied by the value.
// https://arduinojson.org/v6/api/jsonvariantconst/memoryusage/ // https://arduinojson.org/v6/api/jsonvariantconst/memoryusage/
FORCE_INLINE size_t memoryUsage() const { 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. // Returns the depth (nesting level) of the value.
// https://arduinojson.org/v6/api/jsonvariantconst/nesting/ // https://arduinojson.org/v6/api/jsonvariantconst/nesting/
FORCE_INLINE size_t nesting() const { 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. // Returns the size of the array or object.
// https://arduinojson.org/v6/api/jsonvariantconst/size/ // https://arduinojson.org/v6/api/jsonvariantconst/size/
size_t size() const { size_t size() const {
return detail::VariantData::size(data_); return detail::VariantData::size(data_, resources_);
} }
// Casts the value to the specified type. // Casts the value to the specified type.
@ -93,8 +93,8 @@ class JsonVariantConst : public detail::VariantTag,
// Gets array's element at specified index. // Gets array's element at specified index.
// https://arduinojson.org/v6/api/jsonvariantconst/subscript/ // https://arduinojson.org/v6/api/jsonvariantconst/subscript/
FORCE_INLINE JsonVariantConst operator[](size_t index) const { FORCE_INLINE JsonVariantConst operator[](size_t index) const {
return JsonVariantConst(detail::VariantData::getElement(data_, index), return JsonVariantConst(
resources_); detail::VariantData::getElement(data_, index, resources_), resources_);
} }
// Gets object's member with specified key. // 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, FORCE_INLINE typename detail::enable_if<detail::IsString<TString>::value,
JsonVariantConst>::type JsonVariantConst>::type
operator[](const TString& key) const { operator[](const TString& key) const {
return JsonVariantConst( return JsonVariantConst(detail::VariantData::getMember(
detail::VariantData::getMember(data_, detail::adaptString(key)), data_, detail::adaptString(key), resources_),
resources_); resources_);
} }
// Gets object's member with specified key. // 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, FORCE_INLINE typename detail::enable_if<detail::IsString<TChar*>::value,
JsonVariantConst>::type JsonVariantConst>::type
operator[](TChar* key) const { operator[](TChar* key) const {
return JsonVariantConst( return JsonVariantConst(detail::VariantData::getMember(
detail::VariantData::getMember(data_, detail::adaptString(key)), data_, detail::adaptString(key), resources_),
resources_); resources_);
} }
// Returns true if tge object contains the specified key. // Returns true if tge object contains the specified key.
@ -125,8 +125,8 @@ class JsonVariantConst : public detail::VariantTag,
FORCE_INLINE FORCE_INLINE
typename detail::enable_if<detail::IsString<TString>::value, bool>::type typename detail::enable_if<detail::IsString<TString>::value, bool>::type
containsKey(const TString& key) const { containsKey(const TString& key) const {
return detail::VariantData::getMember(getData(), return detail::VariantData::getMember(getData(), detail::adaptString(key),
detail::adaptString(key)) != 0; resources_) != 0;
} }
// Returns true if tge object contains the specified key. // Returns true if tge object contains the specified key.
@ -135,8 +135,8 @@ class JsonVariantConst : public detail::VariantTag,
FORCE_INLINE FORCE_INLINE
typename detail::enable_if<detail::IsString<TChar*>::value, bool>::type typename detail::enable_if<detail::IsString<TChar*>::value, bool>::type
containsKey(TChar* key) const { containsKey(TChar* key) const {
return detail::VariantData::getMember(getData(), return detail::VariantData::getMember(getData(), detail::adaptString(key),
detail::adaptString(key)) != 0; resources_) != 0;
} }
protected: protected:

View File

@ -185,30 +185,28 @@ class VariantData {
} }
} }
VariantData* getElement(size_t index) const { VariantData* getElement(size_t index,
auto array = asArray(); const ResourceManager* resources) const {
if (!array) return ArrayData::getElement(asArray(), index, resources);
return nullptr;
return array->getElement(index);
} }
static VariantData* getElement(const VariantData* var, size_t index) { static VariantData* getElement(const VariantData* var, size_t index,
return var != 0 ? var->getElement(index) : 0; const ResourceManager* resources) {
return var != 0 ? var->getElement(index, resources) : 0;
} }
template <typename TAdaptedString> template <typename TAdaptedString>
VariantData* getMember(TAdaptedString key) const { VariantData* getMember(TAdaptedString key,
auto object = asObject(); const ResourceManager* resources) const {
if (!object) return ObjectData::getMember(asObject(), key, resources);
return nullptr;
return object->getMember(key);
} }
template <typename TAdaptedString> template <typename TAdaptedString>
static VariantData* getMember(const VariantData* var, TAdaptedString key) { static VariantData* getMember(const VariantData* var, TAdaptedString key,
const ResourceManager* resources) {
if (!var) if (!var)
return 0; return 0;
return var->getMember(key); return var->getMember(key, resources);
} }
VariantData* getOrAddElement(size_t index, ResourceManager* 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; return type() == VALUE_IS_LINKED_STRING || type() == VALUE_IS_OWNED_STRING;
} }
size_t memoryUsage() const { size_t memoryUsage(const ResourceManager* resources) const {
switch (type()) { switch (type()) {
case VALUE_IS_OWNED_STRING: case VALUE_IS_OWNED_STRING:
case VALUE_IS_RAW_STRING: case VALUE_IS_RAW_STRING:
return sizeofString(content_.asOwnedString->length); return sizeofString(content_.asOwnedString->length);
case VALUE_IS_OBJECT: case VALUE_IS_OBJECT:
case VALUE_IS_ARRAY: case VALUE_IS_ARRAY:
return content_.asCollection.memoryUsage(); return content_.asCollection.memoryUsage(resources);
default: default:
return 0; return 0;
} }
} }
void movePointers(ptrdiff_t variantDistance) { size_t nesting(const ResourceManager* resources) const {
if (flags_ & COLLECTION_MASK)
content_.asCollection.movePointers(variantDistance);
}
size_t nesting() const {
auto collection = asCollection(); auto collection = asCollection();
if (collection) if (collection)
return collection->nesting(); return collection->nesting(resources);
else else
return 0; return 0;
} }
static size_t nesting(const VariantData* var) { static size_t nesting(const VariantData* var,
const ResourceManager* resources) {
if (!var) if (!var)
return 0; return 0;
return var->nesting(); return var->nesting(resources);
} }
void operator=(const VariantData& src) { void operator=(const VariantData& src) {
@ -455,12 +449,12 @@ class VariantData {
content_.asOwnedString = s; content_.asOwnedString = s;
} }
size_t size() const { size_t size(const ResourceManager* resources) const {
return isCollection() ? content_.asCollection.size() : 0; return isCollection() ? content_.asCollection.size(resources) : 0;
} }
static size_t size(const VariantData* var) { static size_t size(const VariantData* var, const ResourceManager* resources) {
return var != 0 ? var->size() : 0; return var != 0 ? var->size(resources) : 0;
} }
ArrayData& toArray() { ArrayData& toArray() {

View File

@ -58,7 +58,7 @@ class VariantRefBase : public VariantTag {
template <typename T> template <typename T>
FORCE_INLINE typename enable_if<ConverterNeedsWriteableRef<T>::value, T>::type FORCE_INLINE typename enable_if<ConverterNeedsWriteableRef<T>::value, T>::type
as() const { as() const {
return Converter<T>::fromJson(getVariant()); return Converter<T>::fromJson(getSlot());
} }
template <typename T> template <typename T>
@ -92,7 +92,7 @@ class VariantRefBase : public VariantTag {
FORCE_INLINE FORCE_INLINE
typename enable_if<ConverterNeedsWriteableRef<T>::value, bool>::type typename enable_if<ConverterNeedsWriteableRef<T>::value, bool>::type
is() const { is() const {
return Converter<T>::checkJson(getVariant()); return Converter<T>::checkJson(getSlot());
} }
// Returns true if the value is of the specified type. // 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. // Returns the size of the array or object.
// https://arduinojson.org/v6/api/jsonvariant/size/ // https://arduinojson.org/v6/api/jsonvariant/size/
FORCE_INLINE size_t size() const { FORCE_INLINE size_t size() const {
return VariantData::size(getData()); return VariantData::size(getData(), getResourceManager());
} }
// Returns the number of bytes occupied by the value. // Returns the number of bytes occupied by the value.
// https://arduinojson.org/v6/api/jsonvariant/memoryusage/ // https://arduinojson.org/v6/api/jsonvariant/memoryusage/
FORCE_INLINE size_t memoryUsage() const { FORCE_INLINE size_t memoryUsage() const {
VariantData* data = getData(); VariantData* data = getData();
return data ? data->memoryUsage() : 0; return data ? data->memoryUsage(getResourceManager()) : 0;
} }
// Returns the depth (nesting level) of the value. // Returns the depth (nesting level) of the value.
// https://arduinojson.org/v6/api/jsonvariant/nesting/ // https://arduinojson.org/v6/api/jsonvariant/nesting/
FORCE_INLINE size_t nesting() const { FORCE_INLINE size_t nesting() const {
return VariantData::nesting(getData()); return VariantData::nesting(getData(), getResourceManager());
} }
// Appends a new (null) element to the array. // Appends a new (null) element to the array.
@ -269,7 +269,7 @@ class VariantRefBase : public VariantTag {
} }
private: private:
FORCE_INLINE ArduinoJson::JsonVariant getVariant() const; FORCE_INLINE ArduinoJson::JsonVariant getSlot() const;
FORCE_INLINE ArduinoJson::JsonVariantConst getVariantConst() const { FORCE_INLINE ArduinoJson::JsonVariantConst getVariantConst() const {
return ArduinoJson::JsonVariantConst(getData(), getResourceManager()); return ArduinoJson::JsonVariantConst(getData(), getResourceManager());

View File

@ -5,7 +5,6 @@
#pragma once #pragma once
#include <ArduinoJson/Memory/ResourceManager.hpp> #include <ArduinoJson/Memory/ResourceManager.hpp>
#include <ArduinoJson/Polyfills/integer.hpp>
#include <ArduinoJson/Polyfills/limits.hpp> #include <ArduinoJson/Polyfills/limits.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp> #include <ArduinoJson/Polyfills/type_traits.hpp>
#include <ArduinoJson/Variant/VariantContent.hpp> #include <ArduinoJson/Variant/VariantContent.hpp>
@ -14,15 +13,13 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
struct StringNode; struct StringNode;
typedef int_t<ARDUINOJSON_SLOT_OFFSET_SIZE * 8>::type VariantSlotDiff;
class VariantSlot { class VariantSlot {
// CAUTION: same layout as VariantData // CAUTION: same layout as VariantData
// we cannot use composition because it adds padding // we cannot use composition because it adds padding
// (+20% on ESP8266 for example) // (+20% on ESP8266 for example)
VariantContent content_; VariantContent content_;
uint8_t flags_; uint8_t flags_;
VariantSlotDiff next_; SlotId next_;
const char* key_; const char* key_;
public: public:
@ -33,7 +30,7 @@ class VariantSlot {
static void operator delete(void*, void*) noexcept {} static void operator delete(void*, void*) noexcept {}
VariantSlot() : flags_(0), next_(0), key_(0) {} VariantSlot() : flags_(0), next_(NULL_SLOT), key_(0) {}
VariantData* data() { VariantData* data() {
return reinterpret_cast<VariantData*>(&content_); return reinterpret_cast<VariantData*>(&content_);
@ -43,29 +40,12 @@ class VariantSlot {
return reinterpret_cast<const VariantData*>(&content_); return reinterpret_cast<const VariantData*>(&content_);
} }
VariantSlot* next() { SlotId next() const {
return next_ ? this + next_ : 0; return next_;
} }
const VariantSlot* next() const { void setNext(SlotId slot) {
return const_cast<VariantSlot*>(this)->next(); next_ = slot;
}
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 setKey(const char* k) { void setKey(const char* k) {