diff --git a/extras/tests/ResourceManager/allocVariant.cpp b/extras/tests/ResourceManager/allocVariant.cpp index 4a3685d8..ec0ae91f 100644 --- a/extras/tests/ResourceManager/allocVariant.cpp +++ b/extras/tests/ResourceManager/allocVariant.cpp @@ -9,28 +9,28 @@ using namespace ArduinoJson::detail; -TEST_CASE("ResourceManager::allocSlot()") { +TEST_CASE("ResourceManager::allocVariant()") { SECTION("Returns different pointer") { ResourceManager resources; - VariantSlot* s1 = resources.allocSlot(); - REQUIRE(s1 != 0); - VariantSlot* s2 = resources.allocSlot(); - REQUIRE(s2 != 0); + auto s1 = resources.allocVariant(); + REQUIRE(s1.data() != nullptr); + auto s2 = resources.allocVariant(); + REQUIRE(s2.data() != nullptr); - REQUIRE(s1 != s2); + REQUIRE(s1.data() != s2.data()); } - SECTION("Returns the same slot after calling freeSlot()") { + SECTION("Returns the same slot after calling freeVariant()") { ResourceManager resources; - auto s1 = resources.allocSlot(); - auto s2 = resources.allocSlot(); - resources.freeSlot(s1); - resources.freeSlot(s2); - auto s3 = resources.allocSlot(); - auto s4 = resources.allocSlot(); - auto s5 = resources.allocSlot(); + auto s1 = resources.allocVariant(); + auto s2 = resources.allocVariant(); + resources.freeVariant(s1); + resources.freeVariant(s2); + auto s3 = resources.allocVariant(); + auto s4 = resources.allocVariant(); + auto s5 = resources.allocVariant(); REQUIRE(s2.id() != s1.id()); REQUIRE(s3.id() == s2.id()); @@ -42,26 +42,26 @@ TEST_CASE("ResourceManager::allocSlot()") { SECTION("Returns aligned pointers") { ResourceManager resources; - REQUIRE(isAligned(resources.allocSlot().operator VariantSlot*())); - REQUIRE(isAligned(resources.allocSlot().operator VariantSlot*())); + REQUIRE(isAligned(resources.allocVariant().data())); + REQUIRE(isAligned(resources.allocVariant().data())); } SECTION("Returns null if pool list allocation fails") { ResourceManager resources(FailingAllocator::instance()); - auto variant = resources.allocSlot(); + auto variant = resources.allocVariant(); REQUIRE(variant.id() == NULL_SLOT); - REQUIRE(static_cast(variant) == nullptr); + REQUIRE(variant.data() == nullptr); } SECTION("Returns null if pool allocation fails") { ResourceManager resources(FailingAllocator::instance()); - resources.allocSlot(); + resources.allocVariant(); - auto variant = resources.allocSlot(); + auto variant = resources.allocVariant(); REQUIRE(variant.id() == NULL_SLOT); - REQUIRE(static_cast(variant) == nullptr); + REQUIRE(variant.data() == nullptr); } SECTION("Try overflow pool counter") { @@ -73,18 +73,18 @@ TEST_CASE("ResourceManager::allocSlot()") { // fill all the pools for (SlotId i = 0; i < NULL_SLOT; i++) { - auto slot = resources.allocSlot(); + auto slot = resources.allocVariant(); REQUIRE(slot.id() == i); // or != NULL_SLOT - REQUIRE(static_cast(slot) != nullptr); + REQUIRE(slot.data() != nullptr); } REQUIRE(resources.overflowed() == false); // now all allocations should fail for (int i = 0; i < 10; i++) { - auto slot = resources.allocSlot(); + auto slot = resources.allocVariant(); REQUIRE(slot.id() == NULL_SLOT); - REQUIRE(static_cast(slot) == nullptr); + REQUIRE(slot.data() == nullptr); } REQUIRE(resources.overflowed() == true); diff --git a/extras/tests/ResourceManager/clear.cpp b/extras/tests/ResourceManager/clear.cpp index 30afd905..94b9baf4 100644 --- a/extras/tests/ResourceManager/clear.cpp +++ b/extras/tests/ResourceManager/clear.cpp @@ -3,6 +3,7 @@ // MIT License #include +#include #include #include #include @@ -13,7 +14,7 @@ TEST_CASE("ResourceManager::clear()") { ResourceManager resources; SECTION("Discards allocated variants") { - resources.allocSlot(); + resources.allocVariant(); resources.clear(); REQUIRE(resources.size() == 0); diff --git a/extras/tests/ResourceManager/shrinkToFit.cpp b/extras/tests/ResourceManager/shrinkToFit.cpp index 74197703..b7562ca5 100644 --- a/extras/tests/ResourceManager/shrinkToFit.cpp +++ b/extras/tests/ResourceManager/shrinkToFit.cpp @@ -3,6 +3,7 @@ // MIT License #include +#include #include #include @@ -21,7 +22,7 @@ TEST_CASE("ResourceManager::shrinkToFit()") { } SECTION("only one pool") { - resources.allocSlot(); + resources.allocVariant(); resources.shrinkToFit(); @@ -36,7 +37,7 @@ TEST_CASE("ResourceManager::shrinkToFit()") { for (size_t i = 0; i < ARDUINOJSON_POOL_CAPACITY * ARDUINOJSON_INITIAL_POOL_COUNT + 1; i++) - resources.allocSlot(); + resources.allocVariant(); REQUIRE(spyingAllocator.log() == AllocatorLog{ Allocate(sizeofPool()) * ARDUINOJSON_INITIAL_POOL_COUNT, diff --git a/extras/tests/ResourceManager/size.cpp b/extras/tests/ResourceManager/size.cpp index 6b09b17e..ff637b61 100644 --- a/extras/tests/ResourceManager/size.cpp +++ b/extras/tests/ResourceManager/size.cpp @@ -3,6 +3,7 @@ // MIT License #include +#include #include #include @@ -21,10 +22,10 @@ TEST_CASE("ResourceManager::size()") { SECTION("Doesn't grow when allocation of second pool fails") { timebomb.setCountdown(1); for (size_t i = 0; i < ARDUINOJSON_POOL_CAPACITY; i++) - resources.allocSlot(); + resources.allocVariant(); size_t size = resources.size(); - resources.allocSlot(); + resources.allocVariant(); REQUIRE(size == resources.size()); } diff --git a/extras/tests/ResourceManager/swap.cpp b/extras/tests/ResourceManager/swap.cpp index 4fdb45cb..eb511660 100644 --- a/extras/tests/ResourceManager/swap.cpp +++ b/extras/tests/ResourceManager/swap.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -14,7 +15,7 @@ using namespace ArduinoJson::detail; static void fullPreallocatedPools(ResourceManager& resources) { for (int i = 0; i < ARDUINOJSON_INITIAL_POOL_COUNT * ARDUINOJSON_POOL_CAPACITY; i++) - resources.allocSlot(); + resources.allocVariant(); } TEST_CASE("ResourceManager::swap()") { @@ -23,13 +24,13 @@ TEST_CASE("ResourceManager::swap()") { ResourceManager a(&spy); ResourceManager b(&spy); - auto a1 = a.allocSlot(); - auto b1 = b.allocSlot(); + auto a1 = a.allocVariant(); + auto b1 = b.allocVariant(); swap(a, b); - REQUIRE(a1->data() == b.getSlot(a1.id())->data()); - REQUIRE(b1->data() == a.getSlot(b1.id())->data()); + REQUIRE(a1.data() == b.getVariant(a1.id())); + REQUIRE(b1.data() == a.getVariant(b1.id())); REQUIRE(spy.log() == AllocatorLog{ Allocate(sizeofPool()) * 2, @@ -42,12 +43,12 @@ TEST_CASE("ResourceManager::swap()") { ResourceManager b(&spy); fullPreallocatedPools(b); - auto a1 = a.allocSlot(); - auto b1 = b.allocSlot(); + auto a1 = a.allocVariant(); + auto b1 = b.allocVariant(); swap(a, b); - REQUIRE(a1->data() == b.getSlot(a1.id())->data()); - REQUIRE(b1->data() == a.getSlot(b1.id())->data()); + REQUIRE(a1.data() == b.getVariant(a1.id())); + REQUIRE(b1.data() == a.getVariant(b1.id())); REQUIRE(spy.log() == AllocatorLog{ @@ -63,12 +64,12 @@ TEST_CASE("ResourceManager::swap()") { fullPreallocatedPools(a); ResourceManager b(&spy); - auto a1 = a.allocSlot(); - auto b1 = b.allocSlot(); + auto a1 = a.allocVariant(); + auto b1 = b.allocVariant(); swap(a, b); - REQUIRE(a1->data() == b.getSlot(a1.id())->data()); - REQUIRE(b1->data() == a.getSlot(b1.id())->data()); + REQUIRE(a1.data() == b.getVariant(a1.id())); + REQUIRE(b1.data() == a.getVariant(b1.id())); REQUIRE(spy.log() == AllocatorLog{ @@ -85,12 +86,12 @@ TEST_CASE("ResourceManager::swap()") { ResourceManager b(&spy); fullPreallocatedPools(b); - auto a1 = a.allocSlot(); - auto b1 = b.allocSlot(); + auto a1 = a.allocVariant(); + auto b1 = b.allocVariant(); swap(a, b); - REQUIRE(a1->data() == b.getSlot(a1.id())->data()); - REQUIRE(b1->data() == a.getSlot(b1.id())->data()); + REQUIRE(a1.data() == b.getVariant(a1.id())); + REQUIRE(b1.data() == a.getVariant(b1.id())); } } diff --git a/src/ArduinoJson/Array/ArrayImpl.hpp b/src/ArduinoJson/Array/ArrayImpl.hpp index 6e64b016..2b72d586 100644 --- a/src/ArduinoJson/Array/ArrayImpl.hpp +++ b/src/ArduinoJson/Array/ArrayImpl.hpp @@ -20,11 +20,11 @@ inline ArrayData::iterator ArrayData::at( } inline VariantData* ArrayData::addElement(ResourceManager* resources) { - auto slot = resources->allocSlot(); + auto slot = resources->allocVariant(); if (!slot) return nullptr; CollectionData::appendOne(slot, resources); - return slot->data(); + return slot.data(); } inline VariantData* ArrayData::getOrAddElement(size_t index, @@ -58,12 +58,12 @@ inline void ArrayData::removeElement(size_t index, ResourceManager* resources) { template inline bool ArrayData::addValue(T&& value, ResourceManager* resources) { ARDUINOJSON_ASSERT(resources != nullptr); - auto slot = resources->allocSlot(); + auto slot = resources->allocVariant(); if (!slot) return false; - JsonVariant variant(slot->data(), resources); + JsonVariant variant(slot.data(), resources); if (!variant.set(detail::forward(value))) { - resources->freeSlot(slot); + resources->freeVariant(slot); return false; } CollectionData::appendOne(slot, resources); diff --git a/src/ArduinoJson/Collection/CollectionData.hpp b/src/ArduinoJson/Collection/CollectionData.hpp index b4960897..aa0825bc 100644 --- a/src/ArduinoJson/Collection/CollectionData.hpp +++ b/src/ArduinoJson/Collection/CollectionData.hpp @@ -12,7 +12,7 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE class VariantData; -class VariantSlot; +union VariantSlot; class CollectionIterator { friend class CollectionData; @@ -58,9 +58,9 @@ class CollectionIterator { } private: - CollectionIterator(VariantSlot* slot, SlotId slotId); + CollectionIterator(VariantData* slot, SlotId slotId); - VariantSlot* slot_; + VariantData* slot_; SlotId currentId_, nextId_; }; @@ -79,7 +79,7 @@ class CollectionData { using iterator = CollectionIterator; iterator createIterator(const ResourceManager* resources) const { - return iterator(resources->getSlot(head_), head_); + return iterator(resources->getVariant(head_), head_); } size_t size(const ResourceManager*) const; @@ -98,15 +98,15 @@ class CollectionData { } protected: - void appendOne(SlotWithId slot, const ResourceManager* resources); - void appendPair(SlotWithId key, SlotWithId value, + void appendOne(VariantWithId slot, const ResourceManager* resources); + void appendPair(VariantWithId key, VariantWithId value, const ResourceManager* resources); void removeOne(iterator it, ResourceManager* resources); void removePair(iterator it, ResourceManager* resources); private: - SlotWithId getPreviousSlot(VariantSlot*, const ResourceManager*) const; + VariantWithId getPreviousSlot(VariantData*, const ResourceManager*) const; }; inline const VariantData* collectionToVariant( diff --git a/src/ArduinoJson/Collection/CollectionImpl.hpp b/src/ArduinoJson/Collection/CollectionImpl.hpp index e6ae3f22..d68f48ac 100644 --- a/src/ArduinoJson/Collection/CollectionImpl.hpp +++ b/src/ArduinoJson/Collection/CollectionImpl.hpp @@ -12,23 +12,23 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -inline CollectionIterator::CollectionIterator(VariantSlot* slot, SlotId slotId) +inline CollectionIterator::CollectionIterator(VariantData* slot, SlotId slotId) : slot_(slot), currentId_(slotId) { nextId_ = slot_ ? slot_->next() : NULL_SLOT; } inline void CollectionIterator::next(const ResourceManager* resources) { ARDUINOJSON_ASSERT(currentId_ != NULL_SLOT); - slot_ = resources->getSlot(nextId_); + slot_ = resources->getVariant(nextId_); currentId_ = nextId_; if (slot_) nextId_ = slot_->next(); } -inline void CollectionData::appendOne(SlotWithId slot, +inline void CollectionData::appendOne(VariantWithId slot, const ResourceManager* resources) { if (tail_ != NULL_SLOT) { - auto tail = resources->getSlot(tail_); + auto tail = resources->getVariant(tail_); tail->setNext(slot.id()); tail_ = slot.id(); } else { @@ -37,12 +37,12 @@ inline void CollectionData::appendOne(SlotWithId slot, } } -inline void CollectionData::appendPair(SlotWithId key, SlotWithId value, +inline void CollectionData::appendPair(VariantWithId key, VariantWithId value, const ResourceManager* resources) { key->setNext(value.id()); if (tail_ != NULL_SLOT) { - auto tail = resources->getSlot(tail_); + auto tail = resources->getVariant(tail_); tail->setNext(key.id()); tail_ = value.id(); } else { @@ -55,24 +55,24 @@ inline void CollectionData::clear(ResourceManager* resources) { auto next = head_; while (next != NULL_SLOT) { auto currId = next; - auto slot = resources->getSlot(next); + auto slot = resources->getVariant(next); next = slot->next(); - resources->freeSlot(SlotWithId(slot, currId)); + resources->freeVariant(VariantWithId(slot, currId)); } head_ = NULL_SLOT; tail_ = NULL_SLOT; } -inline SlotWithId CollectionData::getPreviousSlot( - VariantSlot* target, const ResourceManager* resources) const { - auto prev = SlotWithId(); +inline VariantWithId CollectionData::getPreviousSlot( + VariantData* target, const ResourceManager* resources) const { + auto prev = VariantWithId(); auto currentId = head_; while (currentId != NULL_SLOT) { - auto currentSlot = resources->getSlot(currentId); + auto currentSlot = resources->getVariant(currentId); if (currentSlot == target) break; - prev = SlotWithId(currentSlot, currentId); + prev = VariantWithId(currentSlot, currentId); currentId = currentSlot->next(); } return prev; @@ -90,7 +90,7 @@ inline void CollectionData::removeOne(iterator it, ResourceManager* resources) { head_ = next; if (next == NULL_SLOT) tail_ = prev.id(); - resources->freeSlot({it.slot_, it.currentId_}); + resources->freeVariant({it.slot_, it.currentId_}); } inline void CollectionData::removePair(ObjectData::iterator it, @@ -101,11 +101,11 @@ inline void CollectionData::removePair(ObjectData::iterator it, auto keySlot = it.slot_; auto valueId = it.nextId_; - auto valueSlot = resources->getSlot(valueId); + auto valueSlot = resources->getVariant(valueId); // remove value slot keySlot->setNext(valueSlot->next()); - resources->freeSlot({valueSlot, valueId}); + resources->freeVariant({valueSlot, valueId}); // remove key slot removeOne(it, resources); diff --git a/src/ArduinoJson/Json/JsonSerializer.hpp b/src/ArduinoJson/Json/JsonSerializer.hpp index 4f3c16e6..187b3bff 100644 --- a/src/ArduinoJson/Json/JsonSerializer.hpp +++ b/src/ArduinoJson/Json/JsonSerializer.hpp @@ -25,9 +25,9 @@ class JsonSerializer : public VariantDataVisitor { auto slotId = array.head(); while (slotId != NULL_SLOT) { - auto slot = resources_->getSlot(slotId); + auto slot = resources_->getVariant(slotId); - slot->data()->accept(*this); + slot->accept(*this); slotId = slot->next(); @@ -47,8 +47,8 @@ class JsonSerializer : public VariantDataVisitor { bool isKey = true; while (slotId != NULL_SLOT) { - auto slot = resources_->getSlot(slotId); - slot->data()->accept(*this); + auto slot = resources_->getVariant(slotId); + slot->accept(*this); slotId = slot->next(); diff --git a/src/ArduinoJson/Memory/ResourceManager.hpp b/src/ArduinoJson/Memory/ResourceManager.hpp index 2270e4f6..51cbe134 100644 --- a/src/ArduinoJson/Memory/ResourceManager.hpp +++ b/src/ArduinoJson/Memory/ResourceManager.hpp @@ -13,8 +13,10 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -class VariantSlot; +union VariantSlot; class VariantPool; +class VariantData; +class VariantWithId; class ResourceManager { public: @@ -49,18 +51,11 @@ class ResourceManager { return overflowed_; } - SlotWithId allocSlot() { - auto p = variantPools_.allocSlot(allocator_); - if (!p) - overflowed_ = true; - return p; - } + VariantWithId allocVariant(); - void freeSlot(SlotWithId slot); + void freeVariant(VariantWithId slot); - VariantSlot* getSlot(SlotId id) const { - return variantPools_.getSlot(id); - } + VariantData* getVariant(SlotId id) const; template StringNode* saveString(TAdaptedString str) { diff --git a/src/ArduinoJson/Memory/ResourceManagerImpl.hpp b/src/ArduinoJson/Memory/ResourceManagerImpl.hpp index c9f004d8..2e112fa7 100644 --- a/src/ArduinoJson/Memory/ResourceManagerImpl.hpp +++ b/src/ArduinoJson/Memory/ResourceManagerImpl.hpp @@ -7,12 +7,26 @@ #include #include #include +#include ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -inline void ResourceManager::freeSlot(SlotWithId slot) { - slot->data()->setNull(this); - variantPools_.freeSlot(slot); +inline VariantWithId ResourceManager::allocVariant() { + auto p = variantPools_.allocSlot(allocator_); + if (!p) { + overflowed_ = true; + return {}; + } + return {new (&p->variant) VariantData, p.id()}; +} + +inline void ResourceManager::freeVariant(VariantWithId variant) { + variant->setNull(this); + variantPools_.freeSlot(variant); +} + +inline VariantData* ResourceManager::getVariant(SlotId id) const { + return reinterpret_cast(variantPools_.getSlot(id)); } ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/src/ArduinoJson/Memory/StringPool.hpp b/src/ArduinoJson/Memory/StringPool.hpp index dcdc98b6..74ea710a 100644 --- a/src/ArduinoJson/Memory/StringPool.hpp +++ b/src/ArduinoJson/Memory/StringPool.hpp @@ -12,7 +12,7 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -class VariantSlot; +union VariantSlot; class VariantPool; class StringPool { diff --git a/src/ArduinoJson/Memory/VariantPool.hpp b/src/ArduinoJson/Memory/VariantPool.hpp index 5fe37bc7..92d468ff 100644 --- a/src/ArduinoJson/Memory/VariantPool.hpp +++ b/src/ArduinoJson/Memory/VariantPool.hpp @@ -10,7 +10,7 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE -class VariantSlot; +union VariantSlot; using SlotId = uint_t; using SlotCount = SlotId; const SlotId NULL_SLOT = SlotId(-1); @@ -22,11 +22,15 @@ class SlotWithId { ARDUINOJSON_ASSERT((slot == nullptr) == (id == NULL_SLOT)); } + explicit operator bool() const { + return slot_ != nullptr; + } + SlotId id() const { return id_; } - operator VariantSlot*() { + VariantSlot* slot() const { return slot_; } diff --git a/src/ArduinoJson/Memory/VariantPoolImpl.hpp b/src/ArduinoJson/Memory/VariantPoolImpl.hpp index d53be32d..833eb627 100644 --- a/src/ArduinoJson/Memory/VariantPoolImpl.hpp +++ b/src/ArduinoJson/Memory/VariantPoolImpl.hpp @@ -41,7 +41,7 @@ inline SlotWithId VariantPool::allocSlot() { return {}; auto index = usage_++; auto slot = &slots_[index]; - return {new (slot) VariantSlot, SlotId(index)}; + return {slot, SlotId(index)}; } inline VariantSlot* VariantPool::getSlot(SlotId id) const { @@ -69,12 +69,12 @@ inline SlotWithId VariantPoolList::allocFromFreeList() { ARDUINOJSON_ASSERT(freeList_ != NULL_SLOT); auto id = freeList_; auto slot = getSlot(freeList_); - freeList_ = slot->next(); - return {new (slot) VariantSlot, id}; + freeList_ = slot->free.next; + return {slot, id}; } inline void VariantPoolList::freeSlot(SlotWithId slot) { - slot->setNext(freeList_); + slot->free.next = freeList_; freeList_ = slot.id(); } diff --git a/src/ArduinoJson/Memory/VariantPoolList.hpp b/src/ArduinoJson/Memory/VariantPoolList.hpp index 8ee5cef6..db2db329 100644 --- a/src/ArduinoJson/Memory/VariantPoolList.hpp +++ b/src/ArduinoJson/Memory/VariantPoolList.hpp @@ -138,7 +138,8 @@ class VariantPoolList { auto slot = pools_[poolIndex].allocSlot(); if (!slot) return {}; - return {slot, SlotId(poolIndex * ARDUINOJSON_POOL_CAPACITY + slot.id())}; + return {slot.slot(), + SlotId(poolIndex * ARDUINOJSON_POOL_CAPACITY + slot.id())}; } VariantPool* addPool(Allocator* allocator) { diff --git a/src/ArduinoJson/MsgPack/MsgPackSerializer.hpp b/src/ArduinoJson/MsgPack/MsgPackSerializer.hpp index e34959cf..d92997b6 100644 --- a/src/ArduinoJson/MsgPack/MsgPackSerializer.hpp +++ b/src/ArduinoJson/MsgPack/MsgPackSerializer.hpp @@ -61,8 +61,8 @@ class MsgPackSerializer : public VariantDataVisitor { auto slotId = array.head(); while (slotId != NULL_SLOT) { - auto slot = resources_->getSlot(slotId); - slot->data()->accept(*this); + auto slot = resources_->getVariant(slotId); + slot->accept(*this); slotId = slot->next(); } @@ -83,8 +83,8 @@ class MsgPackSerializer : public VariantDataVisitor { auto slotId = object.head(); while (slotId != NULL_SLOT) { - auto slot = resources_->getSlot(slotId); - slot->data()->accept(*this); + auto slot = resources_->getVariant(slotId); + slot->accept(*this); slotId = slot->next(); } diff --git a/src/ArduinoJson/Object/ObjectImpl.hpp b/src/ArduinoJson/Object/ObjectImpl.hpp index 67c1c089..b193a929 100644 --- a/src/ArduinoJson/Object/ObjectImpl.hpp +++ b/src/ArduinoJson/Object/ObjectImpl.hpp @@ -51,20 +51,20 @@ inline void ObjectData::removeMember(TAdaptedString key, template inline VariantData* ObjectData::addMember(TAdaptedString key, ResourceManager* resources) { - auto keySlot = resources->allocSlot(); + auto keySlot = resources->allocVariant(); if (!keySlot) return nullptr; - auto valueSlot = resources->allocSlot(); + auto valueSlot = resources->allocVariant(); if (!valueSlot) return nullptr; - if (!keySlot->data()->setString(key, resources)) + if (!keySlot->setString(key, resources)) return nullptr; CollectionData::appendPair(keySlot, valueSlot, resources); - return valueSlot->data(); + return valueSlot.data(); } ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/src/ArduinoJson/Variant/VariantData.hpp b/src/ArduinoJson/Variant/VariantData.hpp index 2ad1ca87..a808547e 100644 --- a/src/ArduinoJson/Variant/VariantData.hpp +++ b/src/ArduinoJson/Variant/VariantData.hpp @@ -5,12 +5,12 @@ #pragma once #include +#include #include #include #include #include #include -#include ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE @@ -20,9 +20,25 @@ T parseNumber(const char* s); class VariantData { VariantContent content_; // must be first to allow cast from array to variant uint8_t type_; + SlotId next_; public: - VariantData() : type_(VALUE_IS_NULL) {} + // Placement new + static void* operator new(size_t, void* p) noexcept { + return p; + } + + static void operator delete(void*, void*) noexcept {} + + VariantData() : type_(VALUE_IS_NULL), next_(NULL_SLOT) {} + + SlotId next() const { + return next_; + } + + void setNext(SlotId slot) { + next_ = slot; + } template typename TVisitor::result_type accept(TVisitor& visit) const { @@ -518,4 +534,20 @@ class VariantData { } }; +class VariantWithId : public SlotWithId { + public: + VariantWithId() {} + VariantWithId(VariantData* data, SlotId id) + : SlotWithId(reinterpret_cast(data), id) {} + + VariantData* data() { + return reinterpret_cast(slot()); + } + + VariantData* operator->() { + ARDUINOJSON_ASSERT(data() != nullptr); + return data(); + } +}; + ARDUINOJSON_END_PRIVATE_NAMESPACE diff --git a/src/ArduinoJson/Variant/VariantSlot.hpp b/src/ArduinoJson/Variant/VariantSlot.hpp index 810f0bf6..a600c6af 100644 --- a/src/ArduinoJson/Variant/VariantSlot.hpp +++ b/src/ArduinoJson/Variant/VariantSlot.hpp @@ -7,52 +7,22 @@ #include #include #include -#include +#include ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE struct StringNode; -class VariantSlot { - // CAUTION: same layout as VariantData - // we cannot use composition because it adds padding - // (+20% on ESP8266 for example) - VariantContent content_; - uint8_t type_; - SlotId next_; - - public: - // Placement new - static void* operator new(size_t, void* p) noexcept { - return p; - } - - static void operator delete(void*, void*) noexcept {} - - VariantSlot() : type_(0), next_(NULL_SLOT) { - (void)type_; // HACK: suppress Clang warning "private field is not used" - } - - VariantData* data() { - return reinterpret_cast(&content_); - } - - const VariantData* data() const { - return reinterpret_cast(&content_); - } - - SlotId next() const { - return next_; - } - - void setNext(SlotId slot) { - next_ = slot; - } +struct FreeSlot { + SlotId next; }; -inline VariantData* slotData(VariantSlot* slot) { - return reinterpret_cast(slot); -} +union VariantSlot { + VariantSlot() {} + + VariantData variant; + FreeSlot free; +}; // Returns the size (in bytes) of an array with n elements. constexpr size_t sizeofArray(size_t n) {