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_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");

View File

@ -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");

View File

@ -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() {}

View File

@ -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");

View File

@ -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
);

View File

@ -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&&)") {

View File

@ -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)));
}
}

View File

@ -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'));

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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());
}

View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -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:

View File

@ -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:

View File

@ -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;
}

View File

@ -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*);
};

View File

@ -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);

View File

@ -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

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.
// 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_);
}

View File

@ -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();

View File

@ -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

View File

@ -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_--;

View File

@ -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:

View File

@ -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;
};

View File

@ -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);
}

View File

@ -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

View File

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

View File

@ -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.

View File

@ -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.

View File

@ -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>

View File

@ -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;
}

View File

@ -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 {

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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());
}

View File

@ -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:

View File

@ -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() {

View File

@ -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());

View File

@ -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) {