diff --git a/CHANGELOG.md b/CHANGELOG.md index 55fa89b0..ea84b2f8 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 8197d0d3..e34b6233 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 7789e6fd..b070af54 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 a2dbec69..5f7c66f9 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 aede1817..a89b45e8 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 6136cf0a..ab0b8182 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 0a8063e7..084f66ee 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 7b1081af..bf5f6100 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 5dd29315..cf3a438d 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 64a78f78..87ddd409 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 00000000..aa51a225 --- /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 60c70c8c..e948c656 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 00000000..c0acdc74 --- /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); + } +}