From ca24ed48f533b1131ecd0379ff5b90bf7f740b30 Mon Sep 17 00:00:00 2001 From: Benoit Blanchon Date: Sun, 21 Nov 2021 15:07:56 +0100 Subject: [PATCH] Separate string adapter from storage policy --- extras/tests/Cpp17/string_view.cpp | 7 +- extras/tests/Misc/StringAdapters.cpp | 185 ++++++++++++------ src/ArduinoJson/Collection/CollectionData.hpp | 9 +- src/ArduinoJson/Collection/CollectionImpl.hpp | 27 +-- src/ArduinoJson/Document/JsonDocument.hpp | 9 +- src/ArduinoJson/Memory/MemoryPool.hpp | 17 +- src/ArduinoJson/Object/ObjectFunctions.hpp | 7 +- src/ArduinoJson/Object/ObjectRef.hpp | 6 +- src/ArduinoJson/Polyfills/pgmspace.hpp | 16 ++ src/ArduinoJson/Polyfills/safe_strcmp.hpp | 33 ---- .../Strings/Adapters/ArduinoString.hpp | 24 +++ .../Strings/Adapters/ArduinoStringAdapter.hpp | 56 ------ .../Adapters/ConstRamStringAdapter.hpp | 58 ------ .../Strings/Adapters/FlashString.hpp | 80 ++++++++ .../Strings/Adapters/FlashStringAdapter.hpp | 55 ------ .../Strings/Adapters/JsonString.hpp | 20 ++ .../Strings/Adapters/JsonStringAdapter.hpp | 27 --- .../Strings/Adapters/RamString.hpp | 119 +++++++++++ .../Strings/Adapters/RamStringAdapter.hpp | 29 --- .../Adapters/SizedFlashStringAdapter.hpp | 56 ------ .../Adapters/SizedRamStringAdapter.hpp | 49 ----- .../Strings/Adapters/StdString.hpp | 23 +++ .../Strings/Adapters/StdStringAdapter.hpp | 51 ----- .../Strings/Adapters/StringView.hpp | 20 ++ .../Strings/Adapters/StringViewAdapter.hpp | 49 ----- src/ArduinoJson/Strings/IsString.hpp | 17 ++ src/ArduinoJson/Strings/StoragePolicy.hpp | 54 ++++- src/ArduinoJson/Strings/StoredString.hpp | 9 +- src/ArduinoJson/Strings/StringAdapter.hpp | 32 --- src/ArduinoJson/Strings/StringAdapters.hpp | 79 +++++++- src/ArduinoJson/Variant/ConverterImpl.hpp | 9 +- src/ArduinoJson/Variant/SlotFunctions.hpp | 42 ++-- src/ArduinoJson/Variant/VariantCompare.hpp | 8 +- src/ArduinoJson/Variant/VariantData.hpp | 88 +++------ src/ArduinoJson/Variant/VariantFunctions.hpp | 17 +- src/ArduinoJson/Variant/VariantImpl.hpp | 33 ++++ src/ArduinoJson/Variant/VariantSlot.hpp | 1 - 37 files changed, 697 insertions(+), 724 deletions(-) delete mode 100644 src/ArduinoJson/Polyfills/safe_strcmp.hpp create mode 100644 src/ArduinoJson/Strings/Adapters/ArduinoString.hpp delete mode 100644 src/ArduinoJson/Strings/Adapters/ArduinoStringAdapter.hpp delete mode 100644 src/ArduinoJson/Strings/Adapters/ConstRamStringAdapter.hpp create mode 100644 src/ArduinoJson/Strings/Adapters/FlashString.hpp delete mode 100644 src/ArduinoJson/Strings/Adapters/FlashStringAdapter.hpp create mode 100644 src/ArduinoJson/Strings/Adapters/JsonString.hpp delete mode 100644 src/ArduinoJson/Strings/Adapters/JsonStringAdapter.hpp create mode 100644 src/ArduinoJson/Strings/Adapters/RamString.hpp delete mode 100644 src/ArduinoJson/Strings/Adapters/RamStringAdapter.hpp delete mode 100644 src/ArduinoJson/Strings/Adapters/SizedFlashStringAdapter.hpp delete mode 100644 src/ArduinoJson/Strings/Adapters/SizedRamStringAdapter.hpp create mode 100644 src/ArduinoJson/Strings/Adapters/StdString.hpp delete mode 100644 src/ArduinoJson/Strings/Adapters/StdStringAdapter.hpp create mode 100644 src/ArduinoJson/Strings/Adapters/StringView.hpp delete mode 100644 src/ArduinoJson/Strings/Adapters/StringViewAdapter.hpp create mode 100644 src/ArduinoJson/Strings/IsString.hpp delete mode 100644 src/ArduinoJson/Strings/StringAdapter.hpp diff --git a/extras/tests/Cpp17/string_view.cpp b/extras/tests/Cpp17/string_view.cpp index 4e43692c..729c59ae 100644 --- a/extras/tests/Cpp17/string_view.cpp +++ b/extras/tests/Cpp17/string_view.cpp @@ -92,10 +92,9 @@ TEST_CASE("StringViewAdapter") { std::string_view str("bravoXXX", 5); auto adapter = adaptString(str); - CHECK(adapter.compare(NULL) > 0); - CHECK(adapter.compare("alpha") > 0); - CHECK(adapter.compare("bravo") == 0); - CHECK(adapter.compare("charlie") < 0); + CHECK(stringCompare(adapter, adaptString("alpha", 5)) > 0); + CHECK(stringCompare(adapter, adaptString("bravo", 5)) == 0); + CHECK(stringCompare(adapter, adaptString("charlie", 7)) < 0); CHECK(adapter.size() == 5); } diff --git a/extras/tests/Misc/StringAdapters.cpp b/extras/tests/Misc/StringAdapters.cpp index 4250f903..4cdedc13 100644 --- a/extras/tests/Misc/StringAdapters.cpp +++ b/extras/tests/Misc/StringAdapters.cpp @@ -15,106 +15,75 @@ using namespace ARDUINOJSON_NAMESPACE; -TEST_CASE("const char*") { +TEST_CASE("ZeroTerminatedRamString") { SECTION("null") { - StringAdapter adapter(NULL); + ZeroTerminatedRamString s = adaptString(static_cast(0)); - CHECK(adapter.compare("bravo") < 0); - CHECK(adapter.compare(NULL) == 0); - - CHECK(adapter.size() == 0); + CHECK(s.isNull() == true); + CHECK(s.size() == 0); } SECTION("non-null") { - StringAdapter adapter("bravo"); + ZeroTerminatedRamString s = adaptString("bravo"); - CHECK(adapter.compare(NULL) > 0); - CHECK(adapter.compare("alpha") > 0); - CHECK(adapter.compare("bravo") == 0); - CHECK(adapter.compare("charlie") < 0); - - CHECK(adapter.size() == 5); + CHECK(s.isNull() == false); + CHECK(s.size() == 5); } } -TEST_CASE("const char* + size") { +TEST_CASE("SizedRamString") { SECTION("null") { - StringAdapter adapter(NULL, 10); + SizedRamString s = adaptString(static_cast(0), 10); - CHECK(adapter.compare("bravo") < 0); - CHECK(adapter.compare(NULL) == 0); - - CHECK(adapter.size() == 10); + CHECK(s.isNull() == true); } SECTION("non-null") { - StringAdapter adapter("bravo", 5); + SizedRamString s = adaptString("bravo", 5); - CHECK(adapter.compare(NULL) > 0); - CHECK(adapter.compare("alpha") > 0); - CHECK(adapter.compare("bravo") == 0); - CHECK(adapter.compare("charlie") < 0); - - CHECK(adapter.size() == 5); + CHECK(s.isNull() == false); + CHECK(s.size() == 5); } } -TEST_CASE("const __FlashStringHelper*") { +TEST_CASE("FlashString") { SECTION("null") { - StringAdapter adapter(NULL); + FlashString s = adaptString(static_cast(0)); - CHECK(adapter.compare("bravo") < 0); - CHECK(adapter.compare(NULL) == 0); - - CHECK(adapter.size() == 0); + CHECK(s.isNull() == true); + CHECK(s.size() == 0); } SECTION("non-null") { - StringAdapter adapter = adaptString(F("bravo")); + FlashString s = adaptString(F("bravo")); - CHECK(adapter.compare(NULL) > 0); - CHECK(adapter.compare("alpha") > 0); - CHECK(adapter.compare("bravo") == 0); - CHECK(adapter.compare("charlie") < 0); - - CHECK(adapter.size() == 5); + CHECK(s.isNull() == false); + CHECK(s.size() == 5); } } TEST_CASE("std::string") { - std::string str("bravo"); - StringAdapter adapter(str); + std::string orig("bravo"); + SizedRamString s = adaptString(orig); - CHECK(adapter.compare(NULL) > 0); - CHECK(adapter.compare("alpha") > 0); - CHECK(adapter.compare("bravo") == 0); - CHECK(adapter.compare("charlie") < 0); - - CHECK(adapter.size() == 5); + CHECK(s.isNull() == false); + CHECK(s.size() == 5); } TEST_CASE("Arduino String") { - ::String str("bravo"); - StringAdapter< ::String> adapter(str); + ::String orig("bravo"); + SizedRamString s = adaptString(orig); - CHECK(adapter.compare(NULL) > 0); - CHECK(adapter.compare("alpha") > 0); - CHECK(adapter.compare("bravo") == 0); - CHECK(adapter.compare("charlie") < 0); - - CHECK(adapter.size() == 5); + CHECK(s.isNull() == false); + CHECK(s.size() == 5); } TEST_CASE("custom_string") { - custom_string str("bravo"); - StringAdapter adapter(str); + custom_string orig("bravo"); + SizedRamString s = adaptString(orig); - CHECK(adapter.compare(NULL) > 0); - CHECK(adapter.compare("alpha") > 0); - CHECK(adapter.compare("bravo") == 0); - CHECK(adapter.compare("charlie") < 0); - - CHECK(adapter.size() == 5); + CHECK(s.isNull() == false); + CHECK(s.size() == 5); } TEST_CASE("IsString") { @@ -142,3 +111,93 @@ TEST_CASE("IsString") { CHECK(IsString::value == true); } } + +TEST_CASE("stringCompare") { + SECTION("ZeroTerminatedRamString vs ZeroTerminatedRamString") { + CHECK(stringCompare(adaptString("bravo"), adaptString("alpha")) > 0); + CHECK(stringCompare(adaptString("bravo"), adaptString("bravo")) == 0); + CHECK(stringCompare(adaptString("bravo"), adaptString("charlie")) < 0); + } + + SECTION("ZeroTerminatedRamString vs SizedRamString") { + CHECK(stringCompare(adaptString("bravo"), adaptString("alpha?", 5)) > 0); + CHECK(stringCompare(adaptString("bravo"), adaptString("bravo?", 4)) > 0); + CHECK(stringCompare(adaptString("bravo"), adaptString("bravo?", 5)) == 0); + CHECK(stringCompare(adaptString("bravo"), adaptString("bravo?", 6)) < 0); + CHECK(stringCompare(adaptString("bravo"), adaptString("charlie?", 7)) < 0); + } + + SECTION("SizedRamString vs SizedRamString") { + // clang-format off + CHECK(stringCompare(adaptString("bravo!", 5), adaptString("alpha?", 5)) > 0); + CHECK(stringCompare(adaptString("bravo!", 5), adaptString("bravo?", 5)) == 0); + CHECK(stringCompare(adaptString("bravo!", 5), adaptString("charlie?", 7)) < 0); + + CHECK(stringCompare(adaptString("bravo!", 5), adaptString("bravo!", 4)) > 0); + CHECK(stringCompare(adaptString("bravo!", 5), adaptString("bravo!", 5)) == 0); + CHECK(stringCompare(adaptString("bravo!", 5), adaptString("bravo!", 6)) < 0); + // clang-format on + } + + SECTION("FlashString vs FlashString") { + // clang-format off + CHECK(stringCompare(adaptString(F("bravo")), adaptString(F("alpha"))) > 0); + CHECK(stringCompare(adaptString(F("bravo")), adaptString(F("bravo"))) == 0); + CHECK(stringCompare(adaptString(F("bravo")), adaptString(F("charlie"))) < 0); + // clang-format on + } + + SECTION("FlashString vs SizedRamString") { + // clang-format off + CHECK(stringCompare(adaptString(F("bravo")), adaptString("alpha?", 5)) > 0); + CHECK(stringCompare(adaptString(F("bravo")), adaptString("bravo?", 5)) == 0); + CHECK(stringCompare(adaptString(F("bravo")), adaptString("charlie?", 7)) < 0); + + CHECK(stringCompare(adaptString(F("bravo")), adaptString("bravo!", 4)) > 0); + CHECK(stringCompare(adaptString(F("bravo")), adaptString("bravo!", 5)) == 0); + CHECK(stringCompare(adaptString(F("bravo")), adaptString("bravo!", 6)) < 0); + // clang-format on + } + + SECTION("ZeroTerminatedRamString vs FlashString") { + // clang-format off + CHECK(stringCompare(adaptString("bravo"), adaptString(F("alpha?"), 5)) > 0); + CHECK(stringCompare(adaptString("bravo"), adaptString(F("bravo?"), 4)) > 0); + CHECK(stringCompare(adaptString("bravo"), adaptString(F("bravo?"), 5)) == 0); + CHECK(stringCompare(adaptString("bravo"), adaptString(F("bravo?"), 6)) < 0); + CHECK(stringCompare(adaptString("bravo"), adaptString(F("charlie?"), 7)) < 0); + // clang-format on + } +} + +TEST_CASE("stringEquals()") { + SECTION("ZeroTerminatedRamString vs ZeroTerminatedRamString") { + CHECK(stringEquals(adaptString("bravo"), adaptString("brav")) == false); + CHECK(stringEquals(adaptString("bravo"), adaptString("bravo")) == true); + CHECK(stringEquals(adaptString("bravo"), adaptString("bravo!")) == false); + } + + SECTION("ZeroTerminatedRamString vs SizedRamString") { + // clang-format off + CHECK(stringEquals(adaptString("bravo"), adaptString("bravo!", 4)) == false); + CHECK(stringEquals(adaptString("bravo"), adaptString("bravo!", 5)) == true); + CHECK(stringEquals(adaptString("bravo"), adaptString("bravo!", 6)) == false); + // clang-format on + } + + SECTION("FlashString vs SizedRamString") { + // clang-format off + CHECK(stringEquals(adaptString(F("bravo")), adaptString("bravo!", 4)) == false); + CHECK(stringEquals(adaptString(F("bravo")), adaptString("bravo!", 5)) == true); + CHECK(stringEquals(adaptString(F("bravo")), adaptString("bravo!", 6)) == false); + // clang-format on + } + + SECTION("SizedRamString vs SizedRamString") { + // clang-format off + CHECK(stringEquals(adaptString("bravo?", 5), adaptString("bravo!", 4)) == false); + CHECK(stringEquals(adaptString("bravo?", 5), adaptString("bravo!", 5)) == true); + CHECK(stringEquals(adaptString("bravo?", 5), adaptString("bravo!", 6)) == false); + // clang-format on + } +} diff --git a/src/ArduinoJson/Collection/CollectionData.hpp b/src/ArduinoJson/Collection/CollectionData.hpp index d2bca45f..a0eb0fff 100644 --- a/src/ArduinoJson/Collection/CollectionData.hpp +++ b/src/ArduinoJson/Collection/CollectionData.hpp @@ -40,14 +40,15 @@ class CollectionData { // Object only - template - VariantData *addMember(TAdaptedString key, MemoryPool *pool); + template + VariantData *addMember(TAdaptedString key, MemoryPool *pool, TStoragePolicy); template VariantData *getMember(TAdaptedString key) const; - template - VariantData *getOrAddMember(TAdaptedString key, MemoryPool *pool); + template + VariantData *getOrAddMember(TAdaptedString key, MemoryPool *pool, + TStoragePolicy); template void removeMember(TAdaptedString key) { diff --git a/src/ArduinoJson/Collection/CollectionImpl.hpp b/src/ArduinoJson/Collection/CollectionImpl.hpp index f814bcdf..61816daf 100644 --- a/src/ArduinoJson/Collection/CollectionImpl.hpp +++ b/src/ArduinoJson/Collection/CollectionImpl.hpp @@ -5,6 +5,8 @@ #pragma once #include +#include +#include #include namespace ARDUINOJSON_NAMESPACE { @@ -34,11 +36,12 @@ inline VariantData* CollectionData::addElement(MemoryPool* pool) { return slotData(addSlot(pool)); } -template +template inline VariantData* CollectionData::addMember(TAdaptedString key, - MemoryPool* pool) { + MemoryPool* pool, + TStoragePolicy storage) { VariantSlot* slot = addSlot(pool); - if (!slotSetKey(slot, key, pool)) { + if (!slotSetKey(slot, key, pool, storage)) { removeSlot(slot); return 0; } @@ -61,10 +64,8 @@ inline bool CollectionData::copyFrom(const CollectionData& src, for (VariantSlot* s = src._head; s; s = s->next()) { VariantData* var; if (s->key() != 0) { - if (s->ownsKey()) - var = addMember(adaptString(const_cast(s->key())), pool); - else - var = addMember(adaptString(s->key()), pool); + String key(s->key(), !s->ownsKey()); + var = addMember(adaptString(key), pool, getStringStoragePolicy(key)); } else { var = addElement(pool); } @@ -105,9 +106,11 @@ inline bool CollectionData::equalsArray(const CollectionData& other) const { template inline VariantSlot* CollectionData::getSlot(TAdaptedString key) const { + if (key.isNull()) + return 0; VariantSlot* slot = _head; while (slot) { - if (key.compare(slot->key()) == 0) + if (stringEquals(key, adaptString(slot->key()))) break; slot = slot->next(); } @@ -137,9 +140,9 @@ inline VariantData* CollectionData::getMember(TAdaptedString key) const { return slot ? slot->data() : 0; } -template -inline VariantData* CollectionData::getOrAddMember(TAdaptedString key, - MemoryPool* pool) { +template +inline VariantData* CollectionData::getOrAddMember( + TAdaptedString key, MemoryPool* pool, TStoragePolicy storage_policy) { // ignore null key if (key.isNull()) return 0; @@ -149,7 +152,7 @@ inline VariantData* CollectionData::getOrAddMember(TAdaptedString key, if (slot) return slot->data(); - return addMember(key, pool); + return addMember(key, pool, storage_policy); } inline VariantData* CollectionData::getElement(size_t index) const { diff --git a/src/ArduinoJson/Document/JsonDocument.hpp b/src/ArduinoJson/Document/JsonDocument.hpp index d81853c3..23ef9b66 100644 --- a/src/ArduinoJson/Document/JsonDocument.hpp +++ b/src/ArduinoJson/Document/JsonDocument.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -244,14 +245,18 @@ class JsonDocument : public Visitable { // getOrAddMember(const __FlashStringHelper*) template FORCE_INLINE VariantRef getOrAddMember(TChar* key) { - return VariantRef(&_pool, _data.getOrAddMember(adaptString(key), &_pool)); + return VariantRef(&_pool, + _data.getOrAddMember(adaptString(key), &_pool, + getStringStoragePolicy(key))); } // getOrAddMember(const std::string&) // getOrAddMember(const String&) template FORCE_INLINE VariantRef getOrAddMember(const TString& key) { - return VariantRef(&_pool, _data.getOrAddMember(adaptString(key), &_pool)); + return VariantRef(&_pool, + _data.getOrAddMember(adaptString(key), &_pool, + getStringStoragePolicy(key))); } FORCE_INLINE VariantRef addElement() { diff --git a/src/ArduinoJson/Memory/MemoryPool.hpp b/src/ArduinoJson/Memory/MemoryPool.hpp index 0082a1d2..0d76cb8a 100644 --- a/src/ArduinoJson/Memory/MemoryPool.hpp +++ b/src/ArduinoJson/Memory/MemoryPool.hpp @@ -60,7 +60,7 @@ class MemoryPool { } template - const char* saveString(const TAdaptedString& str) { + const char* saveString(TAdaptedString str) { if (str.isNull()) return CopiedString(); @@ -74,7 +74,7 @@ class MemoryPool { char* newCopy = allocString(n + 1); if (newCopy) { - str.copyTo(newCopy, n); + stringGetChars(str, newCopy, n); newCopy[n] = 0; // force null-terminator } return CopiedString(newCopy, n); @@ -165,22 +165,11 @@ class MemoryPool { } #if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION - template - static bool stringEquals(const char* p, size_t n, const TAdaptedString& s) { - if (p[n]) // check terminator first - return false; - for (size_t i = 0; i < n; i++) { - if (p[i] != s[i]) - return false; - } - return true; - } - template const char* findString(const TAdaptedString& str) const { size_t n = str.size(); for (char* next = _begin; next + n < _left; ++next) { - if (stringEquals(next, n, str)) + if (next[n] == '\0' && stringEquals(str, adaptString(next, n))) return next; // jump to next terminator diff --git a/src/ArduinoJson/Object/ObjectFunctions.hpp b/src/ArduinoJson/Object/ObjectFunctions.hpp index 1b46e842..9d9338a7 100644 --- a/src/ArduinoJson/Object/ObjectFunctions.hpp +++ b/src/ArduinoJson/Object/ObjectFunctions.hpp @@ -40,12 +40,13 @@ void objectRemove(CollectionData *obj, TAdaptedString key) { obj->removeMember(key); } -template +template inline VariantData *objectGetOrAddMember(CollectionData *obj, - TAdaptedString key, MemoryPool *pool) { + TAdaptedString key, MemoryPool *pool, + TStoragePolicy storage_policy) { if (!obj) return 0; - return obj->getOrAddMember(key, pool); + return obj->getOrAddMember(key, pool, storage_policy); } } // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Object/ObjectRef.hpp b/src/ArduinoJson/Object/ObjectRef.hpp index 047d9b1b..8c0fd836 100644 --- a/src/ArduinoJson/Object/ObjectRef.hpp +++ b/src/ArduinoJson/Object/ObjectRef.hpp @@ -196,7 +196,8 @@ class ObjectRef : public ObjectRefBase, template FORCE_INLINE VariantRef getOrAddMember(const TString& key) const { return VariantRef(_pool, - objectGetOrAddMember(_data, adaptString(key), _pool)); + objectGetOrAddMember(_data, adaptString(key), _pool, + getStringStoragePolicy(key))); } // getOrAddMember(char*) const @@ -205,7 +206,8 @@ class ObjectRef : public ObjectRefBase, template FORCE_INLINE VariantRef getOrAddMember(TChar* key) const { return VariantRef(_pool, - objectGetOrAddMember(_data, adaptString(key), _pool)); + objectGetOrAddMember(_data, adaptString(key), _pool, + getStringStoragePolicy(key))); } FORCE_INLINE bool operator==(ObjectRef rhs) const { diff --git a/src/ArduinoJson/Polyfills/pgmspace.hpp b/src/ArduinoJson/Polyfills/pgmspace.hpp index f253818e..c9107384 100644 --- a/src/ArduinoJson/Polyfills/pgmspace.hpp +++ b/src/ArduinoJson/Polyfills/pgmspace.hpp @@ -65,6 +65,22 @@ inline int strcmp_P(const char* a, ARDUINOJSON_NAMESPACE::pgm_p b) { } #endif +#ifndef memcmp_P +inline int memcmp_P(const void* a, ARDUINOJSON_NAMESPACE::pgm_p b, size_t n) { + const uint8_t* p1 = reinterpret_cast(a); + const char* p2 = b.address; + ARDUINOJSON_ASSERT(p1 != NULL); + ARDUINOJSON_ASSERT(p2 != NULL); + while (n-- > 0) { + uint8_t v1 = *p1++; + uint8_t v2 = pgm_read_byte(p2++); + if (v1 != v2) + return v1 - v2; + } + return 0; +} +#endif + #ifndef memcpy_P inline void* memcpy_P(void* dst, ARDUINOJSON_NAMESPACE::pgm_p src, size_t n) { uint8_t* d = reinterpret_cast(dst); diff --git a/src/ArduinoJson/Polyfills/safe_strcmp.hpp b/src/ArduinoJson/Polyfills/safe_strcmp.hpp deleted file mode 100644 index 502fe527..00000000 --- a/src/ArduinoJson/Polyfills/safe_strcmp.hpp +++ /dev/null @@ -1,33 +0,0 @@ -// ArduinoJson - https://arduinojson.org -// Copyright Benoit Blanchon 2014-2021 -// MIT License - -#pragma once - -#include - -#include // int8_t -#include // strcmp - -namespace ARDUINOJSON_NAMESPACE { - -inline int safe_strcmp(const char* a, const char* b) { - if (a == b) - return 0; - if (!a) - return -1; - if (!b) - return 1; - return strcmp(a, b); -} - -inline int safe_strncmp(const char* a, const char* b, size_t n) { - if (a == b) - return 0; - if (!a) - return -1; - if (!b) - return 1; - return strncmp(a, b, n); -} -} // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Strings/Adapters/ArduinoString.hpp b/src/ArduinoJson/Strings/Adapters/ArduinoString.hpp new file mode 100644 index 00000000..7fb147f2 --- /dev/null +++ b/src/ArduinoJson/Strings/Adapters/ArduinoString.hpp @@ -0,0 +1,24 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include + +#include +#include + +namespace ARDUINOJSON_NAMESPACE { + +inline SizedRamString adaptString(const ::String& s) { + return SizedRamString(s.c_str(), s.length()); +} + +template <> +struct IsString< ::String> : true_type {}; + +template <> +struct IsString< ::StringSumHelper> : true_type {}; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Strings/Adapters/ArduinoStringAdapter.hpp b/src/ArduinoJson/Strings/Adapters/ArduinoStringAdapter.hpp deleted file mode 100644 index 7203bf82..00000000 --- a/src/ArduinoJson/Strings/Adapters/ArduinoStringAdapter.hpp +++ /dev/null @@ -1,56 +0,0 @@ -// ArduinoJson - https://arduinojson.org -// Copyright Benoit Blanchon 2014-2021 -// MIT License - -#pragma once - -#include - -#include -#include -#include - -namespace ARDUINOJSON_NAMESPACE { - -template <> -class StringAdapter< ::String> { - public: - StringAdapter(const ::String& str) : _str(&str) {} - - void copyTo(char* p, size_t n) const { - memcpy(p, _str->c_str(), n); - } - - bool isNull() const { - // Arduino's String::c_str() can return NULL - return !_str->c_str(); - } - - int compare(const char* other) const { - // Arduino's String::c_str() can return NULL - const char* me = _str->c_str(); - return safe_strcmp(me, other); - } - - char operator[](size_t i) const { - ARDUINOJSON_ASSERT(_str != 0); - return _str->operator[](static_cast(i)); - } - - size_t size() const { - return _str->length(); - } - - typedef storage_policies::store_by_copy storage_policy; - - private: - const ::String* _str; -}; - -template <> -class StringAdapter< ::StringSumHelper> : public StringAdapter< ::String> { - public: - StringAdapter(const ::String& s) : StringAdapter< ::String>(s) {} -}; - -} // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Strings/Adapters/ConstRamStringAdapter.hpp b/src/ArduinoJson/Strings/Adapters/ConstRamStringAdapter.hpp deleted file mode 100644 index 760dc1f0..00000000 --- a/src/ArduinoJson/Strings/Adapters/ConstRamStringAdapter.hpp +++ /dev/null @@ -1,58 +0,0 @@ -// ArduinoJson - https://arduinojson.org -// Copyright Benoit Blanchon 2014-2021 -// MIT License - -#pragma once - -#include // size_t -#include // strcmp - -#include -#include -#include -#include - -namespace ARDUINOJSON_NAMESPACE { - -template <> -class StringAdapter { - public: - StringAdapter(const char* str = 0) : _str(str) {} - - int compare(const char* other) const { - return safe_strcmp(_str, other); - } - - bool isNull() const { - return !_str; - } - - size_t size() const { - if (!_str) - return 0; - return strlen(_str); - } - - char operator[](size_t i) const { - ARDUINOJSON_ASSERT(_str != 0); - ARDUINOJSON_ASSERT(i <= size()); - return _str[i]; - } - - const char* data() const { - return _str; - } - - typedef storage_policies::store_by_address storage_policy; - - protected: - const char* _str; -}; - -template -class StringAdapter : public StringAdapter { - public: - StringAdapter(const char* s) : StringAdapter(s) {} -}; - -} // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Strings/Adapters/FlashString.hpp b/src/ArduinoJson/Strings/Adapters/FlashString.hpp new file mode 100644 index 00000000..38acbc34 --- /dev/null +++ b/src/ArduinoJson/Strings/Adapters/FlashString.hpp @@ -0,0 +1,80 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include + +#include +#include + +namespace ARDUINOJSON_NAMESPACE { + +class FlashString { + public: + static const size_t typeSortKey = 1; + + FlashString(const __FlashStringHelper* str, size_t sz) + : _str(reinterpret_cast(str)), _size(sz) {} + + bool isNull() const { + return !_str; + } + + char operator[](size_t i) const { + ARDUINOJSON_ASSERT(_str != 0); + ARDUINOJSON_ASSERT(i <= _size); + return static_cast(pgm_read_byte(_str + i)); + } + + size_t size() const { + return _size; + } + + friend bool stringEquals(FlashString a, SizedRamString b) { + ARDUINOJSON_ASSERT(a.typeSortKey < b.typeSortKey); + ARDUINOJSON_ASSERT(!a.isNull()); + ARDUINOJSON_ASSERT(!b.isNull()); + if (a.size() != b.size()) + return false; + return ::memcmp_P(b.data(), a._str, a._size) == 0; + } + + friend int stringCompare(FlashString a, SizedRamString b) { + ARDUINOJSON_ASSERT(a.typeSortKey < b.typeSortKey); + ARDUINOJSON_ASSERT(!a.isNull()); + ARDUINOJSON_ASSERT(!b.isNull()); + size_t minsize = a.size() < b.size() ? a.size() : b.size(); + int res = ::memcmp_P(b.data(), a._str, minsize); + if (res) + return -res; + if (a.size() < b.size()) + return -1; + if (a.size() > b.size()) + return 1; + return 0; + } + + friend void stringGetChars(FlashString s, char* p, size_t n) { + ARDUINOJSON_ASSERT(s.size() <= n); + ::memcpy_P(p, s._str, n); + } + + private: + const char* _str; + size_t _size; +}; + +inline FlashString adaptString(const __FlashStringHelper* s) { + return FlashString(s, s ? strlen_P(reinterpret_cast(s)) : 0); +} + +inline FlashString adaptString(const __FlashStringHelper* s, size_t n) { + return FlashString(s, n); +} + +template <> +struct IsString : true_type {}; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Strings/Adapters/FlashStringAdapter.hpp b/src/ArduinoJson/Strings/Adapters/FlashStringAdapter.hpp deleted file mode 100644 index c0aa2969..00000000 --- a/src/ArduinoJson/Strings/Adapters/FlashStringAdapter.hpp +++ /dev/null @@ -1,55 +0,0 @@ -// ArduinoJson - https://arduinojson.org -// Copyright Benoit Blanchon 2014-2021 -// MIT License - -#pragma once - -#include -#include -#include - -namespace ARDUINOJSON_NAMESPACE { - -template <> -class StringAdapter { - public: - StringAdapter(const __FlashStringHelper* str) : _str(str) {} - - int compare(const char* other) const { - if (!other && !_str) - return 0; - if (!_str) - return -1; - if (!other) - return 1; - return -strcmp_P(other, reinterpret_cast(_str)); - } - - bool isNull() const { - return !_str; - } - - void copyTo(char* p, size_t n) const { - memcpy_P(p, reinterpret_cast(_str), n); - } - - size_t size() const { - if (!_str) - return 0; - return strlen_P(reinterpret_cast(_str)); - } - - char operator[](size_t i) const { - ARDUINOJSON_ASSERT(_str != 0); - ARDUINOJSON_ASSERT(i <= size()); - return static_cast( - pgm_read_byte(reinterpret_cast(_str) + i)); - } - - typedef storage_policies::store_by_copy storage_policy; - - private: - const __FlashStringHelper* _str; -}; - -} // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Strings/Adapters/JsonString.hpp b/src/ArduinoJson/Strings/Adapters/JsonString.hpp new file mode 100644 index 00000000..e4c54996 --- /dev/null +++ b/src/ArduinoJson/Strings/Adapters/JsonString.hpp @@ -0,0 +1,20 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include +#include +#include + +namespace ARDUINOJSON_NAMESPACE { + +inline SizedRamString adaptString(const String& s) { + return SizedRamString(s.c_str(), s.size()); +} + +template <> +struct IsString : true_type {}; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Strings/Adapters/JsonStringAdapter.hpp b/src/ArduinoJson/Strings/Adapters/JsonStringAdapter.hpp deleted file mode 100644 index c34abce5..00000000 --- a/src/ArduinoJson/Strings/Adapters/JsonStringAdapter.hpp +++ /dev/null @@ -1,27 +0,0 @@ -// ArduinoJson - https://arduinojson.org -// Copyright Benoit Blanchon 2014-2021 -// MIT License - -#pragma once - -#include -#include - -namespace ARDUINOJSON_NAMESPACE { - -template <> -class StringAdapter : public StringAdapter { - public: - StringAdapter(const String& str) - : StringAdapter(str.c_str()), _isStatic(str.isStatic()) {} - - bool isStatic() const { - return _isStatic; - } - - typedef storage_policies::decide_at_runtime storage_policy; - - private: - bool _isStatic; -}; -} // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Strings/Adapters/RamString.hpp b/src/ArduinoJson/Strings/Adapters/RamString.hpp new file mode 100644 index 00000000..66370b16 --- /dev/null +++ b/src/ArduinoJson/Strings/Adapters/RamString.hpp @@ -0,0 +1,119 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include // size_t +#include // strcmp + +#include +#include + +namespace ARDUINOJSON_NAMESPACE { + +class ZeroTerminatedRamString { + public: + static const size_t typeSortKey = 3; + + ZeroTerminatedRamString(const char* str) : _str(str) {} + + bool isNull() const { + return !_str; + } + + size_t size() const { + return _str ? ::strlen(_str) : 0; + } + + char operator[](size_t i) const { + ARDUINOJSON_ASSERT(_str != 0); + ARDUINOJSON_ASSERT(i <= size()); + return _str[i]; + } + + const char* data() const { + return _str; + } + + friend int stringCompare(ZeroTerminatedRamString a, + ZeroTerminatedRamString b) { + ARDUINOJSON_ASSERT(!a.isNull()); + ARDUINOJSON_ASSERT(!b.isNull()); + return ::strcmp(a._str, b._str); + } + + friend bool stringEquals(ZeroTerminatedRamString a, + ZeroTerminatedRamString b) { + return stringCompare(a, b) == 0; + } + + protected: + const char* _str; +}; + +template <> +struct IsString : true_type {}; + +inline ZeroTerminatedRamString adaptString(const char* s) { + return ZeroTerminatedRamString(s); +} + +template <> +struct IsString : true_type {}; + +inline ZeroTerminatedRamString adaptString(const unsigned char* s) { + return adaptString(reinterpret_cast(s)); +} + +template <> +struct IsString : true_type {}; + +inline ZeroTerminatedRamString adaptString(const signed char* s) { + return adaptString(reinterpret_cast(s)); +} + +class SizedRamString { + public: + static const size_t typeSortKey = 2; + + SizedRamString(const char* str, size_t sz) : _str(str), _size(sz) {} + + bool isNull() const { + return !_str; + } + + size_t size() const { + return _size; + } + + char operator[](size_t i) const { + ARDUINOJSON_ASSERT(_str != 0); + ARDUINOJSON_ASSERT(i <= size()); + return _str[i]; + } + + const char* data() const { + return _str; + } + + protected: + const char* _str; + size_t _size; +}; + +inline SizedRamString adaptString(const char* s, size_t n) { + return SizedRamString(s, n); +} + +template +struct IsString : true_type {}; + +template +struct IsString : true_type {}; + +template +inline SizedRamString adaptString(char s[N]) { + return SizedRamString(s, strlen(s)); +} +} // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Strings/Adapters/RamStringAdapter.hpp b/src/ArduinoJson/Strings/Adapters/RamStringAdapter.hpp deleted file mode 100644 index f2b01d17..00000000 --- a/src/ArduinoJson/Strings/Adapters/RamStringAdapter.hpp +++ /dev/null @@ -1,29 +0,0 @@ -// ArduinoJson - https://arduinojson.org -// Copyright Benoit Blanchon 2014-2021 -// MIT License - -#pragma once - -#include -#include -#include - -namespace ARDUINOJSON_NAMESPACE { - -template -class StringAdapter::value>::type> - : public StringAdapter { - public: - StringAdapter(const TChar* str) - : StringAdapter(reinterpret_cast(str)) {} - - void copyTo(char* p, size_t n) const { - memcpy(p, _str, n); - } - - typedef ARDUINOJSON_NAMESPACE::storage_policies::store_by_copy storage_policy; -}; - -} // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Strings/Adapters/SizedFlashStringAdapter.hpp b/src/ArduinoJson/Strings/Adapters/SizedFlashStringAdapter.hpp deleted file mode 100644 index 90950628..00000000 --- a/src/ArduinoJson/Strings/Adapters/SizedFlashStringAdapter.hpp +++ /dev/null @@ -1,56 +0,0 @@ -// ArduinoJson - https://arduinojson.org -// Copyright Benoit Blanchon 2014-2021 -// MIT License - -#pragma once - -#include -#include -#include - -namespace ARDUINOJSON_NAMESPACE { - -template <> -class StringAdapter { - public: - StringAdapter(const __FlashStringHelper* str, size_t sz) - : _str(str), _size(sz) {} - - int compare(const char* other) const { - if (!other && !_str) - return 0; - if (!_str) - return -1; - if (!other) - return 1; - return -strncmp_P(other, reinterpret_cast(_str), _size); - } - - bool isNull() const { - return !_str; - } - - void copyTo(char* p, size_t n) const { - memcpy_P(p, reinterpret_cast(_str), n); - } - - // TODO: not covered by the tests - char operator[](size_t i) const { - ARDUINOJSON_ASSERT(_str != 0); - ARDUINOJSON_ASSERT(i <= _size); - return static_cast( - pgm_read_byte(reinterpret_cast(_str) + i)); - } - - size_t size() const { - return _size; - } - - typedef storage_policies::store_by_copy storage_policy; - - private: - const __FlashStringHelper* _str; - size_t _size; -}; - -} // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Strings/Adapters/SizedRamStringAdapter.hpp b/src/ArduinoJson/Strings/Adapters/SizedRamStringAdapter.hpp deleted file mode 100644 index f219a453..00000000 --- a/src/ArduinoJson/Strings/Adapters/SizedRamStringAdapter.hpp +++ /dev/null @@ -1,49 +0,0 @@ -// ArduinoJson - https://arduinojson.org -// Copyright Benoit Blanchon 2014-2021 -// MIT License - -#pragma once - -#include -#include -#include - -#include // strcmp - -namespace ARDUINOJSON_NAMESPACE { - -template -class StringAdapter { - public: - StringAdapter(const char* str, size_t n) : _str(str), _size(n) {} - - int compare(const char* other) const { - return safe_strncmp(_str, other, _size); - } - - bool isNull() const { - return !_str; - } - - void copyTo(char* p, size_t n) const { - memcpy(p, _str, n); - } - - size_t size() const { - return _size; - } - - char operator[](size_t i) const { - ARDUINOJSON_ASSERT(_str != 0); - ARDUINOJSON_ASSERT(i <= _size); - return _str[i]; - } - - typedef storage_policies::store_by_copy storage_policy; - - private: - const char* _str; - size_t _size; -}; - -} // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Strings/Adapters/StdString.hpp b/src/ArduinoJson/Strings/Adapters/StdString.hpp new file mode 100644 index 00000000..effa6505 --- /dev/null +++ b/src/ArduinoJson/Strings/Adapters/StdString.hpp @@ -0,0 +1,23 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include + +#include + +namespace ARDUINOJSON_NAMESPACE { + +template +inline SizedRamString adaptString( + const std::basic_string& s) { + return SizedRamString(s.c_str(), s.size()); +} + +template +struct IsString > : true_type { +}; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Strings/Adapters/StdStringAdapter.hpp b/src/ArduinoJson/Strings/Adapters/StdStringAdapter.hpp deleted file mode 100644 index 346616f6..00000000 --- a/src/ArduinoJson/Strings/Adapters/StdStringAdapter.hpp +++ /dev/null @@ -1,51 +0,0 @@ -// ArduinoJson - https://arduinojson.org -// Copyright Benoit Blanchon 2014-2021 -// MIT License - -#pragma once - -#include -#include -#include - -#include - -namespace ARDUINOJSON_NAMESPACE { - -template -class StringAdapter > { - public: - typedef std::basic_string string_type; - - StringAdapter(const string_type& str) : _str(&str) {} - - void copyTo(char* p, size_t n) const { - memcpy(p, _str->c_str(), n); - } - - bool isNull() const { - return false; - } - - int compare(const char* other) const { - if (!other) - return 1; - return _str->compare(other); - } - - char operator[](size_t i) const { - ARDUINOJSON_ASSERT(i <= size()); - return _str->operator[](i); - } - - size_t size() const { - return _str->size(); - } - - typedef storage_policies::store_by_copy storage_policy; - - private: - const string_type* _str; -}; - -} // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Strings/Adapters/StringView.hpp b/src/ArduinoJson/Strings/Adapters/StringView.hpp new file mode 100644 index 00000000..285d3e7e --- /dev/null +++ b/src/ArduinoJson/Strings/Adapters/StringView.hpp @@ -0,0 +1,20 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include + +#include + +namespace ARDUINOJSON_NAMESPACE { + +inline SizedRamString adaptString(const std::string_view& s) { + return SizedRamString(s.data(), s.size()); +} + +template <> +struct IsString : true_type {}; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Strings/Adapters/StringViewAdapter.hpp b/src/ArduinoJson/Strings/Adapters/StringViewAdapter.hpp deleted file mode 100644 index 3d5e10c9..00000000 --- a/src/ArduinoJson/Strings/Adapters/StringViewAdapter.hpp +++ /dev/null @@ -1,49 +0,0 @@ -// ArduinoJson - https://arduinojson.org -// Copyright Benoit Blanchon 2014-2021 -// MIT License - -#pragma once - -#include -#include -#include - -#include - -namespace ARDUINOJSON_NAMESPACE { - -template <> -class StringAdapter { - public: - StringAdapter(std::string_view str) : _str(str) {} - - void copyTo(char* p, size_t n) const { - memcpy(p, _str.data(), n); - } - - bool isNull() const { - return false; - } - - int compare(const char* other) const { - if (!other) - return 1; - return _str.compare(other); - } - - char operator[](size_t i) const { - ARDUINOJSON_ASSERT(i <= size()); - return _str[i]; - } - - size_t size() const { - return _str.size(); - } - - typedef storage_policies::store_by_copy storage_policy; - - private: - std::string_view _str; -}; - -} // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Strings/IsString.hpp b/src/ArduinoJson/Strings/IsString.hpp new file mode 100644 index 00000000..9e305c1b --- /dev/null +++ b/src/ArduinoJson/Strings/IsString.hpp @@ -0,0 +1,17 @@ +// ArduinoJson - https://arduinojson.org +// Copyright Benoit Blanchon 2014-2021 +// MIT License + +#pragma once + +#include + +namespace ARDUINOJSON_NAMESPACE { + +template +struct IsString : false_type {}; + +template +struct IsString : IsString {}; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Strings/StoragePolicy.hpp b/src/ArduinoJson/Strings/StoragePolicy.hpp index df0d62b4..e2a35547 100644 --- a/src/ArduinoJson/Strings/StoragePolicy.hpp +++ b/src/ArduinoJson/Strings/StoragePolicy.hpp @@ -4,12 +4,56 @@ #pragma once +#include +#include +#include + namespace ARDUINOJSON_NAMESPACE { -namespace storage_policies { -struct store_by_address {}; -struct store_by_copy {}; -struct decide_at_runtime {}; -} // namespace storage_policies +struct LinkStringStoragePolicy { + template + bool store(TAdaptedString str, MemoryPool *, TCallback callback) { + LinkedString storedString(str.data(), str.size()); + callback(storedString); + return !str.isNull(); + } +}; + +struct CopyStringStoragePolicy { + typedef CopiedString TResult; + + template + bool store(TAdaptedString str, MemoryPool *pool, TCallback callback); +}; + +class LinkOrCopyStringStoragePolicy : LinkStringStoragePolicy, + CopyStringStoragePolicy { + public: + LinkOrCopyStringStoragePolicy(bool link) : _link(link) {} + + template + bool store(TAdaptedString str, MemoryPool *pool, TCallback callback) { + if (_link) + return LinkStringStoragePolicy::store(str, pool, callback); + else + return CopyStringStoragePolicy::store(str, pool, callback); + } + + private: + bool _link; +}; + +template +inline CopyStringStoragePolicy getStringStoragePolicy(const T &) { + return CopyStringStoragePolicy(); +} + +inline LinkStringStoragePolicy getStringStoragePolicy(const char *) { + return LinkStringStoragePolicy(); +} + +inline LinkOrCopyStringStoragePolicy getStringStoragePolicy(const String &s) { + return LinkOrCopyStringStoragePolicy(s.isStatic()); +} } // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Strings/StoredString.hpp b/src/ArduinoJson/Strings/StoredString.hpp index 09165a4c..e799fe6a 100644 --- a/src/ArduinoJson/Strings/StoredString.hpp +++ b/src/ArduinoJson/Strings/StoredString.hpp @@ -4,12 +4,9 @@ #pragma once -#include -#include - namespace ARDUINOJSON_NAMESPACE { -template +template class StoredString { public: StoredString() : _data(0), _size(0) {} @@ -32,7 +29,7 @@ class StoredString { size_t _size; }; -typedef StoredString LinkedString; -typedef StoredString CopiedString; +typedef StoredString LinkedString; +typedef StoredString CopiedString; } // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Strings/StringAdapter.hpp b/src/ArduinoJson/Strings/StringAdapter.hpp deleted file mode 100644 index 1d55b212..00000000 --- a/src/ArduinoJson/Strings/StringAdapter.hpp +++ /dev/null @@ -1,32 +0,0 @@ -// ArduinoJson - https://arduinojson.org -// Copyright Benoit Blanchon 2014-2021 -// MIT License - -#pragma once - -#include - -namespace ARDUINOJSON_NAMESPACE { - -template -class StringAdapter; - -template -inline StringAdapter adaptString(const T& str) { - return StringAdapter(str); -} - -template -inline StringAdapter adaptString(const T& str, size_t sz) { - return StringAdapter(str, sz); -} - -template -struct IsString : false_type {}; - -template -struct IsString< - T, typename make_void::storage_policy>::type> - : true_type {}; - -} // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Strings/StringAdapters.hpp b/src/ArduinoJson/Strings/StringAdapters.hpp index ba763a67..9129e081 100644 --- a/src/ArduinoJson/Strings/StringAdapters.hpp +++ b/src/ArduinoJson/Strings/StringAdapters.hpp @@ -4,24 +4,85 @@ #pragma once -#include -#include -#include -#include +#include +#include +#include #if ARDUINOJSON_ENABLE_STD_STRING -# include +# include #endif #if ARDUINOJSON_ENABLE_STRING_VIEW -# include +# include #endif #if ARDUINOJSON_ENABLE_ARDUINO_STRING -# include +# include #endif #if ARDUINOJSON_ENABLE_PROGMEM -# include -# include +# include #endif + +namespace ARDUINOJSON_NAMESPACE { + +template +typename enable_if::type +stringCompare(TAdaptedString1 s1, TAdaptedString2 s2) { + ARDUINOJSON_ASSERT(!s1.isNull()); + ARDUINOJSON_ASSERT(!s2.isNull()); + size_t size1 = s1.size(); + size_t size2 = s2.size(); + size_t n = size1 < size2 ? size1 : size2; + for (size_t i = 0; i < n; i++) { + if (s1[i] != s2[i]) + return s1[i] - s2[i]; + } + if (size1 < size2) + return -1; + if (size1 > size2) + return 1; + return 0; +} + +template +typename enable_if< + (TAdaptedString1::typeSortKey > TAdaptedString2::typeSortKey), int>::type +stringCompare(TAdaptedString1 s1, TAdaptedString2 s2) { + return -stringCompare(s2, s1); +} + +template +typename enable_if::type +stringEquals(TAdaptedString1 s1, TAdaptedString2 s2) { + ARDUINOJSON_ASSERT(!s1.isNull()); + ARDUINOJSON_ASSERT(!s2.isNull()); + size_t size1 = s1.size(); + size_t size2 = s2.size(); + if (size1 != size2) + return false; + for (size_t i = 0; i < size1; i++) { + if (s1[i] != s2[i]) + return false; + } + return true; +} + +template +typename enable_if< + (TAdaptedString1::typeSortKey > TAdaptedString2::typeSortKey), bool>::type +stringEquals(TAdaptedString1 s1, TAdaptedString2 s2) { + return stringEquals(s2, s1); +} + +template +static void stringGetChars(TAdaptedString s, char* p, size_t n) { + ARDUINOJSON_ASSERT(s.size() <= n); + for (size_t i = 0; i < n; i++) { + p[i] = s[i]; + } +} + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Variant/ConverterImpl.hpp b/src/ArduinoJson/Variant/ConverterImpl.hpp index 4800da9f..c29d8cd9 100644 --- a/src/ArduinoJson/Variant/ConverterImpl.hpp +++ b/src/ArduinoJson/Variant/ConverterImpl.hpp @@ -115,7 +115,8 @@ struct Converter::value>::type> { template <> struct Converter { static void toJson(const char* src, VariantRef dst) { - variantSetString(getData(dst), adaptString(src), getPool(dst)); + variantSetString(getData(dst), adaptString(src), getPool(dst), + getStringStoragePolicy(src)); } static const char* fromJson(VariantConstRef src) { @@ -132,7 +133,8 @@ struct Converter { template <> struct Converter { static void toJson(String src, VariantRef dst) { - variantSetString(getData(dst), adaptString(src), getPool(dst)); + variantSetString(getData(dst), adaptString(src), getPool(dst), + getStringStoragePolicy(src)); } static String fromJson(VariantConstRef src) { @@ -151,7 +153,8 @@ inline typename enable_if::value, bool>::type convertToJson( const T& src, VariantRef dst) { VariantData* data = getData(dst); MemoryPool* pool = getPool(dst); - return variantSetString(data, adaptString(src), pool); + return variantSetString(data, adaptString(src), pool, + getStringStoragePolicy(src)); } template <> diff --git a/src/ArduinoJson/Variant/SlotFunctions.hpp b/src/ArduinoJson/Variant/SlotFunctions.hpp index 06f8727d..8a9a98dc 100644 --- a/src/ArduinoJson/Variant/SlotFunctions.hpp +++ b/src/ArduinoJson/Variant/SlotFunctions.hpp @@ -9,40 +9,24 @@ namespace ARDUINOJSON_NAMESPACE { -template -inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool) { - if (!var) - return false; - return slotSetKey(var, key, pool, typename TAdaptedString::storage_policy()); -} +struct SlotKeySetter { + SlotKeySetter(VariantSlot* instance) : _instance(instance) {} -template -inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool, - storage_policies::decide_at_runtime) { - if (key.isStatic()) { - return slotSetKey(var, key, pool, storage_policies::store_by_address()); - } else { - return slotSetKey(var, key, pool, storage_policies::store_by_copy()); + template + void operator()(TStoredString s) { + if (!s) + return; + ARDUINOJSON_ASSERT(_instance != 0); + _instance->setKey(s); } -} -template -inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool*, - storage_policies::store_by_address) { - ARDUINOJSON_ASSERT(var); - var->setKey(LinkedString(key.data(), key.size())); - return true; -} + VariantSlot* _instance; +}; -template +template inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool, - storage_policies::store_by_copy) { - CopiedString dup(pool->saveString(key), key.size()); - if (!dup) - return false; - ARDUINOJSON_ASSERT(var); - var->setKey(dup); - return true; + TStoragePolicy storage) { + return storage.store(key, pool, SlotKeySetter(var)); } inline size_t slotSize(const VariantSlot* var) { diff --git a/src/ArduinoJson/Variant/VariantCompare.hpp b/src/ArduinoJson/Variant/VariantCompare.hpp index 9142076f..9216ee99 100644 --- a/src/ArduinoJson/Variant/VariantCompare.hpp +++ b/src/ArduinoJson/Variant/VariantCompare.hpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include namespace ARDUINOJSON_NAMESPACE { @@ -23,12 +23,12 @@ struct Comparer; template struct Comparer::value>::type> : ComparerBase { - T rhs; + T rhs; // TODO: store adapted string? explicit Comparer(T value) : rhs(value) {} - CompareResult visitString(const char *lhs, size_t) { - int i = adaptString(rhs).compare(lhs); + CompareResult visitString(const char *lhs, size_t n) { + int i = stringCompare(adaptString(rhs), adaptString(lhs, n)); if (i < 0) return COMPARE_RESULT_GREATER; else if (i > 0) diff --git a/src/ArduinoJson/Variant/VariantData.hpp b/src/ArduinoJson/Variant/VariantData.hpp index ade584a6..75d9ca7a 100644 --- a/src/ArduinoJson/Variant/VariantData.hpp +++ b/src/ArduinoJson/Variant/VariantData.hpp @@ -99,27 +99,7 @@ class VariantData { return const_cast(this)->asObject(); } - bool copyFrom(const VariantData &src, MemoryPool *pool) { - switch (src.type()) { - case VALUE_IS_ARRAY: - return toArray().copyFrom(src._content.asCollection, pool); - case VALUE_IS_OBJECT: - return toObject().copyFrom(src._content.asCollection, pool); - case VALUE_IS_OWNED_STRING: - return storeString( - adaptString(const_cast(src._content.asString.data), - src._content.asString.size), - pool); - case VALUE_IS_OWNED_RAW: - return storeOwnedRaw( - serialized(src._content.asString.data, src._content.asString.size), - pool); - default: - setType(src.type()); - _content = src._content; - return true; - } - } + bool copyFrom(const VariantData &src, MemoryPool *pool); bool isArray() const { return (_flags & VALUE_IS_ARRAY) != 0; @@ -242,11 +222,6 @@ class VariantData { _content.asString.size = s.size(); } - template - bool storeString(TAdaptedString value, MemoryPool *pool) { - return storeString(value, pool, typename TAdaptedString::storage_policy()); - } - CollectionData &toArray() { setType(VALUE_IS_ARRAY); _content.asCollection.clear(); @@ -307,13 +282,14 @@ class VariantData { return isObject() ? _content.asCollection.getMember(key) : 0; } - template - VariantData *getOrAddMember(TAdaptedString key, MemoryPool *pool) { + template + VariantData *getOrAddMember(TAdaptedString key, MemoryPool *pool, + TStoragePolicy storage_policy) { if (isNull()) toObject(); if (!isObject()) return 0; - return _content.asCollection.getOrAddMember(key, pool); + return _content.asCollection.getOrAddMember(key, pool, storage_policy); } void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance) { @@ -327,46 +303,36 @@ class VariantData { return _flags & VALUE_MASK; } + template + inline bool storeString(TAdaptedString value, MemoryPool *pool, + TStoragePolicy storage) { + if (value.isNull()) { + setNull(); + return true; + } + + return storage.store(value, pool, VariantStringSetter(this)); + } + private: void setType(uint8_t t) { _flags &= OWNED_KEY_BIT; _flags |= t; } - template - inline bool storeString(TAdaptedString value, MemoryPool *pool, - storage_policies::decide_at_runtime) { - if (value.isStatic()) - return storeString(value, pool, storage_policies::store_by_address()); - else - return storeString(value, pool, storage_policies::store_by_copy()); - } + struct VariantStringSetter { + VariantStringSetter(VariantData *instance) : _instance(instance) {} - template - inline bool storeString(TAdaptedString value, MemoryPool *, - storage_policies::store_by_address) { - if (value.isNull()) - setNull(); - else - setString(LinkedString(value.data(), value.size())); - return true; - } + template + void operator()(TStoredString s) { + if (s) + _instance->setString(s); + else + _instance->setNull(); + } - template - inline bool storeString(TAdaptedString value, MemoryPool *pool, - storage_policies::store_by_copy) { - if (value.isNull()) { - setNull(); - return true; - } - const char *copy = pool->saveString(value); - if (!copy) { - setNull(); - return false; - } - setString(CopiedString(copy, value.size())); - return true; - } + VariantData *_instance; + }; }; } // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Variant/VariantFunctions.hpp b/src/ArduinoJson/Variant/VariantFunctions.hpp index 397a96bf..445bbc4e 100644 --- a/src/ArduinoJson/Variant/VariantFunctions.hpp +++ b/src/ArduinoJson/Variant/VariantFunctions.hpp @@ -5,6 +5,7 @@ #pragma once #include +#include #include namespace ARDUINOJSON_NAMESPACE { @@ -49,12 +50,10 @@ inline void variantSetNull(VariantData *var) { var->setNull(); } -template +template inline bool variantSetString(VariantData *var, TAdaptedString value, - MemoryPool *pool) { - if (!var) - return false; - return var->storeString(value, pool); + MemoryPool *pool, TStoragePolicy storage_policy) { + return var != 0 ? var->storeString(value, pool, storage_policy) : 0; } inline size_t variantSize(const VariantData *var) { @@ -87,14 +86,18 @@ inline NO_INLINE VariantData *variantGetOrAddElement(VariantData *var, template NO_INLINE VariantData *variantGetOrAddMember(VariantData *var, TChar *key, MemoryPool *pool) { - return var != 0 ? var->getOrAddMember(adaptString(key), pool) : 0; + return var != 0 ? var->getOrAddMember(adaptString(key), pool, + getStringStoragePolicy(key)) + : 0; } template NO_INLINE VariantData *variantGetOrAddMember(VariantData *var, const TString &key, MemoryPool *pool) { - return var != 0 ? var->getOrAddMember(adaptString(key), pool) : 0; + return var != 0 ? var->getOrAddMember(adaptString(key), pool, + getStringStoragePolicy(key)) + : 0; } inline bool variantIsNull(const VariantData *var) { diff --git a/src/ArduinoJson/Variant/VariantImpl.hpp b/src/ArduinoJson/Variant/VariantImpl.hpp index d7620c8c..75f72708 100644 --- a/src/ArduinoJson/Variant/VariantImpl.hpp +++ b/src/ArduinoJson/Variant/VariantImpl.hpp @@ -81,6 +81,28 @@ inline String VariantData::asString() const { } } +inline bool VariantData::copyFrom(const VariantData &src, MemoryPool *pool) { + switch (src.type()) { + case VALUE_IS_ARRAY: + return toArray().copyFrom(src._content.asCollection, pool); + case VALUE_IS_OBJECT: + return toObject().copyFrom(src._content.asCollection, pool); + case VALUE_IS_OWNED_STRING: { + String value = src.asString(); + return storeString(adaptString(value), pool, + getStringStoragePolicy(value)); + } + case VALUE_IS_OWNED_RAW: + return storeOwnedRaw( + serialized(src._content.asString.data, src._content.asString.size), + pool); + default: + setType(src.type()); + _content = src._content; + return true; + } +} + template inline typename enable_if::value, ArrayRef>::type VariantRef::to() const { @@ -146,4 +168,15 @@ inline VariantConstRef operator|(VariantConstRef preferedValue, inline bool VariantRef::set(char value) const { return set(value); } + +// TODO: move somewhere else +template +bool CopyStringStoragePolicy::store(TAdaptedString str, MemoryPool *pool, + TCallback callback) { + const char *copy = pool->saveString(str); + CopiedString storedString(copy, str.size()); + callback(storedString); + return copy != 0; +} + } // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Variant/VariantSlot.hpp b/src/ArduinoJson/Variant/VariantSlot.hpp index bdaa7598..54fdd255 100644 --- a/src/ArduinoJson/Variant/VariantSlot.hpp +++ b/src/ArduinoJson/Variant/VariantSlot.hpp @@ -7,7 +7,6 @@ #include #include #include -#include #include #include