ResourceManager.hpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. // ArduinoJson - https://arduinojson.org
  2. // Copyright © 2014-2023, Benoit BLANCHON
  3. // MIT License
  4. #pragma once
  5. #include <ArduinoJson/Memory/Alignment.hpp>
  6. #include <ArduinoJson/Memory/Allocator.hpp>
  7. #include <ArduinoJson/Memory/StringNode.hpp>
  8. #include <ArduinoJson/Polyfills/assert.hpp>
  9. #include <ArduinoJson/Strings/StringAdapters.hpp>
  10. ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
  11. class VariantSlot;
  12. class ResourceManager {
  13. public:
  14. ResourceManager(size_t capa,
  15. Allocator* allocator = DefaultAllocator::instance())
  16. : allocator_(allocator), overflowed_(false) {
  17. allocPool(addPadding(capa));
  18. }
  19. ~ResourceManager() {
  20. deallocAllStrings();
  21. deallocPool();
  22. }
  23. ResourceManager(const ResourceManager&) = delete;
  24. ResourceManager& operator=(const ResourceManager& src) = delete;
  25. ResourceManager& operator=(ResourceManager&& src) {
  26. deallocAllStrings();
  27. deallocPool();
  28. allocator_ = src.allocator_;
  29. pool_ = src.pool_;
  30. poolCapacity_ = src.poolCapacity_;
  31. poolUsage_ = src.poolUsage_;
  32. overflowed_ = src.overflowed_;
  33. src.pool_ = nullptr;
  34. src.poolCapacity_ = src.poolUsage_ = 0;
  35. strings_ = src.strings_;
  36. src.strings_ = nullptr;
  37. return *this;
  38. }
  39. Allocator* allocator() const {
  40. return allocator_;
  41. }
  42. void reallocPool(size_t requiredSize) {
  43. size_t capa = addPadding(requiredSize);
  44. if (capa == capacity())
  45. return;
  46. allocator_->deallocate(pool_);
  47. allocPool(requiredSize);
  48. }
  49. // Gets the capacity of the memoryPool in bytes
  50. size_t capacity() const {
  51. return poolCapacity_;
  52. }
  53. size_t size() const {
  54. size_t total = poolUsage_;
  55. for (auto node = strings_; node; node = node->next)
  56. total += sizeofString(node->length);
  57. return total;
  58. }
  59. bool overflowed() const {
  60. return overflowed_;
  61. }
  62. VariantSlot* allocVariant();
  63. template <typename TAdaptedString>
  64. StringNode* saveString(TAdaptedString str) {
  65. if (str.isNull())
  66. return 0;
  67. auto node = findString(str);
  68. if (node) {
  69. node->references++;
  70. return node;
  71. }
  72. size_t n = str.size();
  73. node = allocString(n);
  74. if (!node)
  75. return nullptr;
  76. stringGetChars(str, node->data, n);
  77. node->data[n] = 0; // force NUL terminator
  78. addStringToList(node);
  79. return node;
  80. }
  81. void addStringToList(StringNode* node) {
  82. ARDUINOJSON_ASSERT(node != nullptr);
  83. node->next = strings_;
  84. strings_ = node;
  85. }
  86. template <typename TAdaptedString>
  87. StringNode* findString(const TAdaptedString& str) const {
  88. for (auto node = strings_; node; node = node->next) {
  89. if (stringEquals(str, adaptString(node->data, node->length)))
  90. return node;
  91. }
  92. return nullptr;
  93. }
  94. StringNode* allocString(size_t length) {
  95. auto node = reinterpret_cast<StringNode*>(
  96. allocator_->allocate(sizeofString(length)));
  97. if (node) {
  98. node->length = uint16_t(length);
  99. node->references = 1;
  100. } else {
  101. overflowed_ = true;
  102. }
  103. return node;
  104. }
  105. StringNode* reallocString(StringNode* node, size_t length) {
  106. ARDUINOJSON_ASSERT(node != nullptr);
  107. auto newNode = reinterpret_cast<StringNode*>(
  108. allocator_->reallocate(node, sizeofString(length)));
  109. if (newNode) {
  110. newNode->length = uint16_t(length);
  111. } else {
  112. overflowed_ = true;
  113. allocator_->deallocate(node);
  114. }
  115. return newNode;
  116. }
  117. void deallocString(StringNode* node) {
  118. allocator_->deallocate(node);
  119. }
  120. void dereferenceString(const char* s) {
  121. StringNode* prev = nullptr;
  122. for (auto node = strings_; node; node = node->next) {
  123. if (node->data == s) {
  124. if (--node->references == 0) {
  125. if (prev)
  126. prev->next = node->next;
  127. else
  128. strings_ = node->next;
  129. allocator_->deallocate(node);
  130. }
  131. return;
  132. }
  133. prev = node;
  134. }
  135. }
  136. void clear() {
  137. poolUsage_ = 0;
  138. overflowed_ = false;
  139. deallocAllStrings();
  140. }
  141. // Workaround for missing placement new
  142. void* operator new(size_t, void* p) {
  143. return p;
  144. }
  145. ptrdiff_t shrinkToFit() {
  146. auto originalPoolAddress = pool_;
  147. pool_ = reinterpret_cast<char*>(allocator_->reallocate(pool_, poolUsage_));
  148. poolCapacity_ = poolUsage_;
  149. return pool_ - originalPoolAddress;
  150. }
  151. private:
  152. void deallocAllStrings() {
  153. while (strings_) {
  154. auto node = strings_;
  155. strings_ = node->next;
  156. deallocString(node);
  157. }
  158. }
  159. void allocPool(size_t capa) {
  160. pool_ = capa ? reinterpret_cast<char*>(allocator_->allocate(capa)) : 0;
  161. poolUsage_ = 0;
  162. poolCapacity_ = pool_ ? capa : 0;
  163. ARDUINOJSON_ASSERT(isAligned(pool_));
  164. }
  165. void deallocPool() {
  166. if (pool_)
  167. allocator_->deallocate(pool_);
  168. }
  169. Allocator* allocator_;
  170. char* pool_;
  171. size_t poolUsage_, poolCapacity_;
  172. bool overflowed_;
  173. StringNode* strings_ = nullptr;
  174. };
  175. ARDUINOJSON_END_PRIVATE_NAMESPACE