فهرست منبع

Store object members with two slots: one for the key and one for the value

Benoit Blanchon 1 سال پیش
والد
کامیت
09c89dcacf

+ 5 - 0
CHANGELOG.md

@@ -1,6 +1,11 @@
 ArduinoJson: change log
 =======================
 
+HEAD
+----
+
+* Store object members with two slots: one for the key and one for the value
+
 v7.1.0 (2024-06-27)
 ------
 

+ 1 - 1
extras/conf_test/avr.cpp

@@ -10,7 +10,7 @@ static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN");
 
 static_assert(ARDUINOJSON_USE_DOUBLE == 1, "ARDUINOJSON_USE_DOUBLE");
 
-static_assert(sizeof(ArduinoJson::detail::VariantSlot) == 8,
+static_assert(sizeof(ArduinoJson::detail::VariantSlot) == 6,
               "sizeof(VariantSlot)");
 
 void setup() {}

+ 1 - 1
extras/conf_test/linux32.cpp

@@ -8,7 +8,7 @@ static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN");
 
 static_assert(ARDUINOJSON_USE_DOUBLE == 1, "ARDUINOJSON_USE_DOUBLE");
 
-static_assert(sizeof(ArduinoJson::detail::VariantSlot) == 16,
+static_assert(sizeof(ArduinoJson::detail::VariantSlot) == 12,
               "sizeof(VariantSlot)");
 
 int main() {}

+ 1 - 1
extras/conf_test/linux64.cpp

@@ -8,7 +8,7 @@ static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN");
 
 static_assert(ARDUINOJSON_USE_DOUBLE == 1, "ARDUINOJSON_USE_DOUBLE");
 
-static_assert(sizeof(ArduinoJson::detail::VariantSlot) == 24,
+static_assert(sizeof(ArduinoJson::detail::VariantSlot) == 16,
               "sizeof(VariantSlot)");
 
 int main() {}

+ 1 - 1
extras/conf_test/win64.cpp

@@ -8,7 +8,7 @@ static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN");
 
 static_assert(ARDUINOJSON_USE_DOUBLE == 1, "ARDUINOJSON_USE_DOUBLE");
 
-static_assert(sizeof(ArduinoJson::detail::VariantSlot) == 24,
+static_assert(sizeof(ArduinoJson::detail::VariantSlot) == 16,
               "sizeof(VariantSlot)");
 
 int main() {}

+ 6 - 0
extras/tests/JsonArray/remove.cpp

@@ -68,6 +68,12 @@ TEST_CASE("JsonArray::remove()") {
     REQUIRE(array[1] == 2);
   }
 
+  SECTION("remove end()") {
+    array.remove(array.end());
+
+    REQUIRE(3 == array.size());
+  }
+
   SECTION("In a loop") {
     for (JsonArray::iterator it = array.begin(); it != array.end(); ++it) {
       if (*it == 2)

+ 2 - 2
extras/tests/JsonDeserializer/object.cpp

@@ -308,12 +308,12 @@ TEST_CASE("deserialize JSON object") {
       REQUIRE(doc["a"] == 2);
     }
 
-    SECTION("NUL in keys") {  // we don't support NULs in keys
+    SECTION("NUL in keys") {
       DeserializationError err =
           deserializeJson(doc, "{\"x\\u0000a\":1,\"x\\u0000b\":2}");
 
       REQUIRE(err == DeserializationError::Ok);
-      REQUIRE(doc.as<std::string>() == "{\"x\":2}");
+      REQUIRE(doc.as<std::string>() == "{\"x\\u0000a\":1,\"x\\u0000b\":2}");
     }
   }
 

+ 36 - 4
extras/tests/JsonDocument/MemberProxy.cpp

@@ -345,12 +345,12 @@ TEST_CASE("Deduplicate keys") {
 }
 
 TEST_CASE("MemberProxy under memory constraints") {
-  KillswitchAllocator killswitch;
-  SpyingAllocator spy(&killswitch);
+  TimebombAllocator timebomb(1);
+  SpyingAllocator spy(&timebomb);
   JsonDocument doc(&spy);
 
-  SECTION("key allocation fails") {
-    killswitch.on();
+  SECTION("key slot allocation fails") {
+    timebomb.setCountdown(0);
 
     doc["hello"_s] = "world";
 
@@ -361,4 +361,36 @@ TEST_CASE("MemberProxy under memory constraints") {
                              AllocateFail(sizeofPool()),
                          });
   }
+
+  SECTION("value slot allocation fails") {
+    timebomb.setCountdown(1);
+
+    // fill the pool entirely, but leave one slot for the key
+    doc["foo"][ARDUINOJSON_POOL_CAPACITY - 4] = 1;
+    REQUIRE(doc.overflowed() == false);
+
+    doc["hello"_s] = "world";
+
+    REQUIRE(doc.is<JsonObject>());
+    REQUIRE(doc.size() == 1);
+    REQUIRE(doc.overflowed() == true);
+    REQUIRE(spy.log() == AllocatorLog{
+                             Allocate(sizeofPool()),
+                             AllocateFail(sizeofPool()),
+                         });
+  }
+
+  SECTION("key string allocation fails") {
+    timebomb.setCountdown(1);
+
+    doc["hello"_s] = "world";
+
+    REQUIRE(doc.is<JsonObject>());
+    REQUIRE(doc.size() == 0);
+    REQUIRE(doc.overflowed() == true);
+    REQUIRE(spy.log() == AllocatorLog{
+                             Allocate(sizeofPool()),
+                             AllocateFail(sizeofString("hello")),
+                         });
+  }
 }

+ 1 - 1
extras/tests/JsonDocument/shrinkToFit.cpp

@@ -178,7 +178,7 @@ TEST_CASE("JsonDocument::shrinkToFit()") {
             AllocatorLog{
                 Allocate(sizeofPool()),
                 Allocate(sizeofString("abcdefg")),
-                Reallocate(sizeofPool(), sizeofPool(1)),
+                Reallocate(sizeofPool(), sizeofPool(2)),
             });
   }
 }

+ 11 - 3
src/ArduinoJson/Array/ArrayData.hpp

@@ -10,9 +10,7 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
 
 class ArrayData : public CollectionData {
  public:
-  VariantData* addElement(ResourceManager* resources) {
-    return addSlot(resources).data();
-  }
+  VariantData* addElement(ResourceManager* resources);
 
   static VariantData* addElement(ArrayData* array, ResourceManager* resources) {
     if (!array)
@@ -51,6 +49,16 @@ class ArrayData : public CollectionData {
     array->removeElement(index, resources);
   }
 
+  void remove(iterator it, ResourceManager* resources) {
+    CollectionData::removeOne(it, resources);
+  }
+
+  static void remove(ArrayData* array, iterator it,
+                     ResourceManager* resources) {
+    if (array)
+      return array->remove(it, resources);
+  }
+
  private:
   iterator at(size_t index, const ResourceManager* resources) const;
 };

+ 9 - 1
src/ArduinoJson/Array/ArrayImpl.hpp

@@ -19,6 +19,14 @@ inline ArrayData::iterator ArrayData::at(
   return it;
 }
 
+inline VariantData* ArrayData::addElement(ResourceManager* resources) {
+  auto slot = resources->allocSlot();
+  if (!slot)
+    return nullptr;
+  CollectionData::appendOne(slot, resources);
+  return slot->data();
+}
+
 inline VariantData* ArrayData::getOrAddElement(size_t index,
                                                ResourceManager* resources) {
   auto it = createIterator(resources);
@@ -58,7 +66,7 @@ inline bool ArrayData::addValue(T&& value, ResourceManager* resources) {
     resources->freeSlot(slot);
     return false;
   }
-  addSlot(slot, resources);
+  CollectionData::appendOne(slot, resources);
   return true;
 }
 

+ 6 - 17
src/ArduinoJson/Collection/CollectionData.hpp

@@ -49,12 +49,6 @@ class CollectionIterator {
     return *data();
   }
 
-  const char* key() const;
-  bool ownsKey() const;
-
-  void setKey(StringNode*);
-  void setKey(const char*);
-
   VariantData* data() {
     return reinterpret_cast<VariantData*>(slot_);
   }
@@ -99,22 +93,17 @@ class CollectionData {
     collection->clear(resources);
   }
 
-  void remove(iterator it, ResourceManager* resources);
-
-  static void remove(CollectionData* collection, iterator it,
-                     ResourceManager* resources) {
-    if (collection)
-      return collection->remove(it, resources);
-  }
-
   SlotId head() const {
     return head_;
   }
 
-  void addSlot(SlotWithId slot, ResourceManager* resources);
-
  protected:
-  iterator addSlot(ResourceManager*);
+  void appendOne(SlotWithId slot, const ResourceManager* resources);
+  void appendPair(SlotWithId key, SlotWithId value,
+                  const ResourceManager* resources);
+
+  void removeOne(iterator it, ResourceManager* resources);
+  void removePair(iterator it, ResourceManager* resources);
 
  private:
   SlotWithId getPreviousSlot(VariantSlot*, const ResourceManager*) const;

+ 31 - 37
src/ArduinoJson/Collection/CollectionImpl.hpp

@@ -17,28 +17,6 @@ inline CollectionIterator::CollectionIterator(VariantSlot* slot, SlotId slotId)
   nextId_ = slot_ ? slot_->next() : NULL_SLOT;
 }
 
-inline const char* CollectionIterator::key() const {
-  ARDUINOJSON_ASSERT(slot_ != nullptr);
-  return slot_->key();
-}
-
-inline void CollectionIterator::setKey(const char* s) {
-  ARDUINOJSON_ASSERT(slot_ != nullptr);
-  ARDUINOJSON_ASSERT(s != nullptr);
-  return slot_->setKey(s);
-}
-
-inline void CollectionIterator::setKey(StringNode* s) {
-  ARDUINOJSON_ASSERT(slot_ != nullptr);
-  ARDUINOJSON_ASSERT(s != nullptr);
-  return slot_->setKey(s);
-}
-
-inline bool CollectionIterator::ownsKey() const {
-  ARDUINOJSON_ASSERT(slot_ != nullptr);
-  return slot_->ownsKey();
-}
-
 inline void CollectionIterator::next(const ResourceManager* resources) {
   ARDUINOJSON_ASSERT(currentId_ != NULL_SLOT);
   slot_ = resources->getSlot(nextId_);
@@ -47,11 +25,8 @@ inline void CollectionIterator::next(const ResourceManager* resources) {
     nextId_ = slot_->next();
 }
 
-inline CollectionData::iterator CollectionData::addSlot(
-    ResourceManager* resources) {
-  auto slot = resources->allocSlot();
-  if (!slot)
-    return {};
+inline void CollectionData::appendOne(SlotWithId slot,
+                                      const ResourceManager* resources) {
   if (tail_ != NULL_SLOT) {
     auto tail = resources->getSlot(tail_);
     tail->setNext(slot.id());
@@ -60,18 +35,19 @@ inline CollectionData::iterator CollectionData::addSlot(
     head_ = slot.id();
     tail_ = slot.id();
   }
-  return iterator(slot, slot.id());
 }
 
-inline void CollectionData::addSlot(SlotWithId slot,
-                                    ResourceManager* resources) {
+inline void CollectionData::appendPair(SlotWithId key, SlotWithId value,
+                                       const ResourceManager* resources) {
+  key->setNext(value.id());
+
   if (tail_ != NULL_SLOT) {
     auto tail = resources->getSlot(tail_);
-    tail->setNext(slot.id());
-    tail_ = slot.id();
+    tail->setNext(key.id());
+    tail_ = value.id();
   } else {
-    head_ = slot.id();
-    tail_ = slot.id();
+    head_ = key.id();
+    tail_ = value.id();
   }
 }
 
@@ -95,14 +71,14 @@ inline SlotWithId CollectionData::getPreviousSlot(
   while (currentId != NULL_SLOT) {
     auto currentSlot = resources->getSlot(currentId);
     if (currentSlot == target)
-      return prev;
+      break;
     prev = SlotWithId(currentSlot, currentId);
     currentId = currentSlot->next();
   }
-  return SlotWithId();
+  return prev;
 }
 
-inline void CollectionData::remove(iterator it, ResourceManager* resources) {
+inline void CollectionData::removeOne(iterator it, ResourceManager* resources) {
   if (it.done())
     return;
   auto curr = it.slot_;
@@ -117,6 +93,24 @@ inline void CollectionData::remove(iterator it, ResourceManager* resources) {
   resources->freeSlot({it.slot_, it.currentId_});
 }
 
+inline void CollectionData::removePair(ObjectData::iterator it,
+                                       ResourceManager* resources) {
+  if (it.done())
+    return;
+
+  auto keySlot = it.slot_;
+
+  auto valueId = it.nextId_;
+  auto valueSlot = resources->getSlot(valueId);
+
+  // remove value slot
+  keySlot->setNext(valueSlot->next());
+  resources->freeSlot({valueSlot, valueId});
+
+  // remove key slot
+  removeOne(it, resources);
+}
+
 inline size_t CollectionData::nesting(const ResourceManager* resources) const {
   size_t maxChildNesting = 0;
   for (auto it = createIterator(resources); !it.done(); it.next(resources)) {

+ 5 - 4
src/ArduinoJson/Json/JsonSerializer.hpp

@@ -44,17 +44,18 @@ class JsonSerializer : public VariantDataVisitor<size_t> {
 
     auto slotId = object.head();
 
+    bool isKey = true;
+
     while (slotId != NULL_SLOT) {
       auto slot = resources_->getSlot(slotId);
-
-      formatter_.writeString(slot->key());
-      write(':');
       slot->data()->accept(*this);
 
       slotId = slot->next();
 
       if (slotId != NULL_SLOT)
-        write(',');
+        write(isKey ? ':' : ',');
+
+      isKey = !isKey;
     }
 
     write('}');

+ 8 - 5
src/ArduinoJson/Json/PrettyJsonSerializer.hpp

@@ -45,14 +45,17 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
     if (!it.done()) {
       base::write("{\r\n");
       nesting_++;
+      bool isKey = true;
       while (!it.done()) {
-        indent();
-        base::visit(it.key());
-        base::write(": ");
+        if (isKey)
+          indent();
         it->accept(*this);
-
         it.next(base::resources_);
-        base::write(it.done() ? "\r\n" : ",\r\n");
+        if (isKey)
+          base::write(": ");
+        else
+          base::write(it.done() ? "\r\n" : ",\r\n");
+        isKey = !isKey;
       }
       nesting_--;
       indent();

+ 0 - 2
src/ArduinoJson/Memory/ResourceManagerImpl.hpp

@@ -11,8 +11,6 @@
 ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
 
 inline void ResourceManager::freeSlot(SlotWithId slot) {
-  if (slot->ownsKey())
-    dereferenceString(slot->key());
   slot->data()->setNull(this);
   variantPools_.freeSlot(slot);
 }

+ 0 - 1
src/ArduinoJson/MsgPack/MsgPackSerializer.hpp

@@ -84,7 +84,6 @@ class MsgPackSerializer : public VariantDataVisitor<size_t> {
     auto slotId = object.head();
     while (slotId != NULL_SLOT) {
       auto slot = resources_->getSlot(slotId);
-      visit(slot->key());
       slot->data()->accept(*this);
       slotId = slot->next();
     }

+ 4 - 2
src/ArduinoJson/Object/JsonObjectIterator.hpp

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

+ 22 - 22
src/ArduinoJson/Object/JsonPair.hpp

@@ -16,27 +16,27 @@ class JsonPair {
  public:
   // INTERNAL USE ONLY
   JsonPair(detail::ObjectData::iterator iterator,
-           detail::ResourceManager* resources)
-      : iterator_(iterator), resources_(resources) {}
+           detail::ResourceManager* resources) {
+    if (!iterator.done()) {
+      key_ = iterator->asString();
+      iterator.next(resources);
+      value_ = JsonVariant(iterator.data(), resources);
+    }
+  }
 
   // Returns the key.
   JsonString key() const {
-    if (!iterator_.done())
-      return JsonString(iterator_.key(), iterator_.ownsKey()
-                                             ? JsonString::Copied
-                                             : JsonString::Linked);
-    else
-      return JsonString();
+    return key_;
   }
 
   // Returns the value.
   JsonVariant value() {
-    return JsonVariant(iterator_.data(), resources_);
+    return value_;
   }
 
  private:
-  detail::ObjectData::iterator iterator_;
-  detail::ResourceManager* resources_;
+  JsonString key_;
+  JsonVariant value_;
 };
 
 // A read-only key-value pair.
@@ -44,27 +44,27 @@ class JsonPair {
 class JsonPairConst {
  public:
   JsonPairConst(detail::ObjectData::iterator iterator,
-                const detail::ResourceManager* resources)
-      : iterator_(iterator), resources_(resources) {}
+                const detail::ResourceManager* resources) {
+    if (!iterator.done()) {
+      key_ = iterator->asString();
+      iterator.next(resources);
+      value_ = JsonVariantConst(iterator.data(), resources);
+    }
+  }
 
   // Returns the key.
   JsonString key() const {
-    if (!iterator_.done())
-      return JsonString(iterator_.key(), iterator_.ownsKey()
-                                             ? JsonString::Copied
-                                             : JsonString::Linked);
-    else
-      return JsonString();
+    return key_;
   }
 
   // Returns the value.
   JsonVariantConst value() const {
-    return JsonVariantConst(iterator_.data(), resources_);
+    return value_;
   }
 
  private:
-  detail::ObjectData::iterator iterator_;
-  const detail::ResourceManager* resources_;
+  JsonString key_;
+  JsonVariantConst value_;
 };
 
 ARDUINOJSON_END_PUBLIC_NAMESPACE

+ 23 - 28
src/ArduinoJson/Object/ObjectData.hpp

@@ -10,34 +10,8 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
 
 class ObjectData : public CollectionData {
  public:
-  VariantData* addMember(StringNode* key, ResourceManager* resources) {
-    ARDUINOJSON_ASSERT(key != nullptr);
-    auto it = addSlot(resources);
-    if (it.done())
-      return nullptr;
-
-    it.setKey(key);
-    return it.data();
-  }
-
-  template <typename TAdaptedString>
-  VariantData* addMember(TAdaptedString key, ResourceManager* resources) {
-    ARDUINOJSON_ASSERT(!key.isNull());
-    if (key.isLinked()) {
-      auto it = addSlot(resources);
-      if (!it.done())
-        it.setKey(key.data());
-      return it.data();
-    } else {
-      auto storedKey = resources->saveString(key);
-      if (!storedKey)
-        return nullptr;
-      auto it = addSlot(resources);
-      if (!it.done())
-        it.setKey(storedKey);
-      return it.data();
-    }
-  }
+  template <typename TAdaptedString>  // also works with StringNode*
+  VariantData* addMember(TAdaptedString key, ResourceManager* resources);
 
   template <typename TAdaptedString>
   VariantData* getOrAddMember(TAdaptedString key, ResourceManager* resources);
@@ -65,6 +39,27 @@ class ObjectData : public CollectionData {
     obj->removeMember(key, resources);
   }
 
+  void remove(iterator it, ResourceManager* resources) {
+    CollectionData::removePair(it, resources);
+  }
+
+  static void remove(ObjectData* obj, ObjectData::iterator it,
+                     ResourceManager* resources) {
+    if (!obj)
+      return;
+    obj->remove(it, resources);
+  }
+
+  size_t size(const ResourceManager* resources) const {
+    return CollectionData::size(resources) / 2;
+  }
+
+  static size_t size(const ObjectData* obj, const ResourceManager* resources) {
+    if (!obj)
+      return 0;
+    return obj->size(resources);
+  }
+
  private:
   template <typename TAdaptedString>
   iterator findKey(TAdaptedString key, const ResourceManager* resources) const;

+ 30 - 5
src/ArduinoJson/Object/ObjectImpl.hpp

@@ -12,15 +12,19 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
 template <typename TAdaptedString>
 inline VariantData* ObjectData::getMember(
     TAdaptedString key, const ResourceManager* resources) const {
-  return findKey(key, resources).data();
+  auto it = findKey(key, resources);
+  if (it.done())
+    return nullptr;
+  it.next(resources);
+  return it.data();
 }
 
 template <typename TAdaptedString>
 VariantData* ObjectData::getOrAddMember(TAdaptedString key,
                                         ResourceManager* resources) {
-  auto it = findKey(key, resources);
-  if (!it.done())
-    return it.data();
+  auto data = getMember(key, resources);
+  if (data)
+    return data;
   return addMember(key, resources);
 }
 
@@ -29,9 +33,11 @@ inline ObjectData::iterator ObjectData::findKey(
     TAdaptedString key, const ResourceManager* resources) const {
   if (key.isNull())
     return iterator();
+  bool isKey = true;
   for (auto it = createIterator(resources); !it.done(); it.next(resources)) {
-    if (stringEquals(key, adaptString(it.key())))
+    if (isKey && stringEquals(key, adaptString(it->asString())))
       return it;
+    isKey = !isKey;
   }
   return iterator();
 }
@@ -42,4 +48,23 @@ inline void ObjectData::removeMember(TAdaptedString key,
   remove(findKey(key, resources), resources);
 }
 
+template <typename TAdaptedString>
+inline VariantData* ObjectData::addMember(TAdaptedString key,
+                                          ResourceManager* resources) {
+  auto keySlot = resources->allocSlot();
+  if (!keySlot)
+    return nullptr;
+
+  auto valueSlot = resources->allocSlot();
+  if (!valueSlot)
+    return nullptr;
+
+  if (!keySlot->data()->setString(key, resources))
+    return nullptr;
+
+  CollectionData::appendPair(keySlot, valueSlot, resources);
+
+  return valueSlot->data();
+}
+
 ARDUINOJSON_END_PRIVATE_NAMESPACE

+ 0 - 4
src/ArduinoJson/Variant/VariantContent.hpp

@@ -14,8 +14,6 @@
 ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
 
 enum {
-  VALUE_MASK = 0x7F,
-
   OWNED_VALUE_BIT = 0x01,
   VALUE_IS_NULL = 0,
   VALUE_IS_RAW_STRING = 0x03,
@@ -34,8 +32,6 @@ enum {
   COLLECTION_MASK = 0x60,
   VALUE_IS_OBJECT = 0x20,
   VALUE_IS_ARRAY = 0x40,
-
-  OWNED_KEY_BIT = 0x80
 };
 
 union VariantContent {

+ 22 - 8
src/ArduinoJson/Variant/VariantData.hpp

@@ -410,20 +410,29 @@ class VariantData {
   }
 
   template <typename TAdaptedString>
-  void setString(TAdaptedString value, ResourceManager* resources) {
+  bool setString(TAdaptedString value, ResourceManager* resources) {
     setNull(resources);
 
     if (value.isNull())
-      return;
+      return false;
 
     if (value.isLinked()) {
       setLinkedString(value.data());
-      return;
+      return true;
     }
 
     auto dup = resources->saveString(value);
-    if (dup)
+    if (dup) {
       setOwnedString(dup);
+      return true;
+    }
+
+    return false;
+  }
+
+  bool setString(StringNode* s, ResourceManager*) {
+    setOwnedString(s);
+    return true;
   }
 
   template <typename TAdaptedString>
@@ -447,7 +456,13 @@ class VariantData {
   }
 
   size_t size(const ResourceManager* resources) const {
-    return isCollection() ? content_.asCollection.size(resources) : 0;
+    if (isObject())
+      return content_.asObject.size(resources);
+
+    if (isArray())
+      return content_.asArray.size(resources);
+
+    return 0;
   }
 
   static size_t size(const VariantData* var, const ResourceManager* resources) {
@@ -489,7 +504,7 @@ class VariantData {
   }
 
   uint8_t type() const {
-    return flags_ & VALUE_MASK;
+    return flags_;
   }
 
  private:
@@ -503,8 +518,7 @@ class VariantData {
   }
 
   void setType(uint8_t t) {
-    flags_ &= OWNED_KEY_BIT;
-    flags_ |= t;
+    flags_ = t;
   }
 };
 

+ 4 - 23
src/ArduinoJson/Variant/VariantSlot.hpp

@@ -20,7 +20,6 @@ class VariantSlot {
   VariantContent content_;
   uint8_t flags_;
   SlotId next_;
-  const char* key_;
 
  public:
   // Placement new
@@ -30,7 +29,9 @@ class VariantSlot {
 
   static void operator delete(void*, void*) noexcept {}
 
-  VariantSlot() : flags_(0), next_(NULL_SLOT), key_(0) {}
+  VariantSlot() : flags_(0), next_(NULL_SLOT) {
+    (void)flags_;  // HACK: suppress Clang warning "private field is not used"
+  }
 
   VariantData* data() {
     return reinterpret_cast<VariantData*>(&content_);
@@ -47,26 +48,6 @@ class VariantSlot {
   void setNext(SlotId slot) {
     next_ = slot;
   }
-
-  void setKey(const char* k) {
-    ARDUINOJSON_ASSERT(k);
-    flags_ &= VALUE_MASK;
-    key_ = k;
-  }
-
-  void setKey(StringNode* k) {
-    ARDUINOJSON_ASSERT(k);
-    flags_ |= OWNED_KEY_BIT;
-    key_ = k->data;
-  }
-
-  const char* key() const {
-    return key_;
-  }
-
-  bool ownsKey() const {
-    return (flags_ & OWNED_KEY_BIT) != 0;
-  }
 };
 
 inline VariantData* slotData(VariantSlot* slot) {
@@ -80,7 +61,7 @@ constexpr size_t sizeofArray(size_t n) {
 
 // Returns the size (in bytes) of an object with n members.
 constexpr size_t sizeofObject(size_t n) {
-  return n * sizeof(VariantSlot);
+  return 2 * n * sizeof(VariantSlot);
 }
 
 ARDUINOJSON_END_PRIVATE_NAMESPACE