From dee8c8e242f609d91e42111f1dbc327fddb4ff98 Mon Sep 17 00:00:00 2001 From: Benoit Blanchon Date: Sun, 17 Mar 2019 21:48:10 +0100 Subject: [PATCH 001/584] Added `BasicJsonDocument` to support custom allocator (issue #876) --- CHANGELOG.md | 1 + src/ArduinoJson.hpp | 1 + .../Document/BasicJsonDocument.hpp | 89 +++++++++++++++++++ .../Document/DynamicJsonDocument.hpp | 60 ++----------- test/JsonDocument/BasicJsonDocument.cpp | 49 ++++++++++ test/JsonDocument/CMakeLists.txt | 1 + 6 files changed, 149 insertions(+), 52 deletions(-) create mode 100644 src/ArduinoJson/Document/BasicJsonDocument.hpp create mode 100644 test/JsonDocument/BasicJsonDocument.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index e2009f11d..b329d4415 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ HEAD * Added overflow handling in `JsonVariant::as()` and `JsonVariant::is()`. - `as()` returns `0` if the integer `T` overflows - `is()` returns `false` if the integer `T` overflows +* Added `BasicJsonDocument` to support custom allocator (issue #876) v6.9.1 (2019-03-01) ------ diff --git a/src/ArduinoJson.hpp b/src/ArduinoJson.hpp index 5188d5ea0..cb3704ee6 100644 --- a/src/ArduinoJson.hpp +++ b/src/ArduinoJson.hpp @@ -50,6 +50,7 @@ typedef ARDUINOJSON_NAMESPACE::String JsonString; typedef ARDUINOJSON_NAMESPACE::UInt JsonUInt; typedef ARDUINOJSON_NAMESPACE::VariantConstRef JsonVariantConst; typedef ARDUINOJSON_NAMESPACE::VariantRef JsonVariant; +using ARDUINOJSON_NAMESPACE::BasicJsonDocument; using ARDUINOJSON_NAMESPACE::copyArray; using ARDUINOJSON_NAMESPACE::DeserializationError; using ARDUINOJSON_NAMESPACE::deserializeJson; diff --git a/src/ArduinoJson/Document/BasicJsonDocument.hpp b/src/ArduinoJson/Document/BasicJsonDocument.hpp new file mode 100644 index 000000000..3919cb431 --- /dev/null +++ b/src/ArduinoJson/Document/BasicJsonDocument.hpp @@ -0,0 +1,89 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2019 +// MIT License + +#pragma once + +#include "JsonDocument.hpp" + +namespace ARDUINOJSON_NAMESPACE { + +template +class AllocatorOwner { + protected: + AllocatorOwner() {} + AllocatorOwner(const AllocatorOwner& src) : _allocator(src._allocator) {} + AllocatorOwner(TAllocator allocator) : _allocator(allocator) {} + + void* allocate(size_t n) { + return _allocator.allocate(n); + } + + void deallocate(void* p) { + _allocator.deallocate(p); + } + + private: + TAllocator _allocator; +}; + +template +class BasicJsonDocument : AllocatorOwner, public JsonDocument { + public: + explicit BasicJsonDocument(size_t capa, TAllocator allocator = TAllocator()) + : AllocatorOwner(allocator), JsonDocument(allocPool(capa)) {} + + BasicJsonDocument(const BasicJsonDocument& src) + : AllocatorOwner(src), + JsonDocument(allocPool(src.memoryUsage())) { + set(src); + } + + template + BasicJsonDocument(const T& src, + typename enable_if::value>::type* = 0) + : JsonDocument(allocPool(src.memoryUsage())) { + set(src); + } + + // disambiguate + BasicJsonDocument(VariantRef src) + : JsonDocument(allocPool(src.memoryUsage())) { + set(src); + } + + ~BasicJsonDocument() { + freePool(); + } + + BasicJsonDocument& operator=(const BasicJsonDocument& src) { + reallocPoolIfTooSmall(src.memoryUsage()); + set(src); + return *this; + } + + template + BasicJsonDocument& operator=(const T& src) { + reallocPoolIfTooSmall(src.memoryUsage()); + set(src); + return *this; + } + + private: + MemoryPool allocPool(size_t requiredSize) { + size_t capa = addPadding(requiredSize); + return MemoryPool(reinterpret_cast(this->allocate(capa)), capa); + } + + void reallocPoolIfTooSmall(size_t requiredSize) { + if (requiredSize <= capacity()) return; + freePool(); + replacePool(allocPool(addPadding(requiredSize))); + } + + void freePool() { + this->deallocate(memoryPool().buffer()); + } +}; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Document/DynamicJsonDocument.hpp b/src/ArduinoJson/Document/DynamicJsonDocument.hpp index a52f65095..380adae14 100644 --- a/src/ArduinoJson/Document/DynamicJsonDocument.hpp +++ b/src/ArduinoJson/Document/DynamicJsonDocument.hpp @@ -4,66 +4,22 @@ #pragma once -#include "JsonDocument.hpp" +#include "BasicJsonDocument.hpp" #include // malloc, free namespace ARDUINOJSON_NAMESPACE { -class DynamicJsonDocument : public JsonDocument { - public: - explicit DynamicJsonDocument(size_t capa) : JsonDocument(allocPool(capa)) {} - - DynamicJsonDocument(const DynamicJsonDocument& src) - : JsonDocument(allocPool(src.memoryUsage())) { - set(src); - } - - template - DynamicJsonDocument(const T& src, - typename enable_if::value>::type* = 0) - : JsonDocument(allocPool(src.memoryUsage())) { - set(src); - } - - // disambiguate - DynamicJsonDocument(VariantRef src) - : JsonDocument(allocPool(src.memoryUsage())) { - set(src); - } - - ~DynamicJsonDocument() { - freePool(); - } - - DynamicJsonDocument& operator=(const DynamicJsonDocument& src) { - reallocPoolIfTooSmall(src.memoryUsage()); - set(src); - return *this; - } - - template - DynamicJsonDocument& operator=(const T& src) { - reallocPoolIfTooSmall(src.memoryUsage()); - set(src); - return *this; - } - - private: - MemoryPool allocPool(size_t requiredSize) { - size_t capa = addPadding(requiredSize); - return MemoryPool(reinterpret_cast(malloc(capa)), capa); - } - - void reallocPoolIfTooSmall(size_t requiredSize) { - if (requiredSize <= capacity()) return; - freePool(); - replacePool(allocPool(addPadding(requiredSize))); +struct DefaultAllocator { + void* allocate(size_t n) { + return malloc(n); } - void freePool() { - free(memoryPool().buffer()); + void deallocate(void* p) { + free(p); } }; +typedef BasicJsonDocument DynamicJsonDocument; + } // namespace ARDUINOJSON_NAMESPACE diff --git a/test/JsonDocument/BasicJsonDocument.cpp b/test/JsonDocument/BasicJsonDocument.cpp new file mode 100644 index 000000000..e31b0d74f --- /dev/null +++ b/test/JsonDocument/BasicJsonDocument.cpp @@ -0,0 +1,49 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2019 +// MIT License + +#include +#include // malloc, free +#include +#include + +using ARDUINOJSON_NAMESPACE::addPadding; + +class SpyingAllocator { + public: + SpyingAllocator(std::ostream& log) : _log(log) {} + + void* allocate(size_t n) { + _log << "A" << n; + return malloc(n); + } + void deallocate(void* p) { + _log << "F"; + free(p); + } + + private: + SpyingAllocator& operator=(const SpyingAllocator& src); + + std::ostream& _log; +}; + +typedef BasicJsonDocument MyJsonDocument; + +TEST_CASE("BasicJsonDocument") { + std::stringstream log; + + SECTION("Construct/Destruct") { + { MyJsonDocument doc(4096, log); } + REQUIRE(log.str() == "A4096F"); + } + + SECTION("Copy construct") { + { + MyJsonDocument doc1(4096, log); + doc1.set(std::string("The size of this string is 32!!")); + MyJsonDocument doc2(doc1); + } + REQUIRE(log.str() == "A4096A32FF"); + } +} diff --git a/test/JsonDocument/CMakeLists.txt b/test/JsonDocument/CMakeLists.txt index 04d7e227e..29d78dc67 100644 --- a/test/JsonDocument/CMakeLists.txt +++ b/test/JsonDocument/CMakeLists.txt @@ -4,6 +4,7 @@ add_executable(JsonDocumentTests add.cpp + BasicJsonDocument.cpp createNested.cpp DynamicJsonDocument.cpp isNull.cpp From c8e49a7e4e55e98c9cbaf43a23c5d1d58300673e Mon Sep 17 00:00:00 2001 From: Benoit Blanchon Date: Fri, 22 Mar 2019 08:40:46 +0100 Subject: [PATCH 002/584] Added `JsonDocument::containsKey()` (issue #938) --- CHANGELOG.md | 1 + src/ArduinoJson/Document/JsonDocument.hpp | 15 ++++++++ test/JsonDocument/CMakeLists.txt | 1 + test/JsonDocument/containsKey.cpp | 44 +++++++++++++++++++++++ 4 files changed, 61 insertions(+) create mode 100644 test/JsonDocument/containsKey.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index b329d4415..55fa89b0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ HEAD - `as()` returns `0` if the integer `T` overflows - `is()` returns `false` if the integer `T` overflows * Added `BasicJsonDocument` to support custom allocator (issue #876) +* Added `JsonDocument::containsKey()` (issue #938) v6.9.1 (2019-03-01) ------ diff --git a/src/ArduinoJson/Document/JsonDocument.hpp b/src/ArduinoJson/Document/JsonDocument.hpp index c8ad783ad..7789e6fd3 100644 --- a/src/ArduinoJson/Document/JsonDocument.hpp +++ b/src/ArduinoJson/Document/JsonDocument.hpp @@ -124,6 +124,21 @@ class JsonDocument : public Visitable { return getOrAddMember(key).template to(); } + // containsKey(char*) const + // containsKey(const char*) const + // containsKey(const __FlashStringHelper*) const + template + bool containsKey(TChar* key) const { + return as().containsKey(key); + } + + // containsKey(const std::string&) const + // containsKey(const String&) const + template + bool containsKey(const TString& key) const { + return as().containsKey(key); + } + // operator[](const std::string&) // operator[](const String&) template diff --git a/test/JsonDocument/CMakeLists.txt b/test/JsonDocument/CMakeLists.txt index 29d78dc67..2bf05cf92 100644 --- a/test/JsonDocument/CMakeLists.txt +++ b/test/JsonDocument/CMakeLists.txt @@ -5,6 +5,7 @@ add_executable(JsonDocumentTests add.cpp BasicJsonDocument.cpp + containsKey.cpp createNested.cpp DynamicJsonDocument.cpp isNull.cpp diff --git a/test/JsonDocument/containsKey.cpp b/test/JsonDocument/containsKey.cpp new file mode 100644 index 000000000..6b48831c3 --- /dev/null +++ b/test/JsonDocument/containsKey.cpp @@ -0,0 +1,44 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2019 +// MIT License + +#include +#include + +TEST_CASE("JsonDocument::containsKey()") { + DynamicJsonDocument doc(4096); + + SECTION("returns true on object") { + doc["hello"] = "world"; + + REQUIRE(doc.containsKey("hello") == true); + } + + SECTION("returns true when value is null") { + doc["hello"] = static_cast(0); + + REQUIRE(doc.containsKey("hello") == true); + } + + SECTION("returns true when key is a std::string") { + doc["hello"] = "world"; + + REQUIRE(doc.containsKey(std::string("hello")) == true); + } + + SECTION("returns false on object") { + doc["world"] = "hello"; + + REQUIRE(doc.containsKey("hello") == false); + } + + SECTION("returns false on array") { + doc.add("hello"); + + REQUIRE(doc.containsKey("hello") == false); + } + + SECTION("returns false on null") { + REQUIRE(doc.containsKey("hello") == false); + } +} From 6ec5ba521b09ddaca03f5887d1a15511841b0f2f Mon Sep 17 00:00:00 2001 From: Benoit Blanchon Date: Fri, 22 Mar 2019 09:00:00 +0100 Subject: [PATCH 003/584] Added `JsonVariant::containsKey()` --- CHANGELOG.md | 1 + src/ArduinoJson/Array/ArrayRef.hpp | 4 +++ src/ArduinoJson/Document/JsonDocument.hpp | 41 ++++++++++++++++------ src/ArduinoJson/Object/MemberProxy.hpp | 6 ++-- src/ArduinoJson/Object/ObjectFunctions.hpp | 5 --- src/ArduinoJson/Object/ObjectImpl.hpp | 14 ++++++++ src/ArduinoJson/Object/ObjectRef.hpp | 30 ++++++++-------- src/ArduinoJson/Object/ObjectShortcuts.hpp | 13 +++++++ src/ArduinoJson/Variant/VariantRef.hpp | 4 +++ test/JsonVariant/CMakeLists.txt | 1 + test/JsonVariant/containsKey.cpp | 28 +++++++++++++++ test/MemberProxy/CMakeLists.txt | 1 + test/MemberProxy/containsKey.cpp | 27 ++++++++++++++ 13 files changed, 142 insertions(+), 33 deletions(-) create mode 100644 test/JsonVariant/containsKey.cpp create mode 100644 test/MemberProxy/containsKey.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 55fa89b0e..ea84b2f8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ HEAD - `is()` returns `false` if the integer `T` overflows * Added `BasicJsonDocument` to support custom allocator (issue #876) * Added `JsonDocument::containsKey()` (issue #938) +* Added `JsonVariant::containsKey()` v6.9.1 (2019-03-01) ------ diff --git a/src/ArduinoJson/Array/ArrayRef.hpp b/src/ArduinoJson/Array/ArrayRef.hpp index 8197d0d37..e34b62335 100644 --- a/src/ArduinoJson/Array/ArrayRef.hpp +++ b/src/ArduinoJson/Array/ArrayRef.hpp @@ -78,6 +78,10 @@ class ArrayConstRef : public ArrayRefBase, } FORCE_INLINE VariantConstRef operator[](size_t index) const { + return getElement(index); + } + + FORCE_INLINE VariantConstRef getElement(size_t index) const { return VariantConstRef(_data ? _data->get(index) : 0); } }; diff --git a/src/ArduinoJson/Document/JsonDocument.hpp b/src/ArduinoJson/Document/JsonDocument.hpp index 7789e6fd3..b070af548 100644 --- a/src/ArduinoJson/Document/JsonDocument.hpp +++ b/src/ArduinoJson/Document/JsonDocument.hpp @@ -129,14 +129,14 @@ class JsonDocument : public Visitable { // containsKey(const __FlashStringHelper*) const template bool containsKey(TChar* key) const { - return as().containsKey(key); + return !getMember(key).isUndefined(); } // containsKey(const std::string&) const // containsKey(const String&) const template bool containsKey(const TString& key) const { - return as().containsKey(key); + return !getMember(key).isUndefined(); } // operator[](const std::string&) @@ -165,7 +165,7 @@ class JsonDocument : public Visitable { FORCE_INLINE typename enable_if::value, VariantConstRef>::type operator[](const TString& key) const { - return getVariant()[key]; + return getMember(key); } // operator[](char*) const @@ -175,7 +175,7 @@ class JsonDocument : public Visitable { FORCE_INLINE typename enable_if::value, VariantConstRef>::type operator[](TChar* key) const { - return getVariant()[key]; + return getMember(key); } FORCE_INLINE ElementProxy operator[](size_t index) { @@ -183,23 +183,44 @@ class JsonDocument : public Visitable { } FORCE_INLINE VariantConstRef operator[](size_t index) const { - return VariantConstRef(_data.getElement(index)); + return getElement(index); } FORCE_INLINE VariantRef getElement(size_t index) { return VariantRef(&_pool, _data.getElement(index)); } - // getMember(char*) const - // getMember(const char*) const - // getMember(const __FlashStringHelper*) const + FORCE_INLINE VariantConstRef getElement(size_t index) const { + return VariantConstRef(_data.getElement(index)); + } + + // JsonVariantConst getMember(char*) const + // JsonVariantConst getMember(const char*) const + // JsonVariantConst getMember(const __FlashStringHelper*) const + template + FORCE_INLINE VariantConstRef getMember(TChar* key) const { + return VariantConstRef(_data.getMember(adaptString(key))); + } + + // JsonVariantConst getMember(const std::string&) const + // JsonVariantConst getMember(const String&) const + template + FORCE_INLINE + typename enable_if::value, VariantConstRef>::type + getMember(const TString& key) const { + return VariantConstRef(_data.getMember(adaptString(key))); + } + + // JsonVariant getMember(char*) + // JsonVariant getMember(const char*) + // JsonVariant getMember(const __FlashStringHelper*) template FORCE_INLINE VariantRef getMember(TChar* key) { return VariantRef(&_pool, _data.getMember(adaptString(key))); } - // getMember(const std::string&) const - // getMember(const String&) const + // JsonVariant getMember(const std::string&) + // JsonVariant getMember(const String&) template FORCE_INLINE typename enable_if::value, VariantRef>::type getMember(const TString& key) { diff --git a/src/ArduinoJson/Object/MemberProxy.hpp b/src/ArduinoJson/Object/MemberProxy.hpp index a2dbec691..5f7c66f93 100644 --- a/src/ArduinoJson/Object/MemberProxy.hpp +++ b/src/ArduinoJson/Object/MemberProxy.hpp @@ -40,9 +40,9 @@ class MemberProxy : public VariantOperators >, return *this; } - // operator=(char*) const - // operator=(const char*) const - // operator=(const __FlashStringHelper*) const + // operator=(char*) + // operator=(const char*) + // operator=(const __FlashStringHelper*) template FORCE_INLINE this_type &operator=(TChar *src) { getOrAddUpstreamMember().set(src); diff --git a/src/ArduinoJson/Object/ObjectFunctions.hpp b/src/ArduinoJson/Object/ObjectFunctions.hpp index aede18177..a89b45e88 100644 --- a/src/ArduinoJson/Object/ObjectFunctions.hpp +++ b/src/ArduinoJson/Object/ObjectFunctions.hpp @@ -16,11 +16,6 @@ void objectAccept(const CollectionData *obj, Visitor &visitor) { visitor.visitNull(); } -template -inline bool objectContainsKey(const CollectionData *obj, TAdaptedString key) { - return obj && obj->containsKey(key); -} - inline bool objectEquals(const CollectionData *lhs, const CollectionData *rhs) { if (lhs == rhs) return true; if (!lhs || !rhs) return false; diff --git a/src/ArduinoJson/Object/ObjectImpl.hpp b/src/ArduinoJson/Object/ObjectImpl.hpp index 6136cf0a9..ab0b81828 100644 --- a/src/ArduinoJson/Object/ObjectImpl.hpp +++ b/src/ArduinoJson/Object/ObjectImpl.hpp @@ -35,4 +35,18 @@ inline ObjectRef ObjectShortcuts::createNestedObject( TChar* key) const { return impl()->getOrAddMember(key).template to(); } + +template +template +inline typename enable_if::value, bool>::type +ObjectShortcuts::containsKey(const TString& key) const { + return !impl()->getMember(key).isUndefined(); +} + +template +template +inline typename enable_if::value, bool>::type +ObjectShortcuts::containsKey(TChar* key) const { + return !impl()->getMember(key).isUndefined(); +} } // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Object/ObjectRef.hpp b/src/ArduinoJson/Object/ObjectRef.hpp index 0a8063e7c..084f66ee3 100644 --- a/src/ArduinoJson/Object/ObjectRef.hpp +++ b/src/ArduinoJson/Object/ObjectRef.hpp @@ -27,21 +27,6 @@ class ObjectRefBase { objectAccept(_data, visitor); } - // containsKey(const std::string&) const - // containsKey(const String&) const - template - FORCE_INLINE bool containsKey(const TString& key) const { - return objectContainsKey(_data, adaptString(key)); - } - - // containsKey(char*) const - // containsKey(const char*) const - // containsKey(const __FlashStringHelper*) const - template - FORCE_INLINE bool containsKey(TChar* key) const { - return objectContainsKey(_data, adaptString(key)); - } - FORCE_INLINE bool isNull() const { return _data == 0; } @@ -83,6 +68,21 @@ class ObjectConstRef : public ObjectRefBase, return iterator(); } + // containsKey(const std::string&) const + // containsKey(const String&) const + template + FORCE_INLINE bool containsKey(const TString& key) const { + return !getMember(key).isUndefined(); + } + + // containsKey(char*) const + // containsKey(const char*) const + // containsKey(const __FlashStringHelper*) const + template + FORCE_INLINE bool containsKey(TChar* key) const { + return !getMember(key).isUndefined(); + } + // getMember(const std::string&) const // getMember(const String&) const template diff --git a/src/ArduinoJson/Object/ObjectShortcuts.hpp b/src/ArduinoJson/Object/ObjectShortcuts.hpp index 7b1081afb..bf5f61007 100644 --- a/src/ArduinoJson/Object/ObjectShortcuts.hpp +++ b/src/ArduinoJson/Object/ObjectShortcuts.hpp @@ -15,6 +15,19 @@ class MemberProxy; template class ObjectShortcuts { public: + // containsKey(const std::string&) const + // containsKey(const String&) const + template + FORCE_INLINE typename enable_if::value, bool>::type + containsKey(const TString &key) const; + + // containsKey(char*) const + // containsKey(const char*) const + // containsKey(const __FlashStringHelper*) const + template + FORCE_INLINE typename enable_if::value, bool>::type + containsKey(TChar *key) const; + // operator[](const std::string&) const // operator[](const String&) const template diff --git a/src/ArduinoJson/Variant/VariantRef.hpp b/src/ArduinoJson/Variant/VariantRef.hpp index 5dd293150..cf3a438de 100644 --- a/src/ArduinoJson/Variant/VariantRef.hpp +++ b/src/ArduinoJson/Variant/VariantRef.hpp @@ -96,6 +96,10 @@ class VariantRefBase { return variantIsNull(_data); } + FORCE_INLINE bool isUndefined() const { + return !_data; + } + FORCE_INLINE size_t memoryUsage() const { return _data ? _data->memoryUsage() : 0; } diff --git a/test/JsonVariant/CMakeLists.txt b/test/JsonVariant/CMakeLists.txt index 64a78f78e..87ddd409b 100644 --- a/test/JsonVariant/CMakeLists.txt +++ b/test/JsonVariant/CMakeLists.txt @@ -7,6 +7,7 @@ add_executable(JsonVariantTests as.cpp clear.cpp compare.cpp + containsKey.cpp copy.cpp createNested.cpp is.cpp diff --git a/test/JsonVariant/containsKey.cpp b/test/JsonVariant/containsKey.cpp new file mode 100644 index 000000000..aa51a2256 --- /dev/null +++ b/test/JsonVariant/containsKey.cpp @@ -0,0 +1,28 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2019 +// MIT License + +#include +#include +#include + +static const char* null = 0; + +TEST_CASE("JsonVariant::containsKey()") { + DynamicJsonDocument doc(4096); + JsonVariant var = doc.to(); + + SECTION("containsKey(const char*) returns true") { + var["hello"] = "world"; + + REQUIRE(var.containsKey("hello") == true); + REQUIRE(var.containsKey("world") == false); + } + + SECTION("containsKey(std::string) returns true") { + var["hello"] = "world"; + + REQUIRE(var.containsKey(std::string("hello")) == true); + REQUIRE(var.containsKey(std::string("world")) == false); + } +} diff --git a/test/MemberProxy/CMakeLists.txt b/test/MemberProxy/CMakeLists.txt index 60c70c8c0..e948c656b 100644 --- a/test/MemberProxy/CMakeLists.txt +++ b/test/MemberProxy/CMakeLists.txt @@ -5,6 +5,7 @@ add_executable(MemberProxyTests add.cpp clear.cpp + containsKey.cpp remove.cpp set.cpp size.cpp diff --git a/test/MemberProxy/containsKey.cpp b/test/MemberProxy/containsKey.cpp new file mode 100644 index 000000000..c0acdc742 --- /dev/null +++ b/test/MemberProxy/containsKey.cpp @@ -0,0 +1,27 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2019 +// MIT License + +#include +#include + +using namespace ARDUINOJSON_NAMESPACE; + +TEST_CASE("MemberProxy::containsKey()") { + DynamicJsonDocument doc(4096); + MemberProxy mp = doc["hello"]; + + SECTION("containsKey(const char*)") { + mp["key"] = "value"; + + REQUIRE(mp.containsKey("key") == true); + REQUIRE(mp.containsKey("key") == true); + } + + SECTION("containsKey(std::string)") { + mp["key"] = "value"; + + REQUIRE(mp.containsKey(std::string("key")) == true); + REQUIRE(mp.containsKey(std::string("key")) == true); + } +} From afd033e9c9a1c41a7877c15c222edffcb2ee5856 Mon Sep 17 00:00:00 2001 From: Benoit Blanchon Date: Fri, 22 Mar 2019 22:01:46 +0100 Subject: [PATCH 004/584] Set version to 6.10.0 --- CHANGELOG.md | 4 ++-- README.md | 2 +- library.json | 2 +- library.properties | 2 +- src/ArduinoJson/version.hpp | 6 +++--- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea84b2f8e..088e7f6d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ ArduinoJson: change log ======================= -HEAD ----- +v6.10.0 (2019-03-22) +------- * Fixed an integer overflow in the JSON deserializer * Added overflow handling in `JsonVariant::as()` and `JsonVariant::is()`. diff --git a/README.md b/README.md index 7fe2f9aa2..e5600796d 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ --- -[![arduino-library-badge](https://www.ardu-badge.com/badge/ArduinoJson.svg?version=6.9.1)](https://www.ardu-badge.com/ArduinoJson/6.9.1) +[![arduino-library-badge](https://www.ardu-badge.com/badge/ArduinoJson.svg?version=6.10.0)](https://www.ardu-badge.com/ArduinoJson/6.10.0) [![Build Status](https://ci.appveyor.com/api/projects/status/m7s53wav1l0abssg/branch/6.x?svg=true)](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/6.x) [![Build Status](https://travis-ci.org/bblanchon/ArduinoJson.svg?branch=6.x)](https://travis-ci.org/bblanchon/ArduinoJson) [![Coverage Status](https://coveralls.io/repos/github/bblanchon/ArduinoJson/badge.svg?branch=6.x)](https://coveralls.io/github/bblanchon/ArduinoJson?branch=6.x) diff --git a/library.json b/library.json index 4bba809cb..3ce67a39b 100644 --- a/library.json +++ b/library.json @@ -7,7 +7,7 @@ "type": "git", "url": "https://github.com/bblanchon/ArduinoJson.git" }, - "version": "6.9.1", + "version": "6.10.0", "authors": { "name": "Benoit Blanchon", "url": "https://blog.benoitblanchon.fr" diff --git a/library.properties b/library.properties index 1ab21944d..549f0b8b6 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ArduinoJson -version=6.9.1 +version=6.10.0 author=Benoit Blanchon maintainer=Benoit Blanchon sentence=An efficient and elegant JSON library for Arduino. diff --git a/src/ArduinoJson/version.hpp b/src/ArduinoJson/version.hpp index d1e7cc758..2b0011745 100644 --- a/src/ArduinoJson/version.hpp +++ b/src/ArduinoJson/version.hpp @@ -4,7 +4,7 @@ #pragma once -#define ARDUINOJSON_VERSION "6.9.1" +#define ARDUINOJSON_VERSION "6.10.0" #define ARDUINOJSON_VERSION_MAJOR 6 -#define ARDUINOJSON_VERSION_MINOR 9 -#define ARDUINOJSON_VERSION_REVISION 1 +#define ARDUINOJSON_VERSION_MINOR 10 +#define ARDUINOJSON_VERSION_REVISION 0 From 8cabda551d31c5dc4f8c179885146cc8d3aeb702 Mon Sep 17 00:00:00 2001 From: Benoit Blanchon Date: Fri, 22 Mar 2019 22:04:03 +0100 Subject: [PATCH 005/584] Fixed publish.sh not committing appveyor.yml --- appveyor.yml | 2 +- scripts/publish.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 35c80d77b..2ec5118bf 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 6.9.1.{build} +version: 6.10.0.{build} environment: matrix: - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 diff --git a/scripts/publish.sh b/scripts/publish.sh index 7e185e14c..2d2f06930 100644 --- a/scripts/publish.sh +++ b/scripts/publish.sh @@ -38,7 +38,7 @@ update_version_in_source () { } commit_new_version () { - git add src/ArduinoJson/version.hpp README.md CHANGELOG.md library.json library.properties + git add src/ArduinoJson/version.hpp README.md CHANGELOG.md library.json library.properties appveyor.yml git commit -m "Set version to $VERSION" } From 2fc220fa33ac03f069251c3d8bc822ece5940081 Mon Sep 17 00:00:00 2001 From: Benoit Blanchon Date: Sun, 24 Mar 2019 18:21:58 +0100 Subject: [PATCH 006/584] Fixed code samples in the README --- README.md | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index e5600796d..7a4bdc399 100644 --- a/README.md +++ b/README.md @@ -67,11 +67,10 @@ char json[] = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302 DynamicJsonDocument doc(1024); deserializeJson(doc, json); -JsonObjectRef root = doc.as(); -const char* sensor = root["sensor"]; -long time = root["time"]; -double latitude = root["data"][0]; -double longitude = root["data"][1]; +const char* sensor = doc["sensor"]; +long time = doc["time"]; +double latitude = doc["data"][0]; +double longitude = doc["data"][1]; ``` See the [tutorial on arduinojson.org](https://arduinojson.org/doc/decoding/?utm_source=github&utm_medium=readme) @@ -83,11 +82,10 @@ Here is a program that generates a JSON document with ArduinoJson: ```c++ DynamicJsonDocument doc(1024); -JsonObject root = doc.to(); -root["sensor"] = "gps"; -root["time"] = 1351824120; +doc["sensor"] = "gps"; +doc["time"] = 1351824120; -JsonArray data = root.createNestedArray("data"); +JsonArray data = doc.createNestedArray("data"); data.add(48.756080); data.add(2.302038); From d9109966139d99a0eb63cfb07b7b51794c177104 Mon Sep 17 00:00:00 2001 From: Benoit Blanchon Date: Sun, 24 Mar 2019 18:46:55 +0100 Subject: [PATCH 007/584] Travis: Added GCC 8 --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index 643afb2bd..00ed38aea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -42,6 +42,11 @@ matrix: sources: ['ubuntu-toolchain-r-test'] packages: ['g++-7'] env: SCRIPT=test _CC=gcc-7 _CXX=g++-7 + - addons: + apt: + sources: ['ubuntu-toolchain-r-test'] + packages: ['g++-8'] + env: SCRIPT=test _CC=gcc-8 _CXX=g++-8 - addons: apt: packages: ['g++-arm-linux-gnueabihf'] From eacad922df55a458f518e1798c58e80ec930b6b1 Mon Sep 17 00:00:00 2001 From: Benoit Blanchon Date: Sun, 24 Mar 2019 18:57:42 +0100 Subject: [PATCH 008/584] Travis: Added Clang 7 --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index 00ed38aea..0bba19c8d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -92,6 +92,11 @@ matrix: sources: ['ubuntu-toolchain-r-test','llvm-toolchain-trusty-6.0'] packages: ['clang-6.0'] env: SCRIPT=test _CC=clang-6.0 _CXX=clang++-6.0 + - addons: + apt: + sources: ['ubuntu-toolchain-r-test','llvm-toolchain-trusty-7'] + packages: ['clang-7'] + env: SCRIPT=test _CC=clang-7 _CXX=clang++-7 - env: SCRIPT=coverage - os: osx osx_image: xcode7.3 From ebc52a5a65d40bc935945f78547901c2442ee9ce Mon Sep 17 00:00:00 2001 From: Benoit Blanchon Date: Sun, 24 Mar 2019 18:58:19 +0100 Subject: [PATCH 009/584] Travis: Added Clang 8 --- .travis.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0bba19c8d..db996d701 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,7 +31,7 @@ matrix: apt: sources: ['ubuntu-toolchain-r-test'] packages: ['g++-5'] - env: SCRIPT=test _CC=gcc-5 _CXX=g++-5 # SANITIZE=undefined + env: SCRIPT=test _CC=gcc-5 _CXX=g++-5 # SANITIZE=undefined - addons: apt: sources: ['ubuntu-toolchain-r-test'] @@ -96,7 +96,12 @@ matrix: apt: sources: ['ubuntu-toolchain-r-test','llvm-toolchain-trusty-7'] packages: ['clang-7'] - env: SCRIPT=test _CC=clang-7 _CXX=clang++-7 + env: SCRIPT=test _CC=clang-7 _CXX=clang++-7 + - addons: + apt: + sources: ['ubuntu-toolchain-r-test','llvm-toolchain-trusty-8'] + packages: ['clang-8'] + env: SCRIPT=test _CC=clang-8 _CXX=clang++-8 - env: SCRIPT=coverage - os: osx osx_image: xcode7.3 From 9862048a58a81e45f6d4468a713ede099644c123 Mon Sep 17 00:00:00 2001 From: Benoit Blanchon Date: Sun, 24 Mar 2019 18:59:44 +0100 Subject: [PATCH 010/584] Fixed error "attributes are not allowed on a function-definition" --- CHANGELOG.md | 5 +++++ src/ArduinoJson/MsgPack/MsgPackSerializer.hpp | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 088e7f6d3..70a6e35c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ ArduinoJson: change log ======================= +HEAD +---- + +* Fixed error "attributes are not allowed on a function-definition" + v6.10.0 (2019-03-22) ------- diff --git a/src/ArduinoJson/MsgPack/MsgPackSerializer.hpp b/src/ArduinoJson/MsgPack/MsgPackSerializer.hpp index 10edb107d..e3ba6439f 100644 --- a/src/ArduinoJson/MsgPack/MsgPackSerializer.hpp +++ b/src/ArduinoJson/MsgPack/MsgPackSerializer.hpp @@ -24,8 +24,8 @@ class MsgPackSerializer { } template - typename enable_if::type visitFloat(T value64) - ARDUINOJSON_NO_SANITIZE("float-cast-overflow") { + ARDUINOJSON_NO_SANITIZE("float-cast-overflow") + typename enable_if::type visitFloat(T value64) { float value32 = float(value64); if (value32 == value64) { writeByte(0xCA); From 1c814d3bb657752d29a342ef20ce8074f8cde5d7 Mon Sep 17 00:00:00 2001 From: Benoit Blanchon Date: Sun, 24 Mar 2019 19:39:23 +0100 Subject: [PATCH 011/584] Fixed warning on Clang 8 --- test/JsonVariant/compare.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/test/JsonVariant/compare.cpp b/test/JsonVariant/compare.cpp index 49257cd76..e5ca0d5ba 100644 --- a/test/JsonVariant/compare.cpp +++ b/test/JsonVariant/compare.cpp @@ -229,8 +229,13 @@ TEST_CASE("JsonVariant comparisons") { } SECTION("Variants containing linked strings") { - variant1.set("0hello" + 1); // make sure they have - variant2.set("1hello" + 1); // different addresses + // create two identical strings at different addresses + char hello1[] = "hello"; + char hello2[] = "hello"; + REQUIRE(hello1 != hello2); + + variant1.set(hello1); + variant2.set(hello2); variant3.set("world"); REQUIRE(variant1 == variant2); @@ -253,8 +258,13 @@ TEST_CASE("JsonVariant comparisons") { } SECTION("Variants containing linked raws") { - variant1.set(serialized("0hello" + 1)); // make sure they have - variant2.set(serialized("1hello" + 1)); // different addresses + // create two identical strings at different addresses + char hello1[] = "hello"; + char hello2[] = "hello"; + REQUIRE(hello1 != hello2); + + variant1.set(serialized(hello1)); + variant2.set(serialized(hello2)); variant3.set(serialized("world")); REQUIRE(variant1 == variant2); From 6071bd07ec36320e60f3ec88b6d418bf95774c24 Mon Sep 17 00:00:00 2001 From: Benoit Blanchon Date: Sat, 20 Apr 2019 12:10:29 +0200 Subject: [PATCH 012/584] Added a link to the FAQ --- examples/JsonConfigFile/JsonConfigFile.ino | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/JsonConfigFile/JsonConfigFile.ino b/examples/JsonConfigFile/JsonConfigFile.ino index 39c96ab89..675da498b 100644 --- a/examples/JsonConfigFile/JsonConfigFile.ino +++ b/examples/JsonConfigFile/JsonConfigFile.ino @@ -21,7 +21,8 @@ // // Never use a JsonDocument to store the configuration! // A JsonDocument is *not* a permanent storage; it's only a temporary storage -// used during the serialization phase. +// used during the serialization phase. See: +// https://arduinojson.org/v6/faq/why-must-i-create-a-separate-config-object/ struct Config { char hostname[64]; int port; From 6011a2f51a1c28d78a1bd5578cfff405819fd47f Mon Sep 17 00:00:00 2001 From: Benoit Blanchon Date: Sat, 20 Apr 2019 15:12:29 +0200 Subject: [PATCH 013/584] Fixed `deserializeJson()` not being picky enough (fixes #969) --- CHANGELOG.md | 1 + src/ArduinoJson/Numbers/parseNumber.hpp | 3 +++ test/JsonDeserializer/invalid_input.cpp | 4 ++-- test/Numbers/parseNumber.cpp | 6 ++++++ 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 70a6e35c9..e70dbd7a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ HEAD ---- * Fixed error "attributes are not allowed on a function-definition" +* Fixed `deserializeJson()` not being picky enough (issue #969) v6.10.0 (2019-03-22) ------- diff --git a/src/ArduinoJson/Numbers/parseNumber.hpp b/src/ArduinoJson/Numbers/parseNumber.hpp index 35fb3468e..6db0d1bd9 100644 --- a/src/ArduinoJson/Numbers/parseNumber.hpp +++ b/src/ArduinoJson/Numbers/parseNumber.hpp @@ -140,6 +140,9 @@ inline ParsedNumber parseNumber(const char *s) { } exponent += exponent_offset; + // we should be at the end of the string, otherwise it's an error + if (*s != '\0') return return_type(); + TFloat result = traits::make_float(static_cast(mantissa), exponent); return is_negative ? -result : result; diff --git a/test/JsonDeserializer/invalid_input.cpp b/test/JsonDeserializer/invalid_input.cpp index 487fc6f84..ad1fac80f 100644 --- a/test/JsonDeserializer/invalid_input.cpp +++ b/test/JsonDeserializer/invalid_input.cpp @@ -7,8 +7,8 @@ #include TEST_CASE("Invalid JSON input") { - const char* testCases[] = {"'\\u'", "'\\u000g'", "'\\u000'", - "'\\u000G'", "'\\u000/'", "\\x1234"}; + const char* testCases[] = {"'\\u'", "'\\u000g'", "'\\u000'", "'\\u000G'", + "'\\u000/'", "\\x1234", "6a9"}; const size_t testCount = sizeof(testCases) / sizeof(testCases[0]); DynamicJsonDocument doc(4096); diff --git a/test/Numbers/parseNumber.cpp b/test/Numbers/parseNumber.cpp index 19638fedb..320aed736 100644 --- a/test/Numbers/parseNumber.cpp +++ b/test/Numbers/parseNumber.cpp @@ -16,3 +16,9 @@ TEST_CASE("Test uint32_t overflow") { REQUIRE(first.type() == uint8_t(VALUE_IS_POSITIVE_INTEGER)); REQUIRE(second.type() == uint8_t(VALUE_IS_FLOAT)); } + +TEST_CASE("Invalid value") { + ParsedNumber result = parseNumber("6a3"); + + REQUIRE(result.type() == uint8_t(VALUE_IS_NULL)); +} From 81bb3fce97ab91225910c14a0b8de8a1a3947fd5 Mon Sep 17 00:00:00 2001 From: Benoit Blanchon Date: Sat, 20 Apr 2019 15:45:38 +0200 Subject: [PATCH 014/584] Fixed build on platformio --- scripts/travis/platformio.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/scripts/travis/platformio.sh b/scripts/travis/platformio.sh index 4bb7a4c96..518262529 100755 --- a/scripts/travis/platformio.sh +++ b/scripts/travis/platformio.sh @@ -4,6 +4,18 @@ pip install --user platformio rm -r test +case $BOARD in +uno) + platformio lib install 868 # SD library + platformio lib install 872 # Ethernet library + ;; +esp01) + platformio lib uninstall 161 || true + platformio lib uninstall 868 || true + platformio lib uninstall 872 || true + ;; +esac + for EXAMPLE in $PWD/examples/*/*.ino; do platformio ci $EXAMPLE -l '.' -b $BOARD From 12f9aac4ea472bbdaf8bfd919d3c9a2f552b5097 Mon Sep 17 00:00:00 2001 From: Benoit Blanchon Date: Tue, 23 Apr 2019 08:46:18 +0200 Subject: [PATCH 015/584] Fixed "no matching function for call to write(uint8_t)" (closes #972) --- CHANGELOG.md | 1 + src/ArduinoJson/Configuration.hpp | 18 ++++++++++---- src/ArduinoJson/Serialization/serialize.hpp | 26 +++++++++++++-------- 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e70dbd7a3..51c38f65a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ HEAD * Fixed error "attributes are not allowed on a function-definition" * Fixed `deserializeJson()` not being picky enough (issue #969) +* Fixed error "no matching function for call to write(uint8_t)" (issue #972) v6.10.0 (2019-03-22) ------- diff --git a/src/ArduinoJson/Configuration.hpp b/src/ArduinoJson/Configuration.hpp index c34264bd5..662c4d7fa 100644 --- a/src/ArduinoJson/Configuration.hpp +++ b/src/ArduinoJson/Configuration.hpp @@ -88,28 +88,38 @@ #ifdef ARDUINO -// Enable support for Arduino String +// Enable support for Arduino's String class #ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING #define ARDUINOJSON_ENABLE_ARDUINO_STRING 1 #endif -// Enable support for Arduino Stream +// Enable support for Arduino's Stream class #ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM #define ARDUINOJSON_ENABLE_ARDUINO_STREAM 1 #endif +// Enable support for Arduino's Print class +#ifndef ARDUINOJSON_ENABLE_ARDUINO_PRINT +#define ARDUINOJSON_ENABLE_ARDUINO_PRINT 1 +#endif + #else // ARDUINO -// Disable support for Arduino String +// Enable support for Arduino's String class #ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING #define ARDUINOJSON_ENABLE_ARDUINO_STRING 0 #endif -// Disable support for Arduino Stream +// Enable support for Arduino's Stream class #ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM #define ARDUINOJSON_ENABLE_ARDUINO_STREAM 0 #endif +// Enable support for Arduino's Print class +#ifndef ARDUINOJSON_ENABLE_ARDUINO_PRINT +#define ARDUINOJSON_ENABLE_ARDUINO_PRINT 0 +#endif + #endif // ARDUINO #ifndef ARDUINOJSON_ENABLE_PROGMEM diff --git a/src/ArduinoJson/Serialization/serialize.hpp b/src/ArduinoJson/Serialization/serialize.hpp index ae47d1fb0..dfdd83731 100644 --- a/src/ArduinoJson/Serialization/serialize.hpp +++ b/src/ArduinoJson/Serialization/serialize.hpp @@ -14,32 +14,38 @@ namespace ARDUINOJSON_NAMESPACE { template