diff --git a/extras/tests/JsonDeserializer/input_types.cpp b/extras/tests/JsonDeserializer/input_types.cpp index d367e1ad..2ec7e698 100644 --- a/extras/tests/JsonDeserializer/input_types.cpp +++ b/extras/tests/JsonDeserializer/input_types.cpp @@ -3,11 +3,27 @@ // MIT License #include + #include #include #include "CustomReader.hpp" +TEST_CASE("deserializeJson(char*)") { + StaticJsonDocument<1024> doc; + + SECTION("should not duplicate strings") { + char input[] = "{\"hello\":\"world\"}"; + + DeserializationError err = deserializeJson(doc, input); + + REQUIRE(err == DeserializationError::Ok); + CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1)); + CHECK(doc.as().memoryUsage() == + JSON_OBJECT_SIZE(1)); // issue #1318 + } +} + TEST_CASE("deserializeJson(const std::string&)") { DynamicJsonDocument doc(4096); diff --git a/src/ArduinoJson/Json/JsonDeserializer.hpp b/src/ArduinoJson/Json/JsonDeserializer.hpp index e6a1d2c5..21196958 100644 --- a/src/ArduinoJson/Json/JsonDeserializer.hpp +++ b/src/ArduinoJson/Json/JsonDeserializer.hpp @@ -240,7 +240,7 @@ class JsonDeserializer { if (!slot) return DeserializationError::NoMemory; - slot->setOwnedKey(make_not_null(key)); + slot->setKey(key, typename TStringStorage::storage_policy()); variant = slot->data(); } @@ -339,7 +339,8 @@ class JsonDeserializer { if (err) return err; const char *value = _stringStorage.save(_pool); - variant.setOwnedString(make_not_null(value)); + variant.setString(make_not_null(value), + typename TStringStorage::storage_policy()); return DeserializationError::Ok; } diff --git a/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp b/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp index c18bd17c..bf9e2078 100644 --- a/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp +++ b/src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp @@ -233,7 +233,8 @@ class MsgPackDeserializer { const char *s = 0; // <- mute "maybe-uninitialized" (+4 bytes on AVR) DeserializationError err = readString(s, n); if (!err) - variant.setOwnedString(make_not_null(s)); + variant.setString(make_not_null(s), + typename TStringStorage::storage_policy()); return err; } @@ -303,7 +304,7 @@ class MsgPackDeserializer { DeserializationError err = parseKey(key); if (err) return err; - slot->setOwnedKey(make_not_null(key)); + slot->setKey(key, typename TStringStorage::storage_policy()); err = parse(*slot->data(), nestingLimit.decrement()); if (err) diff --git a/src/ArduinoJson/StringStorage/StringCopier.hpp b/src/ArduinoJson/StringStorage/StringCopier.hpp index 65828de9..e5558b7a 100644 --- a/src/ArduinoJson/StringStorage/StringCopier.hpp +++ b/src/ArduinoJson/StringStorage/StringCopier.hpp @@ -48,6 +48,8 @@ class StringCopier { return _ptr; } + typedef storage_policies::store_by_copy storage_policy; + private: char* _ptr; size_t _size; diff --git a/src/ArduinoJson/StringStorage/StringMover.hpp b/src/ArduinoJson/StringStorage/StringMover.hpp index 5fc4a595..724cbb87 100644 --- a/src/ArduinoJson/StringStorage/StringMover.hpp +++ b/src/ArduinoJson/StringStorage/StringMover.hpp @@ -5,6 +5,7 @@ #pragma once #include +#include namespace ARDUINOJSON_NAMESPACE { @@ -32,6 +33,8 @@ class StringMover { return _startPtr; } + typedef storage_policies::store_by_address storage_policy; + private: char* _writePtr; char* _startPtr; diff --git a/src/ArduinoJson/Variant/SlotFunctions.hpp b/src/ArduinoJson/Variant/SlotFunctions.hpp index abd06ba4..1213e586 100644 --- a/src/ArduinoJson/Variant/SlotFunctions.hpp +++ b/src/ArduinoJson/Variant/SlotFunctions.hpp @@ -30,7 +30,7 @@ template inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool*, storage_policies::store_by_address) { ARDUINOJSON_ASSERT(var); - var->setLinkedKey(make_not_null(key.data())); + var->setKey(key.data(), storage_policies::store_by_address()); return true; } @@ -41,7 +41,7 @@ inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool, if (!dup) return false; ARDUINOJSON_ASSERT(var); - var->setOwnedKey(make_not_null(dup)); + var->setKey(dup, storage_policies::store_by_copy()); return true; } diff --git a/src/ArduinoJson/Variant/VariantData.hpp b/src/ArduinoJson/Variant/VariantData.hpp index d8b44ef2..f501545b 100644 --- a/src/ArduinoJson/Variant/VariantData.hpp +++ b/src/ArduinoJson/Variant/VariantData.hpp @@ -101,7 +101,7 @@ class VariantData { case VALUE_IS_OBJECT: return toObject().copyFrom(src._content.asCollection, pool); case VALUE_IS_OWNED_STRING: - return setOwnedString(RamStringAdapter(src._content.asString), pool); + return setString(RamStringAdapter(src._content.asString), pool); case VALUE_IS_OWNED_RAW: return setOwnedRaw( serialized(src._content.asRaw.data, src._content.asRaw.size), pool); @@ -238,27 +238,24 @@ class VariantData { _content.asInteger = value; } - void setLinkedString(const char *value) { - if (value) { - setType(VALUE_IS_LINKED_STRING); - _content.asString = value; - } else { - setType(VALUE_IS_NULL); - } - } - void setNull() { setType(VALUE_IS_NULL); } - void setOwnedString(not_null s) { + void setString(not_null s, storage_policies::store_by_copy) { setType(VALUE_IS_OWNED_STRING); _content.asString = s.get(); } - bool setOwnedString(const char *s) { + void setString(not_null s, storage_policies::store_by_address) { + setType(VALUE_IS_LINKED_STRING); + _content.asString = s.get(); + } + + template + bool setString(const char *s, TStoragePolicy storage_policy) { if (s) { - setOwnedString(make_not_null(s)); + setString(make_not_null(s), storage_policy); return true; } else { setType(VALUE_IS_NULL); @@ -267,8 +264,30 @@ class VariantData { } template - bool setOwnedString(TAdaptedString value, MemoryPool *pool) { - return setOwnedString(pool->saveString(value)); + bool setString(TAdaptedString value, MemoryPool *pool) { + return setString(value, pool, typename TAdaptedString::storage_policy()); + } + + template + inline bool setString(TAdaptedString value, MemoryPool *pool, + storage_policies::decide_at_runtime) { + if (value.isStatic()) + return setString(value, pool, storage_policies::store_by_address()); + else + return setString(value, pool, storage_policies::store_by_copy()); + } + + template + inline bool setString(TAdaptedString value, MemoryPool *, + storage_policies::store_by_address) { + return setString(value.data(), storage_policies::store_by_address()); + } + + template + inline bool setString(TAdaptedString value, MemoryPool *pool, + storage_policies::store_by_copy) { + return setString(pool->saveString(value), + storage_policies::store_by_copy()); } CollectionData &toArray() { diff --git a/src/ArduinoJson/Variant/VariantFunctions.hpp b/src/ArduinoJson/Variant/VariantFunctions.hpp index 8aa2ec39..ea47911b 100644 --- a/src/ArduinoJson/Variant/VariantFunctions.hpp +++ b/src/ArduinoJson/Variant/VariantFunctions.hpp @@ -99,62 +99,18 @@ inline bool variantSetOwnedRaw(VariantData *var, SerializedValue value, return var != 0 && var->setOwnedRaw(value, pool); } -inline bool variantSetLinkedString(VariantData *var, const char *value) { - if (!var) - return false; - var->setLinkedString(value); - return true; -} - inline void variantSetNull(VariantData *var) { if (!var) return; var->setNull(); } -inline bool variantSetOwnedString(VariantData *var, char *value) { - if (!var) - return false; - var->setOwnedString(value); - return true; -} - -template -inline bool variantSetOwnedString(VariantData *var, TAdaptedString value, - MemoryPool *pool) { - return var != 0 && var->setOwnedString(value, pool); -} - -template -inline bool variantSetString(VariantData *var, TAdaptedString value, - MemoryPool *pool, - storage_policies::decide_at_runtime) { - if (value.isStatic()) - return variantSetString(var, value, pool, - storage_policies::store_by_address()); - else - return variantSetString(var, value, pool, - storage_policies::store_by_copy()); -} - template inline bool variantSetString(VariantData *var, TAdaptedString value, MemoryPool *pool) { - return variantSetString(var, value, pool, - typename TAdaptedString::storage_policy()); -} - -template -inline bool variantSetString(VariantData *var, TAdaptedString value, - MemoryPool *, storage_policies::store_by_address) { - return variantSetLinkedString(var, value.data()); -} - -template -inline bool variantSetString(VariantData *var, TAdaptedString value, - MemoryPool *pool, - storage_policies::store_by_copy) { - return variantSetOwnedString(var, value, pool); + if (!var) + return false; + return var->setString(value, pool); } template diff --git a/src/ArduinoJson/Variant/VariantSlot.hpp b/src/ArduinoJson/Variant/VariantSlot.hpp index 4af94dfa..bc5dd378 100644 --- a/src/ArduinoJson/Variant/VariantSlot.hpp +++ b/src/ArduinoJson/Variant/VariantSlot.hpp @@ -4,12 +4,13 @@ #pragma once +#include // int8_t, int16_t + #include #include +#include #include -#include // int8_t, int16_t - namespace ARDUINOJSON_NAMESPACE { typedef conditional::type VariantSlotDiff; @@ -69,14 +70,16 @@ class VariantSlot { _next = VariantSlotDiff(slot - this); } - void setOwnedKey(not_null k) { + void setKey(const char* k, storage_policies::store_by_copy) { + ARDUINOJSON_ASSERT(k != NULL); _flags |= KEY_IS_OWNED; - _key = k.get(); + _key = k; } - void setLinkedKey(not_null k) { + void setKey(const char* k, storage_policies::store_by_address) { + ARDUINOJSON_ASSERT(k != NULL); _flags &= VALUE_MASK; - _key = k.get(); + _key = k; } const char* key() const {