diff --git a/src/ArduinoJson/Array/ArrayFunctions.hpp b/src/ArduinoJson/Array/ArrayFunctions.hpp index 266da3fe..19652b45 100644 --- a/src/ArduinoJson/Array/ArrayFunctions.hpp +++ b/src/ArduinoJson/Array/ArrayFunctions.hpp @@ -15,20 +15,17 @@ inline VariantData* arrayAdd(ArrayData* arr, MemoryPool* pool) { VariantSlot* slot = pool->allocVariant(); if (!slot) return 0; - slot->next = 0; - slot->value.type = JSON_NULL; - slot->value.keyIsOwned = false; + slot->init(); if (arr->tail) { slot->attachTo(arr->tail); arr->tail = slot; } else { - slot->prev = 0; arr->head = slot; arr->tail = slot; } - return &slot->value; + return slot->getData(); } inline VariantSlot* arrayGetSlot(const ArrayData* arr, size_t index) { @@ -38,20 +35,20 @@ inline VariantSlot* arrayGetSlot(const ArrayData* arr, size_t index) { inline VariantData* arrayGet(const ArrayData* arr, size_t index) { VariantSlot* slot = arrayGetSlot(arr, index); - return slot ? &slot->value : 0; + return slot ? slot->getData() : 0; } inline void arrayRemove(ArrayData* arr, VariantSlot* slot) { if (!arr || !slot) return; - if (slot->prev) - slot->getPrev()->setNext(slot->getNext()); + VariantSlot* prev = slot->getPrev(arr->head); + VariantSlot* next = slot->getNext(); + + if (prev) + prev->setNext(next); else - arr->head = slot->getNext(); - if (slot->next) - slot->getNext()->setPrev(slot->getPrev()); - else - arr->tail = slot->getPrev(); + arr->head = next; + if (!next) arr->tail = prev; } inline void arrayRemove(ArrayData* arr, size_t index) { @@ -70,7 +67,7 @@ inline bool arrayCopy(ArrayData* dst, const ArrayData* src, MemoryPool* pool) { if (!dst || !src) return false; arrayClear(dst); for (VariantSlot* s = src->head; s; s = s->getNext()) { - if (!variantCopy(arrayAdd(dst, pool), &s->value, pool)) return false; + if (!variantCopy(arrayAdd(dst, pool), s->getData(), pool)) return false; } return true; } @@ -85,7 +82,7 @@ inline bool arrayEquals(const ArrayData* a1, const ArrayData* a2) { for (;;) { if (s1 == s2) return true; if (!s1 || !s2) return false; - if (!variantEquals(&s1->value, &s2->value)) return false; + if (!variantEquals(s1->getData(), s2->getData())) return false; s1 = s1->getNext(); s2 = s2->getNext(); } diff --git a/src/ArduinoJson/Array/ArrayIterator.hpp b/src/ArduinoJson/Array/ArrayIterator.hpp index e91e25c2..6bc88bbf 100644 --- a/src/ArduinoJson/Array/ArrayIterator.hpp +++ b/src/ArduinoJson/Array/ArrayIterator.hpp @@ -33,10 +33,10 @@ class ArrayIterator { : _memoryPool(memoryPool), _slot(slot) {} VariantRef operator*() const { - return VariantRef(_memoryPool, &_slot->value); + return VariantRef(_memoryPool, _slot->getData()); } VariantPtr operator->() { - return VariantPtr(_memoryPool, &_slot->value); + return VariantPtr(_memoryPool, _slot->getData()); } bool operator==(const ArrayIterator &other) const { @@ -88,10 +88,10 @@ class ArrayConstRefIterator { explicit ArrayConstRefIterator(const VariantSlot *slot) : _slot(slot) {} VariantConstRef operator*() const { - return VariantConstRef(&_slot->value); + return VariantConstRef(_slot->getData()); } VariantConstPtr operator->() { - return VariantConstPtr(&_slot->value); + return VariantConstPtr(_slot->getData()); } bool operator==(const ArrayConstRefIterator &other) const { diff --git a/src/ArduinoJson/Object/Key.hpp b/src/ArduinoJson/Object/Key.hpp index 2e2a6924..13d52a2e 100644 --- a/src/ArduinoJson/Object/Key.hpp +++ b/src/ArduinoJson/Object/Key.hpp @@ -19,7 +19,7 @@ class Key { } bool isNull() const { - return _slot == 0 || _slot->key == 0; + return _slot == 0 || _slot->key() == 0; } friend bool operator==(Key lhs, const char* rhs) { diff --git a/src/ArduinoJson/Object/ObjectFunctions.hpp b/src/ArduinoJson/Object/ObjectFunctions.hpp index 8e69303c..a06be757 100644 --- a/src/ArduinoJson/Object/ObjectFunctions.hpp +++ b/src/ArduinoJson/Object/ObjectFunctions.hpp @@ -31,20 +31,18 @@ inline VariantData* objectAdd(ObjectData* obj, TKey key, MemoryPool* pool) { VariantSlot* slot = pool->allocVariant(); if (!slot) return 0; - slot->next = 0; - slot->value.type = JSON_NULL; + slot->init(); if (obj->tail) { slot->attachTo(obj->tail); obj->tail = slot; } else { - slot->prev = 0; obj->head = slot; obj->tail = slot; } if (!slotSetKey(slot, key, pool)) return 0; - return &slot->value; + return slot->getData(); } template @@ -56,7 +54,7 @@ inline VariantData* objectSet(ObjectData* obj, TKey key, MemoryPool* pool) { // search a matching key VariantSlot* slot = objectFindSlot(obj, key); - if (slot) return &slot->value; + if (slot) return slot->getData(); return objectAdd(obj, key, pool); } @@ -64,7 +62,7 @@ inline VariantData* objectSet(ObjectData* obj, TKey key, MemoryPool* pool) { template inline VariantData* objectGet(const ObjectData* obj, TKey key) { VariantSlot* slot = objectFindSlot(obj, key); - return slot ? &slot->value : 0; + return slot ? slot->getData() : 0; } inline void objectClear(ObjectData* obj) { @@ -76,16 +74,13 @@ inline void objectClear(ObjectData* obj) { inline void objectRemove(ObjectData* obj, VariantSlot* slot) { if (!obj) return; if (!slot) return; - VariantSlot* prev = slot->getPrev(); + VariantSlot* prev = slot->getPrev(obj->head); VariantSlot* next = slot->getNext(); if (prev) prev->setNext(next); else obj->head = next; - if (next) - next->setPrev(prev); - else - obj->tail = prev; + if (!next) obj->tail = prev; } inline size_t objectSize(const ObjectData* obj) { @@ -101,11 +96,11 @@ inline bool objectCopy(ObjectData* dst, const ObjectData* src, objectClear(dst); for (VariantSlot* s = src->head; s; s = s->getNext()) { VariantData* var; - if (s->value.keyIsOwned) - var = objectAdd(dst, ZeroTerminatedRamString(s->key), pool); + if (s->ownsKey()) + var = objectAdd(dst, ZeroTerminatedRamString(s->key()), pool); else - var = objectAdd(dst, ZeroTerminatedRamStringConst(s->key), pool); - if (!variantCopy(var, &s->value, pool)) return false; + var = objectAdd(dst, ZeroTerminatedRamStringConst(s->key()), pool); + if (!variantCopy(var, s->getData(), pool)) return false; } return true; } @@ -115,7 +110,7 @@ inline bool objectEquals(const ObjectData* o1, const ObjectData* o2) { if (!o1 || !o2) return false; for (VariantSlot* s = o1->head; s; s = s->getNext()) { - VariantData* v1 = &s->value; + VariantData* v1 = s->getData(); VariantData* v2 = objectGet(o2, makeString(slotGetKey(s))); if (!variantEquals(v1, v2)) return false; } diff --git a/src/ArduinoJson/Object/Pair.hpp b/src/ArduinoJson/Object/Pair.hpp index 265522df..4c48ee0f 100644 --- a/src/ArduinoJson/Object/Pair.hpp +++ b/src/ArduinoJson/Object/Pair.hpp @@ -13,7 +13,7 @@ class Pair { public: Pair(MemoryPool* memoryPool, VariantSlot* slot) : _key(slot) { if (slot) { - _value = VariantRef(memoryPool, &slot->value); + _value = VariantRef(memoryPool, slot->getData()); } } @@ -34,7 +34,7 @@ class PairConst { public: PairConst(const VariantSlot* slot) : _key(slot) { if (slot) { - _value = VariantConstRef(&slot->value); + _value = VariantConstRef(slot->getData()); } } diff --git a/src/ArduinoJson/Variant/SlotFunctions.hpp b/src/ArduinoJson/Variant/SlotFunctions.hpp index fc0499b8..e083943d 100644 --- a/src/ArduinoJson/Variant/SlotFunctions.hpp +++ b/src/ArduinoJson/Variant/SlotFunctions.hpp @@ -15,26 +15,23 @@ template inline bool slotSetKey(VariantSlot* var, TKey key, MemoryPool* pool) { char* dup = key.save(pool); if (!dup) return false; - var->key = dup; - var->value.keyIsOwned = true; + var->setKey(dup, true); return true; } inline bool slotSetKey(VariantSlot* var, ZeroTerminatedRamStringConst key, MemoryPool*) { - var->key = key.c_str(); - var->value.keyIsOwned = false; + var->setKey(key.c_str(), false); return true; } inline bool slotSetKey(VariantSlot* var, StringInMemoryPool key, MemoryPool*) { - var->key = key.c_str(); - var->value.keyIsOwned = true; + var->setKey(key.c_str(), true); return true; } inline const char* slotGetKey(const VariantSlot* var) { - return var->key; + return var->key(); } inline size_t slotSize(const VariantSlot* var) { diff --git a/src/ArduinoJson/Variant/VariantData.hpp b/src/ArduinoJson/Variant/VariantData.hpp index de7016e2..88e14b34 100644 --- a/src/ArduinoJson/Variant/VariantData.hpp +++ b/src/ArduinoJson/Variant/VariantData.hpp @@ -11,6 +11,8 @@ namespace ARDUINOJSON_NAMESPACE { +class VariantSlot; + enum VariantType { JSON_NULL, JSON_LINKED_RAW, @@ -26,13 +28,13 @@ enum VariantType { }; struct ObjectData { - struct VariantSlot *head; - struct VariantSlot *tail; + VariantSlot *head; + VariantSlot *tail; }; struct ArrayData { - struct VariantSlot *head; - struct VariantSlot *tail; + VariantSlot *head; + VariantSlot *tail; }; struct RawData { @@ -56,9 +58,9 @@ union VariantContent { // this struct must be a POD type to prevent error calling offsetof on clang struct VariantData { + VariantContent content; bool keyIsOwned : 1; VariantType type : 7; - VariantContent content; }; inline VariantData *getVariantData(ArrayData *arr) { diff --git a/src/ArduinoJson/Variant/VariantSlot.hpp b/src/ArduinoJson/Variant/VariantSlot.hpp index 1512764a..5ffcfd78 100644 --- a/src/ArduinoJson/Variant/VariantSlot.hpp +++ b/src/ArduinoJson/Variant/VariantSlot.hpp @@ -11,16 +11,33 @@ namespace ARDUINOJSON_NAMESPACE { typedef conditional::type VariantSlotDiff; -struct VariantSlot { - VariantData value; - VariantSlotDiff next; - VariantSlotDiff prev; - const char* key; +class VariantSlot { + // CAUTION: same layout as VariantData + // we cannot use composition because it adds padding + // (+20% on ESP8266 for example) + VariantContent _content; + bool _keyIsOwned : 1; + VariantType _type : 7; + VariantSlotDiff _next; + const char* _key; - // Must be a POD! so no constructor, nor destructor, nor virtual + public: + // Must be a POD! + // - no constructor + // - no destructor + // - no virtual + // - no inheritance + + VariantData* getData() { + return reinterpret_cast(&_content); + } + + const VariantData* getData() const { + return reinterpret_cast(&_content); + } VariantSlot* getNext() { - return next ? this + next : 0; + return _next ? this + _next : 0; } const VariantSlot* getNext() const { @@ -30,32 +47,50 @@ struct VariantSlot { VariantSlot* getNext(size_t distance) { VariantSlot* slot = this; while (distance--) { - if (!slot->next) return 0; - slot += slot->next; + if (!slot->_next) return 0; + slot += slot->_next; } return slot; } + VariantSlot* getPrev(VariantSlot* head) { + while (head) { + VariantSlot* nxt = head->getNext(); + if (nxt == this) return head; + head = nxt; + } + return head; + } + const VariantSlot* getNext(size_t distance) const { return const_cast(this)->getNext(distance); } - VariantSlot* getPrev() { - return prev ? this + prev : 0; - } - void setNext(VariantSlot* slot) { - this->next = VariantSlotDiff(slot ? slot - this : 0); - } - - void setPrev(VariantSlot* slot) { - this->prev = VariantSlotDiff(slot ? slot - this : 0); + _next = VariantSlotDiff(slot ? slot - this : 0); } void attachTo(VariantSlot* tail) { - VariantSlotDiff offset = VariantSlotDiff(tail - this); - this->prev = offset; - tail->next = VariantSlotDiff(-offset); + tail->_next = VariantSlotDiff(this - tail); + } + + void setKey(const char* k, bool owned) { + _keyIsOwned = owned; + _key = k; + } + + const char* key() const { + return _key; + } + + bool ownsKey() const { + return _keyIsOwned; + } + + void init() { + _next = 0; + _type = JSON_NULL; + _keyIsOwned = false; } };