mirror of
https://github.com/bblanchon/ArduinoJson.git
synced 2025-07-16 12:02:14 +02:00
Store index of slot in the pool instead of a pointer or a distance
This commit is contained in:
@ -4,8 +4,7 @@ static_assert(ARDUINOJSON_ENABLE_PROGMEM == 1, "ARDUINOJSON_ENABLE_PROGMEM");
|
|||||||
|
|
||||||
static_assert(ARDUINOJSON_USE_LONG_LONG == 0, "ARDUINOJSON_USE_LONG_LONG");
|
static_assert(ARDUINOJSON_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");
|
||||||
|
|
||||||
|
@ -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");
|
||||||
|
|
||||||
|
@ -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() {}
|
||||||
|
@ -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");
|
||||||
|
|
||||||
|
@ -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
|
||||||
);
|
);
|
||||||
|
@ -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&&)") {
|
||||||
|
@ -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)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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'));
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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:
|
||||||
|
@ -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:
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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*);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
@ -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
|
||||||
|
@ -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_--;
|
||||||
|
@ -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:
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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,8 +96,8 @@ 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_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,8 +103,8 @@ 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_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,8 +114,8 @@ 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_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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:
|
||||||
|
@ -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() {
|
||||||
|
@ -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());
|
||||||
|
@ -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) {
|
||||||
|
Reference in New Issue
Block a user