forked from bblanchon/ArduinoJson
Added JsonArray::remove(iterator)
and JsonObject::remove(iterator)
(issue #479)
This commit is contained in:
@ -1,6 +1,12 @@
|
|||||||
ArduinoJson: change log
|
ArduinoJson: change log
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
|
HEAD
|
||||||
|
----
|
||||||
|
|
||||||
|
* Added `JsonArray::remove(iterator)` (issue #479)
|
||||||
|
* Added `JsonObject::remove(iterator)`
|
||||||
|
|
||||||
v5.8.4
|
v5.8.4
|
||||||
------
|
------
|
||||||
|
|
||||||
|
@ -48,6 +48,20 @@ class List {
|
|||||||
return nodeCount;
|
return nodeCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iterator add() {
|
||||||
|
node_type *newNode = new (_buffer) node_type();
|
||||||
|
|
||||||
|
if (_firstNode) {
|
||||||
|
node_type *lastNode = _firstNode;
|
||||||
|
while (lastNode->next) lastNode = lastNode->next;
|
||||||
|
lastNode->next = newNode;
|
||||||
|
} else {
|
||||||
|
_firstNode = newNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
return iterator(newNode);
|
||||||
|
}
|
||||||
|
|
||||||
iterator begin() {
|
iterator begin() {
|
||||||
return iterator(_firstNode);
|
return iterator(_firstNode);
|
||||||
}
|
}
|
||||||
@ -62,22 +76,8 @@ class List {
|
|||||||
return const_iterator(NULL);
|
return const_iterator(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
void remove(iterator it) {
|
||||||
node_type *addNewNode() {
|
node_type *nodeToRemove = it._node;
|
||||||
node_type *newNode = new (_buffer) node_type();
|
|
||||||
|
|
||||||
if (_firstNode) {
|
|
||||||
node_type *lastNode = _firstNode;
|
|
||||||
while (lastNode->next) lastNode = lastNode->next;
|
|
||||||
lastNode->next = newNode;
|
|
||||||
} else {
|
|
||||||
_firstNode = newNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
return newNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
void removeNode(node_type *nodeToRemove) {
|
|
||||||
if (!nodeToRemove) return;
|
if (!nodeToRemove) return;
|
||||||
if (nodeToRemove == _firstNode) {
|
if (nodeToRemove == _firstNode) {
|
||||||
_firstNode = nodeToRemove->next;
|
_firstNode = nodeToRemove->next;
|
||||||
@ -87,6 +87,7 @@ class List {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
JsonBuffer *_buffer;
|
JsonBuffer *_buffer;
|
||||||
node_type *_firstNode;
|
node_type *_firstNode;
|
||||||
};
|
};
|
||||||
|
@ -38,6 +38,14 @@ class ListConstIterator {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ListConstIterator<T> &operator+=(size_t distance) {
|
||||||
|
while (_node && distance) {
|
||||||
|
_node = _node->next;
|
||||||
|
--distance;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const ListNode<T> *_node;
|
const ListNode<T> *_node;
|
||||||
};
|
};
|
||||||
|
@ -13,9 +13,14 @@
|
|||||||
namespace ArduinoJson {
|
namespace ArduinoJson {
|
||||||
namespace Internals {
|
namespace Internals {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class List;
|
||||||
|
|
||||||
// A read-write forward iterator for List<T>
|
// A read-write forward iterator for List<T>
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class ListIterator {
|
class ListIterator {
|
||||||
|
friend class List<T>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ListIterator(ListNode<T> *node = NULL) : _node(node) {}
|
explicit ListIterator(ListNode<T> *node = NULL) : _node(node) {}
|
||||||
|
|
||||||
@ -39,6 +44,14 @@ class ListIterator {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ListIterator<T> &operator+=(size_t distance) {
|
||||||
|
while (_node && distance) {
|
||||||
|
_node = _node->next;
|
||||||
|
--distance;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
operator ListConstIterator<T>() const {
|
operator ListConstIterator<T>() const {
|
||||||
return ListConstIterator<T>(_node);
|
return ListConstIterator<T>(_node);
|
||||||
}
|
}
|
||||||
|
@ -111,16 +111,15 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
|
|||||||
// Gets the value at the specified index.
|
// Gets the value at the specified index.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename Internals::JsonVariantAs<T>::type get(size_t index) const {
|
typename Internals::JsonVariantAs<T>::type get(size_t index) const {
|
||||||
node_type *node = findNode(index);
|
const_iterator it = begin() += index;
|
||||||
return node ? node->content.as<T>()
|
return it != end() ? it->as<T>() : Internals::JsonVariantDefault<T>::get();
|
||||||
: Internals::JsonVariantDefault<T>::get();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the type of the value at specified index.
|
// Check the type of the value at specified index.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool is(size_t index) const {
|
bool is(size_t index) const {
|
||||||
node_type *node = findNode(index);
|
const_iterator it = begin() += index;
|
||||||
return node ? node->content.is<T>() : false;
|
return it != end() ? it->is<T>() : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a JsonArray and adds a reference at the end of the array.
|
// Creates a JsonArray and adds a reference at the end of the array.
|
||||||
@ -133,8 +132,9 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
|
|||||||
|
|
||||||
// Removes element at specified index.
|
// Removes element at specified index.
|
||||||
void removeAt(size_t index) {
|
void removeAt(size_t index) {
|
||||||
removeNode(findNode(index));
|
remove(begin() += index);
|
||||||
}
|
}
|
||||||
|
using Internals::List<JsonVariant>::remove;
|
||||||
|
|
||||||
// Returns a reference an invalid JsonArray.
|
// Returns a reference an invalid JsonArray.
|
||||||
// This object is meant to replace a NULL pointer.
|
// This object is meant to replace a NULL pointer.
|
||||||
@ -198,28 +198,18 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
node_type *findNode(size_t index) const {
|
|
||||||
node_type *node = _firstNode;
|
|
||||||
while (node && index--) node = node->next;
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename TValueRef>
|
template <typename TValueRef>
|
||||||
bool set_impl(size_t index, TValueRef value) {
|
bool set_impl(size_t index, TValueRef value) {
|
||||||
node_type *node = findNode(index);
|
iterator it = begin() += index;
|
||||||
if (!node) return false;
|
if (it == end()) return false;
|
||||||
|
return Internals::ValueSetter<TValueRef>::set(_buffer, *it, value);
|
||||||
return Internals::ValueSetter<TValueRef>::set(_buffer, node->content,
|
|
||||||
value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TValueRef>
|
template <typename TValueRef>
|
||||||
bool add_impl(TValueRef value) {
|
bool add_impl(TValueRef value) {
|
||||||
node_type *node = addNewNode();
|
iterator it = Internals::List<JsonVariant>::add();
|
||||||
if (!node) return false;
|
if (it == end()) return false;
|
||||||
|
return Internals::ValueSetter<TValueRef>::set(_buffer, *it, value);
|
||||||
return Internals::ValueSetter<TValueRef>::set(_buffer, node->content,
|
|
||||||
value);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -247,14 +247,14 @@ class JsonObject : public Internals::JsonPrintable<JsonObject>,
|
|||||||
typename TypeTraits::EnableIf<!TypeTraits::IsArray<TString>::value,
|
typename TypeTraits::EnableIf<!TypeTraits::IsArray<TString>::value,
|
||||||
bool>::type
|
bool>::type
|
||||||
containsKey(const TString& key) const {
|
containsKey(const TString& key) const {
|
||||||
return findNode<const TString&>(key) != NULL;
|
return findKey<const TString&>(key) != end();
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
// bool containsKey(TKey);
|
// bool containsKey(TKey);
|
||||||
// TKey = const char*, const char[N], const FlashStringHelper*
|
// TKey = const char*, const char[N], const FlashStringHelper*
|
||||||
template <typename TString>
|
template <typename TString>
|
||||||
bool containsKey(const TString* key) const {
|
bool containsKey(const TString* key) const {
|
||||||
return findNode<const TString*>(key) != NULL;
|
return findKey<const TString*>(key) != end();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes the specified key and the associated value.
|
// Removes the specified key and the associated value.
|
||||||
@ -265,15 +265,18 @@ class JsonObject : public Internals::JsonPrintable<JsonObject>,
|
|||||||
typename TypeTraits::EnableIf<!TypeTraits::IsArray<TString>::value,
|
typename TypeTraits::EnableIf<!TypeTraits::IsArray<TString>::value,
|
||||||
void>::type
|
void>::type
|
||||||
remove(const TString& key) {
|
remove(const TString& key) {
|
||||||
removeNode(findNode<const TString&>(key));
|
remove(findKey<const TString&>(key));
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
// void remove(TKey);
|
// void remove(TKey);
|
||||||
// TKey = const char*, const char[N], const FlashStringHelper*
|
// TKey = const char*, const char[N], const FlashStringHelper*
|
||||||
template <typename TString>
|
template <typename TString>
|
||||||
void remove(const TString* key) {
|
void remove(const TString* key) {
|
||||||
removeNode(findNode<const TString*>(key));
|
remove(findKey<const TString*>(key));
|
||||||
}
|
}
|
||||||
|
//
|
||||||
|
// void remove(iterator)
|
||||||
|
using Internals::List<JsonPair>::remove;
|
||||||
|
|
||||||
// Returns a reference an invalid JsonObject.
|
// Returns a reference an invalid JsonObject.
|
||||||
// This object is meant to replace a NULL pointer.
|
// This object is meant to replace a NULL pointer.
|
||||||
@ -286,41 +289,44 @@ class JsonObject : public Internals::JsonPrintable<JsonObject>,
|
|||||||
private:
|
private:
|
||||||
// Returns the list node that matches the specified key.
|
// Returns the list node that matches the specified key.
|
||||||
template <typename TStringRef>
|
template <typename TStringRef>
|
||||||
node_type* findNode(TStringRef key) const {
|
iterator findKey(TStringRef key) {
|
||||||
for (node_type* node = _firstNode; node; node = node->next) {
|
iterator it;
|
||||||
if (Internals::StringTraits<TStringRef>::equals(key, node->content.key))
|
for (it = begin(); it != end(); ++it) {
|
||||||
return node;
|
if (Internals::StringTraits<TStringRef>::equals(key, it->key)) break;
|
||||||
}
|
}
|
||||||
return NULL;
|
return it;
|
||||||
|
}
|
||||||
|
template <typename TStringRef>
|
||||||
|
const_iterator findKey(TStringRef key) const {
|
||||||
|
return const_cast<JsonObject*>(this)->findKey<TStringRef>(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TStringRef, typename TValue>
|
template <typename TStringRef, typename TValue>
|
||||||
typename Internals::JsonVariantAs<TValue>::type get_impl(
|
typename Internals::JsonVariantAs<TValue>::type get_impl(
|
||||||
TStringRef key) const {
|
TStringRef key) const {
|
||||||
node_type* node = findNode<TStringRef>(key);
|
const_iterator it = findKey<TStringRef>(key);
|
||||||
return node ? node->content.value.as<TValue>()
|
return it != end() ? it->value.as<TValue>()
|
||||||
: Internals::JsonVariantDefault<TValue>::get();
|
: Internals::JsonVariantDefault<TValue>::get();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TStringRef, typename TValueRef>
|
template <typename TStringRef, typename TValueRef>
|
||||||
bool set_impl(TStringRef key, TValueRef value) {
|
bool set_impl(TStringRef key, TValueRef value) {
|
||||||
node_type* node = findNode<TStringRef>(key);
|
iterator it = findKey<TStringRef>(key);
|
||||||
if (!node) {
|
if (it == end()) {
|
||||||
node = addNewNode();
|
it = Internals::List<JsonPair>::add();
|
||||||
if (!node) return false;
|
if (it == end()) return false;
|
||||||
|
|
||||||
bool key_ok = Internals::ValueSetter<TStringRef>::set(
|
bool key_ok =
|
||||||
_buffer, node->content.key, key);
|
Internals::ValueSetter<TStringRef>::set(_buffer, it->key, key);
|
||||||
if (!key_ok) return false;
|
if (!key_ok) return false;
|
||||||
}
|
}
|
||||||
return Internals::ValueSetter<TValueRef>::set(_buffer, node->content.value,
|
return Internals::ValueSetter<TValueRef>::set(_buffer, it->value, value);
|
||||||
value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TStringRef, typename TValue>
|
template <typename TStringRef, typename TValue>
|
||||||
bool is_impl(TStringRef key) const {
|
bool is_impl(TStringRef key) const {
|
||||||
node_type* node = findNode<TStringRef>(key);
|
const_iterator it = findKey<TStringRef>(key);
|
||||||
return node ? node->content.value.is<TValue>() : false;
|
return it != end() ? it->value.is<TValue>() : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TStringRef>
|
template <typename TStringRef>
|
||||||
|
@ -22,7 +22,7 @@ class JsonArray_Remove_Tests : public ::testing::Test {
|
|||||||
|
|
||||||
#define TEST_(name) TEST_F(JsonArray_Remove_Tests, name)
|
#define TEST_(name) TEST_F(JsonArray_Remove_Tests, name)
|
||||||
|
|
||||||
TEST_(RemoveFirstElement) {
|
TEST_(RemoveFirstByIndex) {
|
||||||
_array.removeAt(0);
|
_array.removeAt(0);
|
||||||
|
|
||||||
EXPECT_EQ(2, _array.size());
|
EXPECT_EQ(2, _array.size());
|
||||||
@ -30,7 +30,7 @@ TEST_(RemoveFirstElement) {
|
|||||||
EXPECT_STREQ("three", _array[1]);
|
EXPECT_STREQ("three", _array[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_(RemoveMiddleElement) {
|
TEST_(RemoveMiddleByIndex) {
|
||||||
_array.removeAt(1);
|
_array.removeAt(1);
|
||||||
|
|
||||||
EXPECT_EQ(2, _array.size());
|
EXPECT_EQ(2, _array.size());
|
||||||
@ -38,10 +38,40 @@ TEST_(RemoveMiddleElement) {
|
|||||||
EXPECT_STREQ("three", _array[1]);
|
EXPECT_STREQ("three", _array[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_(RemoveLastElement) {
|
TEST_(RemoveLastByIndex) {
|
||||||
_array.removeAt(2);
|
_array.removeAt(2);
|
||||||
|
|
||||||
EXPECT_EQ(2, _array.size());
|
EXPECT_EQ(2, _array.size());
|
||||||
EXPECT_STREQ("one", _array[0]);
|
EXPECT_STREQ("one", _array[0]);
|
||||||
EXPECT_STREQ("two", _array[1]);
|
EXPECT_STREQ("two", _array[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_(RemoveFirstByIterator) {
|
||||||
|
JsonArray::iterator it = _array.begin();
|
||||||
|
_array.remove(it);
|
||||||
|
|
||||||
|
EXPECT_EQ(2, _array.size());
|
||||||
|
EXPECT_STREQ("two", _array[0]);
|
||||||
|
EXPECT_STREQ("three", _array[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_(RemoveMiddleByIterator) {
|
||||||
|
JsonArray::iterator it = _array.begin();
|
||||||
|
++it;
|
||||||
|
_array.remove(it);
|
||||||
|
|
||||||
|
EXPECT_EQ(2, _array.size());
|
||||||
|
EXPECT_STREQ("one", _array[0]);
|
||||||
|
EXPECT_STREQ("three", _array[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_(RemoveLastByIterator) {
|
||||||
|
JsonArray::iterator it = _array.begin();
|
||||||
|
++it;
|
||||||
|
++it;
|
||||||
|
_array.remove(it);
|
||||||
|
|
||||||
|
EXPECT_EQ(2, _array.size());
|
||||||
|
EXPECT_STREQ("one", _array[0]);
|
||||||
|
EXPECT_STREQ("two", _array[1]);
|
||||||
|
}
|
||||||
|
@ -29,3 +29,16 @@ TEST_(SizeUntouched_WhenRemoveIsCalledWithAWrongKey) {
|
|||||||
|
|
||||||
EXPECT_EQ(1, _object.size());
|
EXPECT_EQ(1, _object.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_(RemoveByIterator) {
|
||||||
|
DynamicJsonBuffer _jsonBuffer;
|
||||||
|
JsonObject& _object = _jsonBuffer.parseObject("{\"a\":0,\"b\":1,\"c\":2}");
|
||||||
|
|
||||||
|
for (JsonObject::iterator it = _object.begin(); it != _object.end(); ++it) {
|
||||||
|
if (it->value == 1) _object.remove(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
char result[64];
|
||||||
|
_object.printTo(result);
|
||||||
|
EXPECT_STREQ("{\"a\":0,\"c\":2}", result);
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user