diff --git a/src/ArduinoJson/Memory/ResourceManager.hpp b/src/ArduinoJson/Memory/ResourceManager.hpp index 1d70d3d4..af7c840c 100644 --- a/src/ArduinoJson/Memory/ResourceManager.hpp +++ b/src/ArduinoJson/Memory/ResourceManager.hpp @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include #include @@ -26,7 +26,7 @@ class ResourceManager { } ~ResourceManager() { - deallocAllStrings(); + stringPool_.clear(allocator_); variantPool_.destroy(allocator_); } @@ -34,13 +34,12 @@ class ResourceManager { ResourceManager& operator=(const ResourceManager& src) = delete; ResourceManager& operator=(ResourceManager&& src) { - deallocAllStrings(); + stringPool_.clear(allocator_); variantPool_.destroy(allocator_); allocator_ = src.allocator_; variantPool_ = detail::move(src.variantPool_); overflowed_ = src.overflowed_; - strings_ = src.strings_; - src.strings_ = nullptr; + stringPool_ = detail::move(src.stringPool_); return *this; } @@ -62,10 +61,7 @@ class ResourceManager { } size_t size() const { - size_t total = variantPool_.usage(); - for (auto node = strings_; node; node = node->next) - total += sizeofString(node->length); - return total; + return variantPool_.usage() + stringPool_.size(); } bool overflowed() const { @@ -84,37 +80,20 @@ class ResourceManager { if (str.isNull()) return 0; - auto node = findString(str); - if (node) { - node->references++; - return node; - } - - size_t n = str.size(); - - node = allocString(n); + auto node = stringPool_.add(str, allocator_); if (!node) - return nullptr; + overflowed_ = true; - stringGetChars(str, node->data, n); - node->data[n] = 0; // force NUL terminator - addStringToList(node); return node; } void addStringToList(StringNode* node) { - ARDUINOJSON_ASSERT(node != nullptr); - node->next = strings_; - strings_ = node; + stringPool_.add(node); } template StringNode* findString(const TAdaptedString& str) const { - for (auto node = strings_; node; node = node->next) { - if (stringEquals(str, adaptString(node->data, node->length))) - return node; - } - return nullptr; + return stringPool_.get(str); } StringNode* allocString(size_t length) { @@ -136,26 +115,13 @@ class ResourceManager { } void dereferenceString(const char* s) { - StringNode* prev = nullptr; - for (auto node = strings_; node; node = node->next) { - if (node->data == s) { - if (--node->references == 0) { - if (prev) - prev->next = node->next; - else - strings_ = node->next; - StringNode::destroy(node, allocator_); - } - return; - } - prev = node; - } + stringPool_.dereference(s, allocator_); } void clear() { variantPool_.clear(); overflowed_ = false; - deallocAllStrings(); + stringPool_.clear(allocator_); } ptrdiff_t shrinkToFit() { @@ -163,17 +129,9 @@ class ResourceManager { } private: - void deallocAllStrings() { - while (strings_) { - auto node = strings_; - strings_ = node->next; - deallocString(node); - } - } - Allocator* allocator_; bool overflowed_; - StringNode* strings_ = nullptr; + StringPool stringPool_; VariantPool variantPool_; }; diff --git a/src/ArduinoJson/Memory/StringPool.hpp b/src/ArduinoJson/Memory/StringPool.hpp new file mode 100644 index 00000000..742f9f14 --- /dev/null +++ b/src/ArduinoJson/Memory/StringPool.hpp @@ -0,0 +1,106 @@ +// ArduinoJson - https://arduinojson.org +// Copyright © 2014-2023, Benoit BLANCHON +// MIT License + +#pragma once + +#include +#include +#include +#include +#include + +ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE + +class VariantSlot; +class VariantPool; + +class StringPool { + public: + StringPool() = default; + StringPool(const StringPool&) = delete; + + ~StringPool() { + ARDUINOJSON_ASSERT(strings_ == nullptr); + } + + void operator=(StringPool&& src) { + ARDUINOJSON_ASSERT(strings_ == nullptr); + strings_ = src.strings_; + src.strings_ = nullptr; + } + + void clear(Allocator* allocator) { + while (strings_) { + auto node = strings_; + strings_ = node->next; + StringNode::destroy(node, allocator); + } + } + + size_t size() const { + size_t total = 0; + for (auto node = strings_; node; node = node->next) + total += sizeofString(node->length); + return total; + } + + template + StringNode* add(TAdaptedString str, Allocator* allocator) { + ARDUINOJSON_ASSERT(str.isNull() == false); + + auto node = get(str); + if (node) { + node->references++; + return node; + } + + size_t n = str.size(); + + node = StringNode::create(n, allocator); + if (!node) + return nullptr; + + stringGetChars(str, node->data, n); + node->data[n] = 0; // force NUL terminator + add(node); + return node; + } + + void add(StringNode* node) { + ARDUINOJSON_ASSERT(node != nullptr); + node->next = strings_; + strings_ = node; + } + + template + StringNode* get(const TAdaptedString& str) const { + for (auto node = strings_; node; node = node->next) { + if (stringEquals(str, adaptString(node->data, node->length))) + return node; + } + return nullptr; + } + + void dereference(const char* s, Allocator* allocator) { + StringNode* prev = nullptr; + for (auto node = strings_; node; node = node->next) { + if (node->data == s) { + if (--node->references == 0) { + if (prev) + prev->next = node->next; + else + strings_ = node->next; + StringNode::destroy(node, allocator); + } + return; + } + prev = node; + } + } + + private: + StringNode* strings_ = nullptr; +}; + +ARDUINOJSON_END_PRIVATE_NAMESPACE