mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 16:14:11 +01:00 
			
		
		
		
	Added JsonArray::remove(iterator) and JsonObject::remove(iterator) (issue #479)
				
					
				
			This commit is contained in:
		| @@ -1,6 +1,12 @@ | ||||
| ArduinoJson: change log | ||||
| ======================= | ||||
|  | ||||
| HEAD | ||||
| ---- | ||||
|  | ||||
| * Added `JsonArray::remove(iterator)` (issue #479) | ||||
| * Added `JsonObject::remove(iterator)` | ||||
|  | ||||
| v5.8.4 | ||||
| ------ | ||||
|  | ||||
|   | ||||
| @@ -48,6 +48,20 @@ class List { | ||||
|     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() { | ||||
|     return iterator(_firstNode); | ||||
|   } | ||||
| @@ -62,22 +76,8 @@ class List { | ||||
|     return const_iterator(NULL); | ||||
|   } | ||||
|  | ||||
|  protected: | ||||
|   node_type *addNewNode() { | ||||
|     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) { | ||||
|   void remove(iterator it) { | ||||
|     node_type *nodeToRemove = it._node; | ||||
|     if (!nodeToRemove) return; | ||||
|     if (nodeToRemove == _firstNode) { | ||||
|       _firstNode = nodeToRemove->next; | ||||
| @@ -87,6 +87,7 @@ class List { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|  protected: | ||||
|   JsonBuffer *_buffer; | ||||
|   node_type *_firstNode; | ||||
| }; | ||||
|   | ||||
| @@ -38,6 +38,14 @@ class ListConstIterator { | ||||
|     return *this; | ||||
|   } | ||||
|  | ||||
|   ListConstIterator<T> &operator+=(size_t distance) { | ||||
|     while (_node && distance) { | ||||
|       _node = _node->next; | ||||
|       --distance; | ||||
|     } | ||||
|     return *this; | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   const ListNode<T> *_node; | ||||
| }; | ||||
|   | ||||
| @@ -13,9 +13,14 @@ | ||||
| namespace ArduinoJson { | ||||
| namespace Internals { | ||||
|  | ||||
| template <typename T> | ||||
| class List; | ||||
|  | ||||
| // A read-write forward iterator for List<T> | ||||
| template <typename T> | ||||
| class ListIterator { | ||||
|   friend class List<T>; | ||||
|  | ||||
|  public: | ||||
|   explicit ListIterator(ListNode<T> *node = NULL) : _node(node) {} | ||||
|  | ||||
| @@ -39,6 +44,14 @@ class ListIterator { | ||||
|     return *this; | ||||
|   } | ||||
|  | ||||
|   ListIterator<T> &operator+=(size_t distance) { | ||||
|     while (_node && distance) { | ||||
|       _node = _node->next; | ||||
|       --distance; | ||||
|     } | ||||
|     return *this; | ||||
|   } | ||||
|  | ||||
|   operator ListConstIterator<T>() const { | ||||
|     return ListConstIterator<T>(_node); | ||||
|   } | ||||
|   | ||||
| @@ -111,16 +111,15 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>, | ||||
|   // Gets the value at the specified index. | ||||
|   template <typename T> | ||||
|   typename Internals::JsonVariantAs<T>::type get(size_t index) const { | ||||
|     node_type *node = findNode(index); | ||||
|     return node ? node->content.as<T>() | ||||
|                 : Internals::JsonVariantDefault<T>::get(); | ||||
|     const_iterator it = begin() += index; | ||||
|     return it != end() ? it->as<T>() : Internals::JsonVariantDefault<T>::get(); | ||||
|   } | ||||
|  | ||||
|   // Check the type of the value at specified index. | ||||
|   template <typename T> | ||||
|   bool is(size_t index) const { | ||||
|     node_type *node = findNode(index); | ||||
|     return node ? node->content.is<T>() : false; | ||||
|     const_iterator it = begin() += index; | ||||
|     return it != end() ? it->is<T>() : false; | ||||
|   } | ||||
|  | ||||
|   // 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. | ||||
|   void removeAt(size_t index) { | ||||
|     removeNode(findNode(index)); | ||||
|     remove(begin() += index); | ||||
|   } | ||||
|   using Internals::List<JsonVariant>::remove; | ||||
|  | ||||
|   // Returns a reference an invalid JsonArray. | ||||
|   // This object is meant to replace a NULL pointer. | ||||
| @@ -198,28 +198,18 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>, | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   node_type *findNode(size_t index) const { | ||||
|     node_type *node = _firstNode; | ||||
|     while (node && index--) node = node->next; | ||||
|     return node; | ||||
|   } | ||||
|  | ||||
|   template <typename TValueRef> | ||||
|   bool set_impl(size_t index, TValueRef value) { | ||||
|     node_type *node = findNode(index); | ||||
|     if (!node) return false; | ||||
|  | ||||
|     return Internals::ValueSetter<TValueRef>::set(_buffer, node->content, | ||||
|                                                   value); | ||||
|     iterator it = begin() += index; | ||||
|     if (it == end()) return false; | ||||
|     return Internals::ValueSetter<TValueRef>::set(_buffer, *it, value); | ||||
|   } | ||||
|  | ||||
|   template <typename TValueRef> | ||||
|   bool add_impl(TValueRef value) { | ||||
|     node_type *node = addNewNode(); | ||||
|     if (!node) return false; | ||||
|  | ||||
|     return Internals::ValueSetter<TValueRef>::set(_buffer, node->content, | ||||
|                                                   value); | ||||
|     iterator it = Internals::List<JsonVariant>::add(); | ||||
|     if (it == end()) return false; | ||||
|     return Internals::ValueSetter<TValueRef>::set(_buffer, *it, value); | ||||
|   } | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -247,14 +247,14 @@ class JsonObject : public Internals::JsonPrintable<JsonObject>, | ||||
|   typename TypeTraits::EnableIf<!TypeTraits::IsArray<TString>::value, | ||||
|                                 bool>::type | ||||
|   containsKey(const TString& key) const { | ||||
|     return findNode<const TString&>(key) != NULL; | ||||
|     return findKey<const TString&>(key) != end(); | ||||
|   } | ||||
|   // | ||||
|   // bool containsKey(TKey); | ||||
|   // TKey = const char*, const char[N], const FlashStringHelper* | ||||
|   template <typename TString> | ||||
|   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. | ||||
| @@ -265,15 +265,18 @@ class JsonObject : public Internals::JsonPrintable<JsonObject>, | ||||
|   typename TypeTraits::EnableIf<!TypeTraits::IsArray<TString>::value, | ||||
|                                 void>::type | ||||
|   remove(const TString& key) { | ||||
|     removeNode(findNode<const TString&>(key)); | ||||
|     remove(findKey<const TString&>(key)); | ||||
|   } | ||||
|   // | ||||
|   // void remove(TKey); | ||||
|   // TKey = const char*, const char[N], const FlashStringHelper* | ||||
|   template <typename TString> | ||||
|   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. | ||||
|   // This object is meant to replace a NULL pointer. | ||||
| @@ -286,41 +289,44 @@ class JsonObject : public Internals::JsonPrintable<JsonObject>, | ||||
|  private: | ||||
|   // Returns the list node that matches the specified key. | ||||
|   template <typename TStringRef> | ||||
|   node_type* findNode(TStringRef key) const { | ||||
|     for (node_type* node = _firstNode; node; node = node->next) { | ||||
|       if (Internals::StringTraits<TStringRef>::equals(key, node->content.key)) | ||||
|         return node; | ||||
|   iterator findKey(TStringRef key) { | ||||
|     iterator it; | ||||
|     for (it = begin(); it != end(); ++it) { | ||||
|       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> | ||||
|   typename Internals::JsonVariantAs<TValue>::type get_impl( | ||||
|       TStringRef key) const { | ||||
|     node_type* node = findNode<TStringRef>(key); | ||||
|     return node ? node->content.value.as<TValue>() | ||||
|                 : Internals::JsonVariantDefault<TValue>::get(); | ||||
|     const_iterator it = findKey<TStringRef>(key); | ||||
|     return it != end() ? it->value.as<TValue>() | ||||
|                        : Internals::JsonVariantDefault<TValue>::get(); | ||||
|   } | ||||
|  | ||||
|   template <typename TStringRef, typename TValueRef> | ||||
|   bool set_impl(TStringRef key, TValueRef value) { | ||||
|     node_type* node = findNode<TStringRef>(key); | ||||
|     if (!node) { | ||||
|       node = addNewNode(); | ||||
|       if (!node) return false; | ||||
|     iterator it = findKey<TStringRef>(key); | ||||
|     if (it == end()) { | ||||
|       it = Internals::List<JsonPair>::add(); | ||||
|       if (it == end()) return false; | ||||
|  | ||||
|       bool key_ok = Internals::ValueSetter<TStringRef>::set( | ||||
|           _buffer, node->content.key, key); | ||||
|       bool key_ok = | ||||
|           Internals::ValueSetter<TStringRef>::set(_buffer, it->key, key); | ||||
|       if (!key_ok) return false; | ||||
|     } | ||||
|     return Internals::ValueSetter<TValueRef>::set(_buffer, node->content.value, | ||||
|                                                   value); | ||||
|     return Internals::ValueSetter<TValueRef>::set(_buffer, it->value, value); | ||||
|   } | ||||
|  | ||||
|   template <typename TStringRef, typename TValue> | ||||
|   bool is_impl(TStringRef key) const { | ||||
|     node_type* node = findNode<TStringRef>(key); | ||||
|     return node ? node->content.value.is<TValue>() : false; | ||||
|     const_iterator it = findKey<TStringRef>(key); | ||||
|     return it != end() ? it->value.is<TValue>() : false; | ||||
|   } | ||||
|  | ||||
|   template <typename TStringRef> | ||||
|   | ||||
| @@ -22,7 +22,7 @@ class JsonArray_Remove_Tests : public ::testing::Test { | ||||
|  | ||||
| #define TEST_(name) TEST_F(JsonArray_Remove_Tests, name) | ||||
|  | ||||
| TEST_(RemoveFirstElement) { | ||||
| TEST_(RemoveFirstByIndex) { | ||||
|   _array.removeAt(0); | ||||
|  | ||||
|   EXPECT_EQ(2, _array.size()); | ||||
| @@ -30,7 +30,7 @@ TEST_(RemoveFirstElement) { | ||||
|   EXPECT_STREQ("three", _array[1]); | ||||
| } | ||||
|  | ||||
| TEST_(RemoveMiddleElement) { | ||||
| TEST_(RemoveMiddleByIndex) { | ||||
|   _array.removeAt(1); | ||||
|  | ||||
|   EXPECT_EQ(2, _array.size()); | ||||
| @@ -38,10 +38,40 @@ TEST_(RemoveMiddleElement) { | ||||
|   EXPECT_STREQ("three", _array[1]); | ||||
| } | ||||
|  | ||||
| TEST_(RemoveLastElement) { | ||||
| TEST_(RemoveLastByIndex) { | ||||
|   _array.removeAt(2); | ||||
|  | ||||
|   EXPECT_EQ(2, _array.size()); | ||||
|   EXPECT_STREQ("one", _array[0]); | ||||
|   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()); | ||||
| } | ||||
|  | ||||
| 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