diff --git a/CHANGELOG.md b/CHANGELOG.md index 688e49b6..765ef5e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ HEAD * `JsonArray::copyFrom()` accepts `JsonArrayConst` * `JsonVariant::set()` accepts `JsonArrayConst` and `JsonObjectConst` * `JsonDocument` was missing in the ArduinoJson namespace +* Added `memoryUsage()` to `JsonArray`, `JsonObject`, and `JsonVariant` > ### BREAKING CHANGES > diff --git a/src/ArduinoJson/Array/ArrayRef.hpp b/src/ArduinoJson/Array/ArrayRef.hpp index 85fc29e8..f993c832 100644 --- a/src/ArduinoJson/Array/ArrayRef.hpp +++ b/src/ArduinoJson/Array/ArrayRef.hpp @@ -34,6 +34,10 @@ class ArrayRefBase { return VariantConstRef(_data ? _data->get(index) : 0); } + FORCE_INLINE size_t memoryUsage() const { + return _data ? _data->memoryUsage() : 0; + } + FORCE_INLINE size_t size() const { return _data ? _data->size() : 0; } diff --git a/src/ArduinoJson/Collection/CollectionData.hpp b/src/ArduinoJson/Collection/CollectionData.hpp index 54bd12b8..3f5f0b83 100644 --- a/src/ArduinoJson/Collection/CollectionData.hpp +++ b/src/ArduinoJson/Collection/CollectionData.hpp @@ -55,6 +55,7 @@ class CollectionData { void remove(VariantSlot *slot); + size_t memoryUsage() const; size_t size() const; private: diff --git a/src/ArduinoJson/Collection/CollectionImpl.hpp b/src/ArduinoJson/Collection/CollectionImpl.hpp index f4ed312a..8dbe42f3 100644 --- a/src/ArduinoJson/Collection/CollectionImpl.hpp +++ b/src/ArduinoJson/Collection/CollectionImpl.hpp @@ -138,6 +138,15 @@ inline void CollectionData::remove(size_t index) { remove(getSlot(index)); } +inline size_t CollectionData::memoryUsage() const { + size_t total = 0; + for (VariantSlot* s = _head; s; s = s->next()) { + total += sizeof(VariantSlot) + s->data()->memoryUsage(); + if (s->ownsKey()) total += strlen(s->key()) + 1; + } + return total; +} + inline size_t CollectionData::size() const { return slotSize(_head); } diff --git a/src/ArduinoJson/Object/ObjectRef.hpp b/src/ArduinoJson/Object/ObjectRef.hpp index 2a9edba9..b2792cdc 100644 --- a/src/ArduinoJson/Object/ObjectRef.hpp +++ b/src/ArduinoJson/Object/ObjectRef.hpp @@ -42,6 +42,10 @@ class ObjectRefBase { return _data == 0; } + FORCE_INLINE size_t memoryUsage() const { + return _data ? _data->memoryUsage() : 0; + } + FORCE_INLINE size_t size() const { return _data ? _data->size() : 0; } diff --git a/src/ArduinoJson/Variant/VariantData.hpp b/src/ArduinoJson/Variant/VariantData.hpp index 69361a8f..c17b5bd4 100644 --- a/src/ArduinoJson/Variant/VariantData.hpp +++ b/src/ArduinoJson/Variant/VariantData.hpp @@ -266,6 +266,20 @@ class VariantData { return _content.asCollection; } + size_t memoryUsage() const { + switch (type()) { + case VALUE_IS_OWNED_STRING: + return strlen(_content.asString) + 1; + case VALUE_IS_OWNED_RAW: + return _content.asRaw.size; + case VALUE_IS_OBJECT: + case VALUE_IS_ARRAY: + return _content.asCollection.memoryUsage(); + default: + return 0; + } + } + size_t size() const { if (type() == VALUE_IS_OBJECT || type() == VALUE_IS_ARRAY) return _content.asCollection.size(); diff --git a/src/ArduinoJson/Variant/VariantRef.hpp b/src/ArduinoJson/Variant/VariantRef.hpp index 6b8cd98b..8578e86f 100644 --- a/src/ArduinoJson/Variant/VariantRef.hpp +++ b/src/ArduinoJson/Variant/VariantRef.hpp @@ -95,6 +95,10 @@ class VariantRefBase { return variantIsNull(_data); } + FORCE_INLINE size_t memoryUsage() const { + return _data ? _data->memoryUsage() : 0; + } + size_t size() const { return variantSize(_data); } diff --git a/test/JsonArray/CMakeLists.txt b/test/JsonArray/CMakeLists.txt index 8a603965..851be713 100644 --- a/test/JsonArray/CMakeLists.txt +++ b/test/JsonArray/CMakeLists.txt @@ -11,6 +11,7 @@ add_executable(JsonArrayTests get.cpp isNull.cpp iterator.cpp + memoryUsage.cpp remove.cpp size.cpp std_string.cpp diff --git a/test/JsonArray/memoryUsage.cpp b/test/JsonArray/memoryUsage.cpp new file mode 100644 index 00000000..f7cd0160 --- /dev/null +++ b/test/JsonArray/memoryUsage.cpp @@ -0,0 +1,42 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 +// MIT License + +#include +#include + +TEST_CASE("JsonArray::memoryUsage()") { + DynamicJsonDocument doc(4096); + JsonArray arr = doc.to(); + + SECTION("return 0 if uninitialized") { + JsonArray unitialized; + REQUIRE(unitialized.memoryUsage() == 0); + } + + SECTION("JSON_ARRAY_SIZE(0) if empty") { + REQUIRE(arr.memoryUsage() == JSON_ARRAY_SIZE(0)); + } + + SECTION("JSON_ARRAY_SIZE(1) after add") { + arr.add("hello"); + REQUIRE(arr.memoryUsage() == JSON_ARRAY_SIZE(1)); + } + + SECTION("includes the size of the string") { + arr.add(std::string("hello")); + REQUIRE(arr.memoryUsage() == JSON_ARRAY_SIZE(1) + 6); + } + + SECTION("includes the size of the nested array") { + JsonArray nested = arr.createNestedArray(); + nested.add(42); + REQUIRE(arr.memoryUsage() == 2 * JSON_ARRAY_SIZE(1)); + } + + SECTION("includes the size of the nested arrect") { + JsonObject nested = arr.createNestedObject(); + nested["hello"] = "world"; + REQUIRE(arr.memoryUsage() == JSON_OBJECT_SIZE(1) + JSON_ARRAY_SIZE(1)); + } +} diff --git a/test/JsonArray/size.cpp b/test/JsonArray/size.cpp index 818b2daa..60a4f7c9 100644 --- a/test/JsonArray/size.cpp +++ b/test/JsonArray/size.cpp @@ -9,7 +9,7 @@ TEST_CASE("JsonArray::size()") { DynamicJsonDocument doc(4096); JsonArray array = doc.to(); - SECTION("InitialSizeIsZero") { + SECTION("returns 0 is empty") { REQUIRE(0U == array.size()); } diff --git a/test/JsonObject/CMakeLists.txt b/test/JsonObject/CMakeLists.txt index dde3a3f7..389fec63 100644 --- a/test/JsonObject/CMakeLists.txt +++ b/test/JsonObject/CMakeLists.txt @@ -11,6 +11,7 @@ add_executable(JsonObjectTests invalid.cpp isNull.cpp iterator.cpp + memoryUsage.cpp remove.cpp size.cpp std_string.cpp diff --git a/test/JsonObject/memoryUsage.cpp b/test/JsonObject/memoryUsage.cpp new file mode 100644 index 00000000..51b27525 --- /dev/null +++ b/test/JsonObject/memoryUsage.cpp @@ -0,0 +1,43 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 +// MIT License + +#include +#include +#include + +TEST_CASE("JsonObject::memoryUsage()") { + DynamicJsonDocument doc(4096); + JsonObject obj = doc.to(); + + SECTION("return 0 if uninitialized") { + JsonObject unitialized; + REQUIRE(unitialized.memoryUsage() == 0); + } + + SECTION("JSON_OBJECT_SIZE(0) for empty object") { + REQUIRE(obj.memoryUsage() == JSON_OBJECT_SIZE(0)); + } + + SECTION("JSON_OBJECT_SIZE(1) after add") { + obj["hello"] = 42; + REQUIRE(obj.memoryUsage() == JSON_OBJECT_SIZE(1)); + } + + SECTION("includes the size of the key") { + obj[std::string("hello")] = 42; + REQUIRE(obj.memoryUsage() == JSON_OBJECT_SIZE(1) + 6); + } + + SECTION("includes the size of the nested array") { + JsonArray nested = obj.createNestedArray("nested"); + nested.add(42); + REQUIRE(obj.memoryUsage() == JSON_OBJECT_SIZE(1) + JSON_ARRAY_SIZE(1)); + } + + SECTION("includes the size of the nested object") { + JsonObject nested = obj.createNestedObject("nested"); + nested["hello"] = "world"; + REQUIRE(obj.memoryUsage() == 2 * JSON_OBJECT_SIZE(1)); + } +} diff --git a/test/JsonVariant/CMakeLists.txt b/test/JsonVariant/CMakeLists.txt index c9ec9964..8ef62fb6 100644 --- a/test/JsonVariant/CMakeLists.txt +++ b/test/JsonVariant/CMakeLists.txt @@ -9,6 +9,7 @@ add_executable(JsonVariantTests get.cpp is.cpp isnull.cpp + memoryUsage.cpp misc.cpp or.cpp set.cpp diff --git a/test/JsonVariant/memoryUsage.cpp b/test/JsonVariant/memoryUsage.cpp new file mode 100644 index 00000000..83f006c8 --- /dev/null +++ b/test/JsonVariant/memoryUsage.cpp @@ -0,0 +1,39 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 +// MIT License + +#include +#include +#include + +TEST_CASE("JsonVariant::memoryUsage()") { + DynamicJsonDocument doc(4096); + JsonVariant var = doc.to(); + + SECTION("returns 0 if uninitialized") { + JsonVariant unitialized; + REQUIRE(unitialized.memoryUsage() == 0); + } + + SECTION("returns size of object") { + JsonObject obj = var.to(); + obj["hello"] = 42; + REQUIRE(var.memoryUsage() == JSON_OBJECT_SIZE(1)); + } + + SECTION("returns size of array") { + JsonArray arr = var.to(); + arr.add(42); + REQUIRE(var.memoryUsage() == JSON_ARRAY_SIZE(1)); + } + + SECTION("returns size of owned string") { + var.set(std::string("hello")); + REQUIRE(var.memoryUsage() == 6); + } + + SECTION("returns size of owned raw") { + var.set(serialized(std::string("hello"))); + REQUIRE(var.memoryUsage() == 5); + } +}