mirror of
https://github.com/bblanchon/ArduinoJson.git
synced 2025-07-17 12:32:17 +02:00
Add CollectionIterator
This commit is contained in:
@ -51,7 +51,8 @@ TEST_CASE("JsonObject::remove()") {
|
||||
}
|
||||
|
||||
SECTION("Remove last") {
|
||||
it += 2;
|
||||
++it;
|
||||
++it;
|
||||
obj.remove(it);
|
||||
serializeJson(obj, result);
|
||||
REQUIRE("{\"a\":0,\"b\":1}" == result);
|
||||
|
@ -59,7 +59,7 @@ class ArrayData : public CollectionData {
|
||||
}
|
||||
|
||||
private:
|
||||
VariantSlot* getSlot(size_t index) const;
|
||||
iterator at(size_t index) const;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
@ -9,6 +9,15 @@
|
||||
|
||||
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) {
|
||||
auto slot = resources->allocVariant();
|
||||
if (!slot)
|
||||
@ -21,63 +30,57 @@ inline bool ArrayData::copyFrom(const ArrayData& src,
|
||||
ResourceManager* resources) {
|
||||
clear(resources);
|
||||
|
||||
for (VariantSlot* s = src.head(); s; s = s->next()) {
|
||||
for (auto it = src.begin(); it; ++it) {
|
||||
auto var = addElement(resources);
|
||||
if (!var)
|
||||
return false;
|
||||
if (!var->copyFrom(s->data(), resources))
|
||||
if (!var->copyFrom(*it, resources))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool ArrayData::equals(const ArrayData& other) const {
|
||||
auto a = head();
|
||||
auto b = other.head();
|
||||
auto a = begin();
|
||||
auto b = other.begin();
|
||||
|
||||
for (;;) {
|
||||
if (!a && !b) // both ended
|
||||
return true;
|
||||
if (!a || !b) // one ended
|
||||
return false;
|
||||
if (compare(a->data(), b->data()) != COMPARE_RESULT_EQUAL)
|
||||
if (compare(a.data(), b.data()) != COMPARE_RESULT_EQUAL)
|
||||
return false;
|
||||
a = a->next();
|
||||
b = b->next();
|
||||
++a;
|
||||
++b;
|
||||
}
|
||||
}
|
||||
|
||||
inline VariantData* ArrayData::getOrAddElement(size_t index,
|
||||
ResourceManager* resources) {
|
||||
VariantSlot* slot = head();
|
||||
while (slot && index > 0) {
|
||||
slot = slot->next();
|
||||
auto it = begin();
|
||||
while (it && index > 0) {
|
||||
++it;
|
||||
index--;
|
||||
}
|
||||
if (!slot)
|
||||
if (!it)
|
||||
index++;
|
||||
VariantData* element = it.data();
|
||||
while (index > 0) {
|
||||
slot = resources->allocVariant();
|
||||
if (!slot)
|
||||
element = addElement(resources);
|
||||
if (!element)
|
||||
return nullptr;
|
||||
addSlot(slot);
|
||||
index--;
|
||||
}
|
||||
return slot->data();
|
||||
return element;
|
||||
}
|
||||
|
||||
inline VariantData* ArrayData::getElement(size_t index) const {
|
||||
return slotData(getSlot(index));
|
||||
}
|
||||
|
||||
inline VariantSlot* ArrayData::getSlot(size_t index) const {
|
||||
if (!head())
|
||||
return 0;
|
||||
return head()->next(index);
|
||||
return at(index).data();
|
||||
}
|
||||
|
||||
inline void ArrayData::removeElement(size_t index, ResourceManager* resources) {
|
||||
removeSlot(getSlot(index), resources);
|
||||
remove(at(index), resources);
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
@ -68,7 +68,7 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
|
||||
FORCE_INLINE iterator begin() const {
|
||||
if (!data_)
|
||||
return iterator();
|
||||
return iterator(resources_, data_->head());
|
||||
return iterator(data_->begin(), resources_);
|
||||
}
|
||||
|
||||
// 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.
|
||||
// https://arduinojson.org/v6/api/jsonarray/remove/
|
||||
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.
|
||||
|
@ -26,7 +26,7 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
|
||||
FORCE_INLINE iterator begin() const {
|
||||
if (!data_)
|
||||
return iterator();
|
||||
return iterator(data_->head());
|
||||
return iterator(data_->begin());
|
||||
}
|
||||
|
||||
// Returns an iterator to the element following the last element of the array.
|
||||
|
@ -30,76 +30,66 @@ class JsonArrayIterator {
|
||||
friend class JsonArray;
|
||||
|
||||
public:
|
||||
JsonArrayIterator() : slot_(0) {}
|
||||
explicit JsonArrayIterator(detail::ResourceManager* resources,
|
||||
detail::VariantSlot* slot)
|
||||
: resources_(resources), slot_(slot) {}
|
||||
JsonArrayIterator() {}
|
||||
explicit JsonArrayIterator(detail::ArrayData::iterator iterator,
|
||||
detail::ResourceManager* resources)
|
||||
: iterator_(iterator), resources_(resources) {}
|
||||
|
||||
JsonVariant operator*() const {
|
||||
return JsonVariant(slot_->data(), resources_);
|
||||
JsonVariant operator*() {
|
||||
return JsonVariant(iterator_.data(), resources_);
|
||||
}
|
||||
Ptr<JsonVariant> operator->() {
|
||||
return operator*();
|
||||
}
|
||||
|
||||
bool operator==(const JsonArrayIterator& other) const {
|
||||
return slot_ == other.slot_;
|
||||
return iterator_ == other.iterator_;
|
||||
}
|
||||
|
||||
bool operator!=(const JsonArrayIterator& other) const {
|
||||
return slot_ != other.slot_;
|
||||
return iterator_ != other.iterator_;
|
||||
}
|
||||
|
||||
JsonArrayIterator& operator++() {
|
||||
slot_ = slot_->next();
|
||||
return *this;
|
||||
}
|
||||
|
||||
JsonArrayIterator& operator+=(size_t distance) {
|
||||
slot_ = slot_->next(distance);
|
||||
++iterator_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
detail::ArrayData::iterator iterator_;
|
||||
detail::ResourceManager* resources_;
|
||||
detail::VariantSlot* slot_;
|
||||
};
|
||||
|
||||
class JsonArrayConstIterator {
|
||||
friend class JsonArray;
|
||||
|
||||
public:
|
||||
JsonArrayConstIterator() : slot_(0) {}
|
||||
explicit JsonArrayConstIterator(const detail::VariantSlot* slot)
|
||||
: slot_(slot) {}
|
||||
JsonArrayConstIterator() {}
|
||||
explicit JsonArrayConstIterator(detail::ArrayData::iterator iterator)
|
||||
: iterator_(iterator) {}
|
||||
|
||||
JsonVariantConst operator*() const {
|
||||
return JsonVariantConst(slot_->data());
|
||||
return JsonVariantConst(iterator_.data());
|
||||
}
|
||||
Ptr<JsonVariantConst> operator->() {
|
||||
return operator*();
|
||||
}
|
||||
|
||||
bool operator==(const JsonArrayConstIterator& other) const {
|
||||
return slot_ == other.slot_;
|
||||
return iterator_ == other.iterator_;
|
||||
}
|
||||
|
||||
bool operator!=(const JsonArrayConstIterator& other) const {
|
||||
return slot_ != other.slot_;
|
||||
return iterator_ != other.iterator_;
|
||||
}
|
||||
|
||||
JsonArrayConstIterator& operator++() {
|
||||
slot_ = slot_->next();
|
||||
return *this;
|
||||
}
|
||||
|
||||
JsonArrayConstIterator& operator+=(size_t distance) {
|
||||
slot_ = slot_->next(distance);
|
||||
++iterator_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
const detail::VariantSlot* slot_;
|
||||
detail::ArrayData::iterator iterator_;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
|
@ -14,6 +14,58 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
class VariantData;
|
||||
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 {
|
||||
VariantSlot* head_ = 0;
|
||||
VariantSlot* tail_ = 0;
|
||||
@ -26,8 +78,19 @@ class CollectionData {
|
||||
|
||||
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 size() const;
|
||||
size_t nesting() const;
|
||||
|
||||
void clear(ResourceManager* resources);
|
||||
|
||||
@ -37,21 +100,16 @@ class CollectionData {
|
||||
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 remove(iterator it, ResourceManager* resources);
|
||||
|
||||
static void remove(CollectionData* collection, iterator it,
|
||||
ResourceManager* resources) {
|
||||
if (collection)
|
||||
return collection->remove(it, resources);
|
||||
}
|
||||
|
||||
protected:
|
||||
void addSlot(VariantSlot*);
|
||||
|
||||
|
@ -11,6 +11,22 @@
|
||||
|
||||
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) {
|
||||
ARDUINOJSON_ASSERT(slot != nullptr);
|
||||
|
||||
@ -41,19 +57,19 @@ inline VariantSlot* CollectionData::getPreviousSlot(VariantSlot* target) const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void CollectionData::removeSlot(VariantSlot* slot,
|
||||
ResourceManager* resources) {
|
||||
if (!slot)
|
||||
inline void CollectionData::remove(iterator it, ResourceManager* resources) {
|
||||
if (!it)
|
||||
return;
|
||||
VariantSlot* prev = getPreviousSlot(slot);
|
||||
VariantSlot* next = slot->next();
|
||||
auto curr = it.slot_;
|
||||
auto prev = getPreviousSlot(curr);
|
||||
auto next = curr->next();
|
||||
if (prev)
|
||||
prev->setNext(next);
|
||||
else
|
||||
head_ = next;
|
||||
if (!next)
|
||||
tail_ = prev;
|
||||
slotRelease(slot, resources);
|
||||
slotRelease(curr, resources);
|
||||
}
|
||||
|
||||
inline size_t CollectionData::memoryUsage() const {
|
||||
@ -66,6 +82,16 @@ inline size_t CollectionData::memoryUsage() const {
|
||||
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 {
|
||||
return slotSize(head_);
|
||||
}
|
||||
|
@ -21,13 +21,13 @@ class JsonSerializer : public Visitor<size_t> {
|
||||
FORCE_INLINE size_t visitArray(const ArrayData& array) {
|
||||
write('[');
|
||||
|
||||
const VariantSlot* slot = array.head();
|
||||
auto it = array.begin();
|
||||
|
||||
while (slot != 0) {
|
||||
slot->data()->accept(*this);
|
||||
while (it) {
|
||||
it->accept(*this);
|
||||
|
||||
slot = slot->next();
|
||||
if (slot == 0)
|
||||
++it;
|
||||
if (!it)
|
||||
break;
|
||||
|
||||
write(',');
|
||||
@ -40,15 +40,15 @@ class JsonSerializer : public Visitor<size_t> {
|
||||
size_t visitObject(const ObjectData& object) {
|
||||
write('{');
|
||||
|
||||
const VariantSlot* slot = object.head();
|
||||
auto it = object.begin();
|
||||
|
||||
while (slot != 0) {
|
||||
formatter_.writeString(slot->key());
|
||||
while (it) {
|
||||
formatter_.writeString(it.key());
|
||||
write(':');
|
||||
slot->data()->accept(*this);
|
||||
it->accept(*this);
|
||||
|
||||
slot = slot->next();
|
||||
if (slot == 0)
|
||||
++it;
|
||||
if (!it)
|
||||
break;
|
||||
|
||||
write(',');
|
||||
|
@ -19,16 +19,16 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
|
||||
PrettyJsonSerializer(TWriter writer) : base(writer), nesting_(0) {}
|
||||
|
||||
size_t visitArray(const ArrayData& array) {
|
||||
const VariantSlot* slot = array.head();
|
||||
if (slot) {
|
||||
auto it = array.begin();
|
||||
if (it) {
|
||||
base::write("[\r\n");
|
||||
nesting_++;
|
||||
while (slot != 0) {
|
||||
while (it) {
|
||||
indent();
|
||||
slot->data()->accept(*this);
|
||||
it->accept(*this);
|
||||
|
||||
slot = slot->next();
|
||||
base::write(slot ? ",\r\n" : "\r\n");
|
||||
++it;
|
||||
base::write(it ? ",\r\n" : "\r\n");
|
||||
}
|
||||
nesting_--;
|
||||
indent();
|
||||
@ -40,18 +40,18 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
|
||||
}
|
||||
|
||||
size_t visitObject(const ObjectData& object) {
|
||||
const VariantSlot* slot = object.head();
|
||||
if (slot) {
|
||||
auto it = object.begin();
|
||||
if (it) {
|
||||
base::write("{\r\n");
|
||||
nesting_++;
|
||||
while (slot != 0) {
|
||||
while (it) {
|
||||
indent();
|
||||
base::visitString(slot->key());
|
||||
base::visitString(it.key());
|
||||
base::write(": ");
|
||||
slot->data()->accept(*this);
|
||||
it->accept(*this);
|
||||
|
||||
slot = slot->next();
|
||||
base::write(slot ? ",\r\n" : "\r\n");
|
||||
++it;
|
||||
base::write(it ? ",\r\n" : "\r\n");
|
||||
}
|
||||
nesting_--;
|
||||
indent();
|
||||
|
@ -55,8 +55,8 @@ class MsgPackSerializer : public Visitor<size_t> {
|
||||
writeByte(0xDD);
|
||||
writeInteger(uint32_t(n));
|
||||
}
|
||||
for (const VariantSlot* slot = array.head(); slot; slot = slot->next()) {
|
||||
slot->data()->accept(*this);
|
||||
for (auto it = array.begin(); it; ++it) {
|
||||
it->accept(*this);
|
||||
}
|
||||
return bytesWritten();
|
||||
}
|
||||
@ -72,9 +72,9 @@ class MsgPackSerializer : public Visitor<size_t> {
|
||||
writeByte(0xDF);
|
||||
writeInteger(uint32_t(n));
|
||||
}
|
||||
for (const VariantSlot* slot = object.head(); slot; slot = slot->next()) {
|
||||
visitString(slot->key());
|
||||
slot->data()->accept(*this);
|
||||
for (auto it = object.begin(); it; ++it) {
|
||||
visitString(it.key());
|
||||
it->accept(*this);
|
||||
}
|
||||
return bytesWritten();
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
|
||||
FORCE_INLINE iterator begin() const {
|
||||
if (!data_)
|
||||
return iterator();
|
||||
return iterator(resources_, data_->head());
|
||||
return iterator(data_->begin(), resources_);
|
||||
}
|
||||
|
||||
// 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.
|
||||
// https://arduinojson.org/v6/api/jsonobject/remove/
|
||||
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.
|
||||
|
@ -63,7 +63,7 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
|
||||
FORCE_INLINE iterator begin() const {
|
||||
if (!data_)
|
||||
return iterator();
|
||||
return iterator(data_->head());
|
||||
return iterator(data_->begin());
|
||||
}
|
||||
|
||||
// Returns an iterator following the last key-value pair of the object.
|
||||
|
@ -13,78 +13,68 @@ class JsonObjectIterator {
|
||||
friend class JsonObject;
|
||||
|
||||
public:
|
||||
JsonObjectIterator() : slot_(0) {}
|
||||
JsonObjectIterator() {}
|
||||
|
||||
explicit JsonObjectIterator(detail::ResourceManager* resources,
|
||||
detail::VariantSlot* slot)
|
||||
: resources_(resources), slot_(slot) {}
|
||||
explicit JsonObjectIterator(detail::ObjectData::iterator iterator,
|
||||
detail::ResourceManager* resources)
|
||||
: iterator_(iterator), resources_(resources) {}
|
||||
|
||||
JsonPair operator*() const {
|
||||
return JsonPair(resources_, slot_);
|
||||
return JsonPair(iterator_, resources_);
|
||||
}
|
||||
Ptr<JsonPair> operator->() {
|
||||
return operator*();
|
||||
}
|
||||
|
||||
bool operator==(const JsonObjectIterator& other) const {
|
||||
return slot_ == other.slot_;
|
||||
return iterator_ == other.iterator_;
|
||||
}
|
||||
|
||||
bool operator!=(const JsonObjectIterator& other) const {
|
||||
return slot_ != other.slot_;
|
||||
return iterator_ != other.iterator_;
|
||||
}
|
||||
|
||||
JsonObjectIterator& operator++() {
|
||||
slot_ = slot_->next();
|
||||
return *this;
|
||||
}
|
||||
|
||||
JsonObjectIterator& operator+=(size_t distance) {
|
||||
slot_ = slot_->next(distance);
|
||||
++iterator_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
detail::ObjectData::iterator iterator_;
|
||||
detail::ResourceManager* resources_;
|
||||
detail::VariantSlot* slot_;
|
||||
};
|
||||
|
||||
class JsonObjectConstIterator {
|
||||
friend class JsonObject;
|
||||
|
||||
public:
|
||||
JsonObjectConstIterator() : slot_(0) {}
|
||||
JsonObjectConstIterator() {}
|
||||
|
||||
explicit JsonObjectConstIterator(const detail::VariantSlot* slot)
|
||||
: slot_(slot) {}
|
||||
explicit JsonObjectConstIterator(detail::ObjectData::iterator iterator)
|
||||
: iterator_(iterator) {}
|
||||
|
||||
JsonPairConst operator*() const {
|
||||
return JsonPairConst(slot_);
|
||||
return JsonPairConst(iterator_);
|
||||
}
|
||||
Ptr<JsonPairConst> operator->() {
|
||||
return operator*();
|
||||
}
|
||||
|
||||
bool operator==(const JsonObjectConstIterator& other) const {
|
||||
return slot_ == other.slot_;
|
||||
return iterator_ == other.iterator_;
|
||||
}
|
||||
|
||||
bool operator!=(const JsonObjectConstIterator& other) const {
|
||||
return slot_ != other.slot_;
|
||||
return iterator_ != other.iterator_;
|
||||
}
|
||||
|
||||
JsonObjectConstIterator& operator++() {
|
||||
slot_ = slot_->next();
|
||||
return *this;
|
||||
}
|
||||
|
||||
JsonObjectConstIterator& operator+=(size_t distance) {
|
||||
slot_ = slot_->next(distance);
|
||||
++iterator_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
const detail::VariantSlot* slot_;
|
||||
detail::ObjectData::iterator iterator_;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
|
@ -15,54 +15,53 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
|
||||
class JsonPair {
|
||||
public:
|
||||
// INTERNAL USE ONLY
|
||||
JsonPair(detail::ResourceManager* resources, detail::VariantSlot* slot) {
|
||||
if (slot) {
|
||||
key_ = JsonString(slot->key(), slot->ownsKey() ? JsonString::Copied
|
||||
: JsonString::Linked);
|
||||
value_ = JsonVariant(slot->data(), resources);
|
||||
}
|
||||
}
|
||||
JsonPair(detail::ObjectData::iterator iterator,
|
||||
detail::ResourceManager* resources)
|
||||
: iterator_(iterator), resources_(resources) {}
|
||||
|
||||
// Returns the key.
|
||||
JsonString key() const {
|
||||
return key_;
|
||||
if (iterator_)
|
||||
return JsonString(iterator_.key(), iterator_.ownsKey()
|
||||
? JsonString::Copied
|
||||
: JsonString::Linked);
|
||||
else
|
||||
return JsonString();
|
||||
}
|
||||
|
||||
// Returns the value.
|
||||
JsonVariant value() const {
|
||||
return value_;
|
||||
JsonVariant value() {
|
||||
return JsonVariant(iterator_.data(), resources_);
|
||||
}
|
||||
|
||||
private:
|
||||
JsonString key_;
|
||||
JsonVariant value_;
|
||||
detail::ObjectData::iterator iterator_;
|
||||
detail::ResourceManager* resources_;
|
||||
};
|
||||
|
||||
// A read-only key-value pair.
|
||||
// https://arduinojson.org/v6/api/jsonobjectconst/begin_end/
|
||||
class JsonPairConst {
|
||||
public:
|
||||
JsonPairConst(const detail::VariantSlot* slot) {
|
||||
if (slot) {
|
||||
key_ = JsonString(slot->key(), slot->ownsKey() ? JsonString::Copied
|
||||
: JsonString::Linked);
|
||||
value_ = JsonVariantConst(slot->data());
|
||||
}
|
||||
}
|
||||
JsonPairConst(detail::ObjectData::iterator iterator) : iterator_(iterator) {}
|
||||
|
||||
// Returns the key.
|
||||
JsonString key() const {
|
||||
return key_;
|
||||
if (iterator_)
|
||||
return JsonString(iterator_.key(), iterator_.ownsKey()
|
||||
? JsonString::Copied
|
||||
: JsonString::Linked);
|
||||
else
|
||||
return JsonString();
|
||||
}
|
||||
|
||||
// Returns the value.
|
||||
JsonVariantConst value() const {
|
||||
return value_;
|
||||
return JsonVariantConst(iterator_.data());
|
||||
}
|
||||
|
||||
private:
|
||||
JsonString key_;
|
||||
JsonVariantConst value_;
|
||||
detail::ObjectData::iterator iterator_;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||
|
@ -63,7 +63,7 @@ class ObjectData : public CollectionData {
|
||||
|
||||
private:
|
||||
template <typename TAdaptedString>
|
||||
VariantSlot* getSlot(TAdaptedString key) const;
|
||||
iterator findKey(TAdaptedString key) const;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
@ -44,14 +44,14 @@ inline bool ObjectData::copyFrom(const ObjectData& src,
|
||||
ResourceManager* resources) {
|
||||
clear(resources);
|
||||
|
||||
for (VariantSlot* s = src.head(); s; s = s->next()) {
|
||||
ARDUINOJSON_ASSERT(s->key() != 0);
|
||||
JsonString key(s->key(),
|
||||
s->ownsKey() ? JsonString::Copied : JsonString::Linked);
|
||||
for (auto it = src.begin(); it; ++it) {
|
||||
ARDUINOJSON_ASSERT(it.key() != 0);
|
||||
JsonString key(it.key(),
|
||||
it.ownsKey() ? JsonString::Copied : JsonString::Linked);
|
||||
auto var = addMember(adaptString(key), resources);
|
||||
if (!var)
|
||||
return false;
|
||||
if (!var->copyFrom(s->data(), resources))
|
||||
if (!var->copyFrom(*it, resources))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -59,11 +59,12 @@ inline bool ObjectData::copyFrom(const ObjectData& src,
|
||||
|
||||
inline bool ObjectData::equals(const ObjectData& other) const {
|
||||
size_t count = 0;
|
||||
for (auto a = head(); a; a = a->next()) {
|
||||
auto b = other.getMember(adaptString(a->key()));
|
||||
for (auto it = begin(); it; ++it) {
|
||||
auto a = it.data();
|
||||
auto b = other.getMember(adaptString(it.key()));
|
||||
if (!b)
|
||||
return false;
|
||||
if (compare(a->data(), b) != COMPARE_RESULT_EQUAL)
|
||||
if (compare(a, b) != COMPARE_RESULT_EQUAL)
|
||||
return false;
|
||||
count++;
|
||||
}
|
||||
@ -72,35 +73,33 @@ inline bool ObjectData::equals(const ObjectData& other) const {
|
||||
|
||||
template <typename TAdaptedString>
|
||||
inline VariantData* ObjectData::getMember(TAdaptedString key) const {
|
||||
return slotData(getSlot(key));
|
||||
return findKey(key).data();
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
VariantData* ObjectData::getOrAddMember(TAdaptedString key,
|
||||
ResourceManager* resources) {
|
||||
auto slot = getSlot(key);
|
||||
if (slot)
|
||||
return slot->data();
|
||||
auto it = findKey(key);
|
||||
if (it)
|
||||
return it.data();
|
||||
return addMember(key, resources);
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
inline VariantSlot* ObjectData::getSlot(TAdaptedString key) const {
|
||||
inline ObjectData::iterator ObjectData::findKey(TAdaptedString key) const {
|
||||
if (key.isNull())
|
||||
return 0;
|
||||
VariantSlot* slot = head();
|
||||
while (slot) {
|
||||
if (stringEquals(key, adaptString(slot->key())))
|
||||
break;
|
||||
slot = slot->next();
|
||||
return end();
|
||||
for (auto it = begin(); it; ++it) {
|
||||
if (stringEquals(key, adaptString(it.key())))
|
||||
return it;
|
||||
}
|
||||
return slot;
|
||||
return end();
|
||||
}
|
||||
|
||||
template <typename TAdaptedString>
|
||||
inline void ObjectData::removeMember(TAdaptedString key,
|
||||
ResourceManager* resources) {
|
||||
removeSlot(getSlot(key), resources);
|
||||
remove(findKey(key), resources);
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
@ -107,10 +107,14 @@ class VariantData {
|
||||
return const_cast<VariantData*>(this)->asArray();
|
||||
}
|
||||
|
||||
const CollectionData* asCollection() const {
|
||||
CollectionData* asCollection() {
|
||||
return isCollection() ? &content_.asCollection : 0;
|
||||
}
|
||||
|
||||
const CollectionData* asCollection() const {
|
||||
return const_cast<VariantData*>(this)->asCollection();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T asFloat() const {
|
||||
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);
|
||||
if (!src) {
|
||||
setNull();
|
||||
return true;
|
||||
}
|
||||
switch (src->type()) {
|
||||
switch (src.type()) {
|
||||
case VALUE_IS_ARRAY:
|
||||
return toArray().copyFrom(*src->asArray(), resources);
|
||||
return toArray().copyFrom(src.content_.asArray, resources);
|
||||
case VALUE_IS_OBJECT:
|
||||
return toObject().copyFrom(*src->asObject(), resources);
|
||||
return toObject().copyFrom(src.content_.asObject, resources);
|
||||
case VALUE_IS_OWNED_STRING: {
|
||||
auto str = adaptString(src->asString());
|
||||
auto str = adaptString(src.asString());
|
||||
auto dup = resources->saveString(str);
|
||||
if (!dup)
|
||||
return false;
|
||||
@ -202,7 +202,7 @@ class VariantData {
|
||||
return true;
|
||||
}
|
||||
case VALUE_IS_RAW_STRING: {
|
||||
auto str = adaptString(src->asRawString());
|
||||
auto str = adaptString(src.asRawString());
|
||||
auto dup = resources->saveString(str);
|
||||
if (!dup)
|
||||
return false;
|
||||
@ -210,8 +210,8 @@ class VariantData {
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
content_ = src->content_;
|
||||
flags_ = src->flags_;
|
||||
content_ = src.content_;
|
||||
flags_ = src.flags_;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -220,7 +220,11 @@ class VariantData {
|
||||
ResourceManager* resources) {
|
||||
if (!dst)
|
||||
return false;
|
||||
return dst->copyFrom(src, resources);
|
||||
if (!src) {
|
||||
dst->setNull();
|
||||
return true;
|
||||
}
|
||||
return dst->copyFrom(*src, resources);
|
||||
}
|
||||
|
||||
VariantData* getElement(size_t index) const {
|
||||
@ -334,16 +338,10 @@ class VariantData {
|
||||
|
||||
size_t nesting() const {
|
||||
auto collection = asCollection();
|
||||
if (!collection)
|
||||
if (collection)
|
||||
return collection->nesting();
|
||||
else
|
||||
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) {
|
||||
@ -550,11 +548,9 @@ class VariantData {
|
||||
if (flags_ & OWNED_VALUE_BIT)
|
||||
resources->dereferenceString(content_.asOwnedString->data);
|
||||
|
||||
auto c = asCollection();
|
||||
if (c) {
|
||||
for (auto slot = c->head(); slot; slot = slot->next())
|
||||
slotRelease(slot, resources);
|
||||
}
|
||||
auto collection = asCollection();
|
||||
if (collection)
|
||||
collection->clear(resources);
|
||||
}
|
||||
|
||||
void setType(uint8_t t) {
|
||||
|
@ -51,20 +51,6 @@ class VariantSlot {
|
||||
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) {
|
||||
ARDUINOJSON_ASSERT(!slot || slot - this >=
|
||||
numeric_limits<VariantSlotDiff>::lowest());
|
||||
|
Reference in New Issue
Block a user