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") {
|
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);
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -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*);
|
||||||
|
|
||||||
|
@ -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_);
|
||||||
}
|
}
|
||||||
|
@ -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(',');
|
||||||
|
@ -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();
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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.
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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) {
|
||||||
|
@ -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());
|
||||||
|
Reference in New Issue
Block a user