Add CollectionIterator

This commit is contained in:
Benoit Blanchon
2023-06-26 17:41:46 +02:00
parent d921cd6d02
commit 688e21e75f
19 changed files with 269 additions and 221 deletions

View File

@ -51,7 +51,8 @@ TEST_CASE("JsonObject::remove()") {
} }
SECTION("Remove last") { SECTION("Remove last") {
it += 2; ++it;
++it;
obj.remove(it); obj.remove(it);
serializeJson(obj, result); serializeJson(obj, result);
REQUIRE("{\"a\":0,\"b\":1}" == result); REQUIRE("{\"a\":0,\"b\":1}" == result);

View File

@ -59,7 +59,7 @@ class ArrayData : public CollectionData {
} }
private: private:
VariantSlot* getSlot(size_t index) const; iterator at(size_t index) const;
}; };
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@ -9,6 +9,15 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
inline ArrayData::iterator ArrayData::at(size_t index) const {
auto it = begin();
while (it && index) {
++it;
--index;
}
return it;
}
inline VariantData* ArrayData::addElement(ResourceManager* resources) { inline VariantData* ArrayData::addElement(ResourceManager* resources) {
auto slot = resources->allocVariant(); auto slot = resources->allocVariant();
if (!slot) if (!slot)
@ -21,63 +30,57 @@ inline bool ArrayData::copyFrom(const ArrayData& src,
ResourceManager* resources) { ResourceManager* resources) {
clear(resources); clear(resources);
for (VariantSlot* s = src.head(); s; s = s->next()) { for (auto it = src.begin(); it; ++it) {
auto var = addElement(resources); auto var = addElement(resources);
if (!var) if (!var)
return false; return false;
if (!var->copyFrom(s->data(), resources)) if (!var->copyFrom(*it, resources))
return false; return false;
} }
return true; return true;
} }
inline bool ArrayData::equals(const ArrayData& other) const { inline bool ArrayData::equals(const ArrayData& other) const {
auto a = head(); auto a = begin();
auto b = other.head(); auto b = other.begin();
for (;;) { for (;;) {
if (!a && !b) // both ended if (!a && !b) // both ended
return true; return true;
if (!a || !b) // one ended if (!a || !b) // one ended
return false; return false;
if (compare(a->data(), b->data()) != COMPARE_RESULT_EQUAL) if (compare(a.data(), b.data()) != COMPARE_RESULT_EQUAL)
return false; return false;
a = a->next(); ++a;
b = b->next(); ++b;
} }
} }
inline VariantData* ArrayData::getOrAddElement(size_t index, inline VariantData* ArrayData::getOrAddElement(size_t index,
ResourceManager* resources) { ResourceManager* resources) {
VariantSlot* slot = head(); auto it = begin();
while (slot && index > 0) { while (it && index > 0) {
slot = slot->next(); ++it;
index--; index--;
} }
if (!slot) if (!it)
index++; index++;
VariantData* element = it.data();
while (index > 0) { while (index > 0) {
slot = resources->allocVariant(); element = addElement(resources);
if (!slot) if (!element)
return nullptr; return nullptr;
addSlot(slot);
index--; index--;
} }
return slot->data(); return element;
} }
inline VariantData* ArrayData::getElement(size_t index) const { inline VariantData* ArrayData::getElement(size_t index) const {
return slotData(getSlot(index)); return at(index).data();
}
inline VariantSlot* ArrayData::getSlot(size_t index) const {
if (!head())
return 0;
return head()->next(index);
} }
inline void ArrayData::removeElement(size_t index, ResourceManager* resources) { inline void ArrayData::removeElement(size_t index, ResourceManager* resources) {
removeSlot(getSlot(index), resources); remove(at(index), resources);
} }
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@ -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(resources_, data_->head()); return iterator(data_->begin(), resources_);
} }
// Returns an iterator following the last element of the array. // Returns an iterator following the last element of the array.
@ -92,7 +92,7 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
// ⚠️ Doesn't release the memory associated with the removed element. // ⚠️ Doesn't release the memory associated with the removed element.
// https://arduinojson.org/v6/api/jsonarray/remove/ // https://arduinojson.org/v6/api/jsonarray/remove/
FORCE_INLINE void remove(iterator it) const { FORCE_INLINE void remove(iterator it) const {
detail::ArrayData::removeSlot(data_, it.slot_, resources_); detail::ArrayData::remove(data_, it.iterator_, resources_);
} }
// Removes the element at the specified index. // Removes the element at the specified index.

View File

@ -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_->head()); return iterator(data_->begin());
} }
// 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.

View File

@ -30,76 +30,66 @@ class JsonArrayIterator {
friend class JsonArray; friend class JsonArray;
public: public:
JsonArrayIterator() : slot_(0) {} JsonArrayIterator() {}
explicit JsonArrayIterator(detail::ResourceManager* resources, explicit JsonArrayIterator(detail::ArrayData::iterator iterator,
detail::VariantSlot* slot) detail::ResourceManager* resources)
: resources_(resources), slot_(slot) {} : iterator_(iterator), resources_(resources) {}
JsonVariant operator*() const { JsonVariant operator*() {
return JsonVariant(slot_->data(), resources_); return JsonVariant(iterator_.data(), resources_);
} }
Ptr<JsonVariant> operator->() { Ptr<JsonVariant> operator->() {
return operator*(); return operator*();
} }
bool operator==(const JsonArrayIterator& other) const { bool operator==(const JsonArrayIterator& other) const {
return slot_ == other.slot_; return iterator_ == other.iterator_;
} }
bool operator!=(const JsonArrayIterator& other) const { bool operator!=(const JsonArrayIterator& other) const {
return slot_ != other.slot_; return iterator_ != other.iterator_;
} }
JsonArrayIterator& operator++() { JsonArrayIterator& operator++() {
slot_ = slot_->next(); ++iterator_;
return *this;
}
JsonArrayIterator& operator+=(size_t distance) {
slot_ = slot_->next(distance);
return *this; return *this;
} }
private: private:
detail::ArrayData::iterator iterator_;
detail::ResourceManager* resources_; detail::ResourceManager* resources_;
detail::VariantSlot* slot_;
}; };
class JsonArrayConstIterator { class JsonArrayConstIterator {
friend class JsonArray; friend class JsonArray;
public: public:
JsonArrayConstIterator() : slot_(0) {} JsonArrayConstIterator() {}
explicit JsonArrayConstIterator(const detail::VariantSlot* slot) explicit JsonArrayConstIterator(detail::ArrayData::iterator iterator)
: slot_(slot) {} : iterator_(iterator) {}
JsonVariantConst operator*() const { JsonVariantConst operator*() const {
return JsonVariantConst(slot_->data()); return JsonVariantConst(iterator_.data());
} }
Ptr<JsonVariantConst> operator->() { Ptr<JsonVariantConst> operator->() {
return operator*(); return operator*();
} }
bool operator==(const JsonArrayConstIterator& other) const { bool operator==(const JsonArrayConstIterator& other) const {
return slot_ == other.slot_; return iterator_ == other.iterator_;
} }
bool operator!=(const JsonArrayConstIterator& other) const { bool operator!=(const JsonArrayConstIterator& other) const {
return slot_ != other.slot_; return iterator_ != other.iterator_;
} }
JsonArrayConstIterator& operator++() { JsonArrayConstIterator& operator++() {
slot_ = slot_->next(); ++iterator_;
return *this;
}
JsonArrayConstIterator& operator+=(size_t distance) {
slot_ = slot_->next(distance);
return *this; return *this;
} }
private: private:
const detail::VariantSlot* slot_; detail::ArrayData::iterator iterator_;
}; };
ARDUINOJSON_END_PUBLIC_NAMESPACE ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@ -14,6 +14,58 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
class VariantData; class VariantData;
class VariantSlot; class VariantSlot;
class CollectionIterator {
friend class CollectionData;
public:
CollectionIterator() : slot_(nullptr) {}
CollectionIterator& operator++();
operator bool() const {
return slot_ != nullptr;
}
bool operator==(const CollectionIterator& other) const {
return slot_ == other.slot_;
}
bool operator!=(const CollectionIterator& other) const {
return slot_ != other.slot_;
}
VariantData* operator->() {
ARDUINOJSON_ASSERT(slot_ != nullptr);
return data();
}
VariantData& operator*() {
ARDUINOJSON_ASSERT(slot_ != nullptr);
return *data();
}
const VariantData& operator*() const {
ARDUINOJSON_ASSERT(slot_ != nullptr);
return *data();
}
const char* key() const;
bool ownsKey() const;
VariantData* data() {
return reinterpret_cast<VariantData*>(slot_);
}
const VariantData* data() const {
return reinterpret_cast<const VariantData*>(slot_);
}
private:
CollectionIterator(VariantSlot* slot) : slot_(slot) {}
VariantSlot* slot_;
};
class CollectionData { class CollectionData {
VariantSlot* head_ = 0; VariantSlot* head_ = 0;
VariantSlot* tail_ = 0; VariantSlot* tail_ = 0;
@ -26,8 +78,19 @@ class CollectionData {
static void operator delete(void*, void*) noexcept {} static void operator delete(void*, void*) noexcept {}
using iterator = CollectionIterator;
iterator begin() const {
return iterator(head_);
}
iterator end() const {
return iterator(nullptr);
}
size_t memoryUsage() const; size_t memoryUsage() const;
size_t size() const; size_t size() const;
size_t nesting() const;
void clear(ResourceManager* resources); void clear(ResourceManager* resources);
@ -37,21 +100,16 @@ class CollectionData {
collection->clear(resources); collection->clear(resources);
} }
void removeSlot(VariantSlot* slot, ResourceManager* resources);
static void removeSlot(CollectionData* collection, VariantSlot* slot,
ResourceManager* resources) {
if (!collection)
return;
collection->removeSlot(slot, resources);
}
VariantSlot* head() const {
return head_;
}
void movePointers(ptrdiff_t variantDistance); void movePointers(ptrdiff_t variantDistance);
void remove(iterator it, ResourceManager* resources);
static void remove(CollectionData* collection, iterator it,
ResourceManager* resources) {
if (collection)
return collection->remove(it, resources);
}
protected: protected:
void addSlot(VariantSlot*); void addSlot(VariantSlot*);

View File

@ -11,6 +11,22 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
inline const char* CollectionIterator::key() const {
ARDUINOJSON_ASSERT(slot_ != nullptr);
return slot_->key();
}
inline bool CollectionIterator::ownsKey() const {
ARDUINOJSON_ASSERT(slot_ != nullptr);
return slot_->ownsKey();
}
inline CollectionIterator& CollectionIterator::operator++() {
ARDUINOJSON_ASSERT(slot_ != nullptr);
slot_ = slot_->next();
return *this;
}
inline void CollectionData::addSlot(VariantSlot* slot) { inline void CollectionData::addSlot(VariantSlot* slot) {
ARDUINOJSON_ASSERT(slot != nullptr); ARDUINOJSON_ASSERT(slot != nullptr);
@ -41,19 +57,19 @@ inline VariantSlot* CollectionData::getPreviousSlot(VariantSlot* target) const {
return 0; return 0;
} }
inline void CollectionData::removeSlot(VariantSlot* slot, inline void CollectionData::remove(iterator it, ResourceManager* resources) {
ResourceManager* resources) { if (!it)
if (!slot)
return; return;
VariantSlot* prev = getPreviousSlot(slot); auto curr = it.slot_;
VariantSlot* next = slot->next(); auto prev = getPreviousSlot(curr);
auto next = curr->next();
if (prev) if (prev)
prev->setNext(next); prev->setNext(next);
else else
head_ = next; head_ = next;
if (!next) if (!next)
tail_ = prev; tail_ = prev;
slotRelease(slot, resources); slotRelease(curr, resources);
} }
inline size_t CollectionData::memoryUsage() const { inline size_t CollectionData::memoryUsage() const {
@ -66,6 +82,16 @@ inline size_t CollectionData::memoryUsage() const {
return total; return total;
} }
inline size_t CollectionData::nesting() const {
size_t maxChildNesting = 0;
for (const VariantSlot* s = head_; s; s = s->next()) {
size_t childNesting = s->data()->nesting();
if (childNesting > maxChildNesting)
maxChildNesting = childNesting;
}
return maxChildNesting + 1;
}
inline size_t CollectionData::size() const { inline size_t CollectionData::size() const {
return slotSize(head_); return slotSize(head_);
} }

View File

@ -21,13 +21,13 @@ class JsonSerializer : public Visitor<size_t> {
FORCE_INLINE size_t visitArray(const ArrayData& array) { FORCE_INLINE size_t visitArray(const ArrayData& array) {
write('['); write('[');
const VariantSlot* slot = array.head(); auto it = array.begin();
while (slot != 0) { while (it) {
slot->data()->accept(*this); it->accept(*this);
slot = slot->next(); ++it;
if (slot == 0) if (!it)
break; break;
write(','); write(',');
@ -40,15 +40,15 @@ class JsonSerializer : public Visitor<size_t> {
size_t visitObject(const ObjectData& object) { size_t visitObject(const ObjectData& object) {
write('{'); write('{');
const VariantSlot* slot = object.head(); auto it = object.begin();
while (slot != 0) { while (it) {
formatter_.writeString(slot->key()); formatter_.writeString(it.key());
write(':'); write(':');
slot->data()->accept(*this); it->accept(*this);
slot = slot->next(); ++it;
if (slot == 0) if (!it)
break; break;
write(','); write(',');

View File

@ -19,16 +19,16 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
PrettyJsonSerializer(TWriter writer) : base(writer), nesting_(0) {} PrettyJsonSerializer(TWriter writer) : base(writer), nesting_(0) {}
size_t visitArray(const ArrayData& array) { size_t visitArray(const ArrayData& array) {
const VariantSlot* slot = array.head(); auto it = array.begin();
if (slot) { if (it) {
base::write("[\r\n"); base::write("[\r\n");
nesting_++; nesting_++;
while (slot != 0) { while (it) {
indent(); indent();
slot->data()->accept(*this); it->accept(*this);
slot = slot->next(); ++it;
base::write(slot ? ",\r\n" : "\r\n"); base::write(it ? ",\r\n" : "\r\n");
} }
nesting_--; nesting_--;
indent(); indent();
@ -40,18 +40,18 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
} }
size_t visitObject(const ObjectData& object) { size_t visitObject(const ObjectData& object) {
const VariantSlot* slot = object.head(); auto it = object.begin();
if (slot) { if (it) {
base::write("{\r\n"); base::write("{\r\n");
nesting_++; nesting_++;
while (slot != 0) { while (it) {
indent(); indent();
base::visitString(slot->key()); base::visitString(it.key());
base::write(": "); base::write(": ");
slot->data()->accept(*this); it->accept(*this);
slot = slot->next(); ++it;
base::write(slot ? ",\r\n" : "\r\n"); base::write(it ? ",\r\n" : "\r\n");
} }
nesting_--; nesting_--;
indent(); indent();

View File

@ -55,8 +55,8 @@ class MsgPackSerializer : public Visitor<size_t> {
writeByte(0xDD); writeByte(0xDD);
writeInteger(uint32_t(n)); writeInteger(uint32_t(n));
} }
for (const VariantSlot* slot = array.head(); slot; slot = slot->next()) { for (auto it = array.begin(); it; ++it) {
slot->data()->accept(*this); it->accept(*this);
} }
return bytesWritten(); return bytesWritten();
} }
@ -72,9 +72,9 @@ class MsgPackSerializer : public Visitor<size_t> {
writeByte(0xDF); writeByte(0xDF);
writeInteger(uint32_t(n)); writeInteger(uint32_t(n));
} }
for (const VariantSlot* slot = object.head(); slot; slot = slot->next()) { for (auto it = object.begin(); it; ++it) {
visitString(slot->key()); visitString(it.key());
slot->data()->accept(*this); it->accept(*this);
} }
return bytesWritten(); return bytesWritten();
} }

View File

@ -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(resources_, data_->head()); return iterator(data_->begin(), 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.
@ -127,7 +127,7 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
// ⚠️ Doesn't release the memory associated with the removed member. // ⚠️ Doesn't release the memory associated with the removed member.
// https://arduinojson.org/v6/api/jsonobject/remove/ // https://arduinojson.org/v6/api/jsonobject/remove/
FORCE_INLINE void remove(iterator it) const { FORCE_INLINE void remove(iterator it) const {
detail::ObjectData::removeSlot(data_, it.slot_, resources_); detail::ObjectData::remove(data_, it.iterator_, resources_);
} }
// Removes the member with the specified key. // Removes the member with the specified key.

View File

@ -63,7 +63,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_->head()); return iterator(data_->begin());
} }
// Returns an iterator following the last key-value pair of the object. // Returns an iterator following the last key-value pair of the object.

View File

@ -13,78 +13,68 @@ class JsonObjectIterator {
friend class JsonObject; friend class JsonObject;
public: public:
JsonObjectIterator() : slot_(0) {} JsonObjectIterator() {}
explicit JsonObjectIterator(detail::ResourceManager* resources, explicit JsonObjectIterator(detail::ObjectData::iterator iterator,
detail::VariantSlot* slot) detail::ResourceManager* resources)
: resources_(resources), slot_(slot) {} : iterator_(iterator), resources_(resources) {}
JsonPair operator*() const { JsonPair operator*() const {
return JsonPair(resources_, slot_); return JsonPair(iterator_, resources_);
} }
Ptr<JsonPair> operator->() { Ptr<JsonPair> operator->() {
return operator*(); return operator*();
} }
bool operator==(const JsonObjectIterator& other) const { bool operator==(const JsonObjectIterator& other) const {
return slot_ == other.slot_; return iterator_ == other.iterator_;
} }
bool operator!=(const JsonObjectIterator& other) const { bool operator!=(const JsonObjectIterator& other) const {
return slot_ != other.slot_; return iterator_ != other.iterator_;
} }
JsonObjectIterator& operator++() { JsonObjectIterator& operator++() {
slot_ = slot_->next(); ++iterator_;
return *this;
}
JsonObjectIterator& operator+=(size_t distance) {
slot_ = slot_->next(distance);
return *this; return *this;
} }
private: private:
detail::ObjectData::iterator iterator_;
detail::ResourceManager* resources_; detail::ResourceManager* resources_;
detail::VariantSlot* slot_;
}; };
class JsonObjectConstIterator { class JsonObjectConstIterator {
friend class JsonObject; friend class JsonObject;
public: public:
JsonObjectConstIterator() : slot_(0) {} JsonObjectConstIterator() {}
explicit JsonObjectConstIterator(const detail::VariantSlot* slot) explicit JsonObjectConstIterator(detail::ObjectData::iterator iterator)
: slot_(slot) {} : iterator_(iterator) {}
JsonPairConst operator*() const { JsonPairConst operator*() const {
return JsonPairConst(slot_); return JsonPairConst(iterator_);
} }
Ptr<JsonPairConst> operator->() { Ptr<JsonPairConst> operator->() {
return operator*(); return operator*();
} }
bool operator==(const JsonObjectConstIterator& other) const { bool operator==(const JsonObjectConstIterator& other) const {
return slot_ == other.slot_; return iterator_ == other.iterator_;
} }
bool operator!=(const JsonObjectConstIterator& other) const { bool operator!=(const JsonObjectConstIterator& other) const {
return slot_ != other.slot_; return iterator_ != other.iterator_;
} }
JsonObjectConstIterator& operator++() { JsonObjectConstIterator& operator++() {
slot_ = slot_->next(); ++iterator_;
return *this;
}
JsonObjectConstIterator& operator+=(size_t distance) {
slot_ = slot_->next(distance);
return *this; return *this;
} }
private: private:
const detail::VariantSlot* slot_; detail::ObjectData::iterator iterator_;
}; };
ARDUINOJSON_END_PUBLIC_NAMESPACE ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@ -15,54 +15,53 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
class JsonPair { class JsonPair {
public: public:
// INTERNAL USE ONLY // INTERNAL USE ONLY
JsonPair(detail::ResourceManager* resources, detail::VariantSlot* slot) { JsonPair(detail::ObjectData::iterator iterator,
if (slot) { detail::ResourceManager* resources)
key_ = JsonString(slot->key(), slot->ownsKey() ? JsonString::Copied : iterator_(iterator), resources_(resources) {}
: JsonString::Linked);
value_ = JsonVariant(slot->data(), resources);
}
}
// Returns the key. // Returns the key.
JsonString key() const { JsonString key() const {
return key_; if (iterator_)
return JsonString(iterator_.key(), iterator_.ownsKey()
? JsonString::Copied
: JsonString::Linked);
else
return JsonString();
} }
// Returns the value. // Returns the value.
JsonVariant value() const { JsonVariant value() {
return value_; return JsonVariant(iterator_.data(), resources_);
} }
private: private:
JsonString key_; detail::ObjectData::iterator iterator_;
JsonVariant value_; detail::ResourceManager* resources_;
}; };
// A read-only key-value pair. // A read-only key-value pair.
// https://arduinojson.org/v6/api/jsonobjectconst/begin_end/ // https://arduinojson.org/v6/api/jsonobjectconst/begin_end/
class JsonPairConst { class JsonPairConst {
public: public:
JsonPairConst(const detail::VariantSlot* slot) { JsonPairConst(detail::ObjectData::iterator iterator) : iterator_(iterator) {}
if (slot) {
key_ = JsonString(slot->key(), slot->ownsKey() ? JsonString::Copied
: JsonString::Linked);
value_ = JsonVariantConst(slot->data());
}
}
// Returns the key. // Returns the key.
JsonString key() const { JsonString key() const {
return key_; if (iterator_)
return JsonString(iterator_.key(), iterator_.ownsKey()
? JsonString::Copied
: JsonString::Linked);
else
return JsonString();
} }
// Returns the value. // Returns the value.
JsonVariantConst value() const { JsonVariantConst value() const {
return value_; return JsonVariantConst(iterator_.data());
} }
private: private:
JsonString key_; detail::ObjectData::iterator iterator_;
JsonVariantConst value_;
}; };
ARDUINOJSON_END_PUBLIC_NAMESPACE ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@ -63,7 +63,7 @@ class ObjectData : public CollectionData {
private: private:
template <typename TAdaptedString> template <typename TAdaptedString>
VariantSlot* getSlot(TAdaptedString key) const; iterator findKey(TAdaptedString key) const;
}; };
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@ -44,14 +44,14 @@ inline bool ObjectData::copyFrom(const ObjectData& src,
ResourceManager* resources) { ResourceManager* resources) {
clear(resources); clear(resources);
for (VariantSlot* s = src.head(); s; s = s->next()) { for (auto it = src.begin(); it; ++it) {
ARDUINOJSON_ASSERT(s->key() != 0); ARDUINOJSON_ASSERT(it.key() != 0);
JsonString key(s->key(), JsonString key(it.key(),
s->ownsKey() ? JsonString::Copied : JsonString::Linked); it.ownsKey() ? JsonString::Copied : JsonString::Linked);
auto var = addMember(adaptString(key), resources); auto var = addMember(adaptString(key), resources);
if (!var) if (!var)
return false; return false;
if (!var->copyFrom(s->data(), resources)) if (!var->copyFrom(*it, resources))
return false; return false;
} }
return true; return true;
@ -59,11 +59,12 @@ inline bool ObjectData::copyFrom(const ObjectData& src,
inline bool ObjectData::equals(const ObjectData& other) const { inline bool ObjectData::equals(const ObjectData& other) const {
size_t count = 0; size_t count = 0;
for (auto a = head(); a; a = a->next()) { for (auto it = begin(); it; ++it) {
auto b = other.getMember(adaptString(a->key())); auto a = it.data();
auto b = other.getMember(adaptString(it.key()));
if (!b) if (!b)
return false; return false;
if (compare(a->data(), b) != COMPARE_RESULT_EQUAL) if (compare(a, b) != COMPARE_RESULT_EQUAL)
return false; return false;
count++; count++;
} }
@ -72,35 +73,33 @@ inline bool ObjectData::equals(const ObjectData& other) const {
template <typename TAdaptedString> template <typename TAdaptedString>
inline VariantData* ObjectData::getMember(TAdaptedString key) const { inline VariantData* ObjectData::getMember(TAdaptedString key) const {
return slotData(getSlot(key)); return findKey(key).data();
} }
template <typename TAdaptedString> template <typename TAdaptedString>
VariantData* ObjectData::getOrAddMember(TAdaptedString key, VariantData* ObjectData::getOrAddMember(TAdaptedString key,
ResourceManager* resources) { ResourceManager* resources) {
auto slot = getSlot(key); auto it = findKey(key);
if (slot) if (it)
return slot->data(); return it.data();
return addMember(key, resources); return addMember(key, resources);
} }
template <typename TAdaptedString> template <typename TAdaptedString>
inline VariantSlot* ObjectData::getSlot(TAdaptedString key) const { inline ObjectData::iterator ObjectData::findKey(TAdaptedString key) const {
if (key.isNull()) if (key.isNull())
return 0; return end();
VariantSlot* slot = head(); for (auto it = begin(); it; ++it) {
while (slot) { if (stringEquals(key, adaptString(it.key())))
if (stringEquals(key, adaptString(slot->key()))) return it;
break;
slot = slot->next();
} }
return slot; return end();
} }
template <typename TAdaptedString> template <typename TAdaptedString>
inline void ObjectData::removeMember(TAdaptedString key, inline void ObjectData::removeMember(TAdaptedString key,
ResourceManager* resources) { ResourceManager* resources) {
removeSlot(getSlot(key), resources); remove(findKey(key), resources);
} }
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@ -107,10 +107,14 @@ class VariantData {
return const_cast<VariantData*>(this)->asArray(); return const_cast<VariantData*>(this)->asArray();
} }
const CollectionData* asCollection() const { CollectionData* asCollection() {
return isCollection() ? &content_.asCollection : 0; return isCollection() ? &content_.asCollection : 0;
} }
const CollectionData* asCollection() const {
return const_cast<VariantData*>(this)->asCollection();
}
template <typename T> template <typename T>
T asFloat() const { T asFloat() const {
static_assert(is_floating_point<T>::value, "T must be a floating point"); static_assert(is_floating_point<T>::value, "T must be a floating point");
@ -182,19 +186,15 @@ class VariantData {
} }
} }
bool copyFrom(const VariantData* src, ResourceManager* resources) { bool copyFrom(const VariantData& src, ResourceManager* resources) {
release(resources); release(resources);
if (!src) { switch (src.type()) {
setNull();
return true;
}
switch (src->type()) {
case VALUE_IS_ARRAY: case VALUE_IS_ARRAY:
return toArray().copyFrom(*src->asArray(), resources); return toArray().copyFrom(src.content_.asArray, resources);
case VALUE_IS_OBJECT: case VALUE_IS_OBJECT:
return toObject().copyFrom(*src->asObject(), resources); return toObject().copyFrom(src.content_.asObject, resources);
case VALUE_IS_OWNED_STRING: { case VALUE_IS_OWNED_STRING: {
auto str = adaptString(src->asString()); auto str = adaptString(src.asString());
auto dup = resources->saveString(str); auto dup = resources->saveString(str);
if (!dup) if (!dup)
return false; return false;
@ -202,7 +202,7 @@ class VariantData {
return true; return true;
} }
case VALUE_IS_RAW_STRING: { case VALUE_IS_RAW_STRING: {
auto str = adaptString(src->asRawString()); auto str = adaptString(src.asRawString());
auto dup = resources->saveString(str); auto dup = resources->saveString(str);
if (!dup) if (!dup)
return false; return false;
@ -210,8 +210,8 @@ class VariantData {
return true; return true;
} }
default: default:
content_ = src->content_; content_ = src.content_;
flags_ = src->flags_; flags_ = src.flags_;
return true; return true;
} }
} }
@ -220,7 +220,11 @@ class VariantData {
ResourceManager* resources) { ResourceManager* resources) {
if (!dst) if (!dst)
return false; return false;
return dst->copyFrom(src, resources); if (!src) {
dst->setNull();
return true;
}
return dst->copyFrom(*src, resources);
} }
VariantData* getElement(size_t index) const { VariantData* getElement(size_t index) const {
@ -334,16 +338,10 @@ class VariantData {
size_t nesting() const { size_t nesting() const {
auto collection = asCollection(); auto collection = asCollection();
if (!collection) if (collection)
return collection->nesting();
else
return 0; return 0;
size_t maxChildNesting = 0;
for (const VariantSlot* s = collection->head(); s; s = s->next()) {
size_t childNesting = s->data()->nesting();
if (childNesting > maxChildNesting)
maxChildNesting = childNesting;
}
return maxChildNesting + 1;
} }
static size_t nesting(const VariantData* var) { static size_t nesting(const VariantData* var) {
@ -550,11 +548,9 @@ class VariantData {
if (flags_ & OWNED_VALUE_BIT) if (flags_ & OWNED_VALUE_BIT)
resources->dereferenceString(content_.asOwnedString->data); resources->dereferenceString(content_.asOwnedString->data);
auto c = asCollection(); auto collection = asCollection();
if (c) { if (collection)
for (auto slot = c->head(); slot; slot = slot->next()) collection->clear(resources);
slotRelease(slot, resources);
}
} }
void setType(uint8_t t) { void setType(uint8_t t) {

View File

@ -51,20 +51,6 @@ class VariantSlot {
return const_cast<VariantSlot*>(this)->next(); return const_cast<VariantSlot*>(this)->next();
} }
VariantSlot* next(size_t distance) {
VariantSlot* slot = this;
while (distance--) {
if (!slot->next_)
return 0;
slot += slot->next_;
}
return slot;
}
const VariantSlot* next(size_t distance) const {
return const_cast<VariantSlot*>(this)->next(distance);
}
void setNext(VariantSlot* slot) { void setNext(VariantSlot* slot) {
ARDUINOJSON_ASSERT(!slot || slot - this >= ARDUINOJSON_ASSERT(!slot || slot - this >=
numeric_limits<VariantSlotDiff>::lowest()); numeric_limits<VariantSlotDiff>::lowest());