Allocators.hpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. // ArduinoJson - https://arduinojson.org
  2. // Copyright © 2014-2024, Benoit BLANCHON
  3. // MIT License
  4. #pragma once
  5. #include <ArduinoJson/Memory/Allocator.hpp>
  6. #include <ArduinoJson/Memory/StringBuilder.hpp>
  7. #include <ArduinoJson/Memory/VariantPool.hpp>
  8. #include <sstream>
  9. struct FailingAllocator : ArduinoJson::Allocator {
  10. static FailingAllocator* instance() {
  11. static FailingAllocator allocator;
  12. return &allocator;
  13. }
  14. private:
  15. FailingAllocator() = default;
  16. ~FailingAllocator() = default;
  17. void* allocate(size_t) override {
  18. return nullptr;
  19. }
  20. void deallocate(void*) override {}
  21. void* reallocate(void*, size_t) override {
  22. return nullptr;
  23. }
  24. };
  25. class AllocatorLogEntry {
  26. public:
  27. AllocatorLogEntry(std::string s, size_t n = 1) : str_(s), count_(n) {}
  28. const std::string& str() const {
  29. return str_;
  30. }
  31. size_t count() const {
  32. return count_;
  33. }
  34. AllocatorLogEntry operator*(size_t n) const {
  35. return AllocatorLogEntry(str_, n);
  36. }
  37. private:
  38. std::string str_;
  39. size_t count_;
  40. };
  41. inline AllocatorLogEntry Allocate(size_t s) {
  42. char buffer[32];
  43. sprintf(buffer, "allocate(%zu)", s);
  44. return AllocatorLogEntry(buffer);
  45. }
  46. inline AllocatorLogEntry AllocateFail(size_t s) {
  47. char buffer[32];
  48. sprintf(buffer, "allocate(%zu) -> nullptr", s);
  49. return AllocatorLogEntry(buffer);
  50. }
  51. inline AllocatorLogEntry Reallocate(size_t s1, size_t s2) {
  52. char buffer[32];
  53. sprintf(buffer, "reallocate(%zu, %zu)", s1, s2);
  54. return AllocatorLogEntry(buffer);
  55. }
  56. inline AllocatorLogEntry ReallocateFail(size_t s1, size_t s2) {
  57. char buffer[32];
  58. sprintf(buffer, "reallocate(%zu, %zu) -> nullptr", s1, s2);
  59. return AllocatorLogEntry(buffer);
  60. }
  61. inline AllocatorLogEntry Deallocate(size_t s) {
  62. char buffer[32];
  63. sprintf(buffer, "deallocate(%zu)", s);
  64. return AllocatorLogEntry(buffer);
  65. }
  66. class AllocatorLog {
  67. public:
  68. AllocatorLog() = default;
  69. AllocatorLog(std::initializer_list<AllocatorLogEntry> list) {
  70. for (auto& entry : list)
  71. append(entry);
  72. }
  73. void clear() {
  74. log_.str("");
  75. }
  76. void append(const AllocatorLogEntry& entry) {
  77. for (size_t i = 0; i < entry.count(); i++)
  78. log_ << entry.str() << "\n";
  79. }
  80. std::string str() const {
  81. auto s = log_.str();
  82. if (s.empty())
  83. return "(empty)";
  84. s.pop_back(); // remove the trailing '\n'
  85. return s;
  86. }
  87. bool operator==(const AllocatorLog& other) const {
  88. return str() == other.str();
  89. }
  90. friend std::ostream& operator<<(std::ostream& os, const AllocatorLog& log) {
  91. os << log.str();
  92. return os;
  93. }
  94. private:
  95. std::ostringstream log_;
  96. };
  97. class SpyingAllocator : public ArduinoJson::Allocator {
  98. public:
  99. SpyingAllocator(
  100. Allocator* upstream = ArduinoJson::detail::DefaultAllocator::instance())
  101. : upstream_(upstream) {}
  102. virtual ~SpyingAllocator() {}
  103. size_t allocatedBytes() const {
  104. return allocatedBytes_;
  105. }
  106. void* allocate(size_t n) override {
  107. auto block = reinterpret_cast<AllocatedBlock*>(
  108. upstream_->allocate(sizeof(AllocatedBlock) + n - 1));
  109. if (block) {
  110. log_.append(Allocate(n));
  111. allocatedBytes_ += n;
  112. block->size = n;
  113. return block->payload;
  114. } else {
  115. log_.append(AllocateFail(n));
  116. return nullptr;
  117. }
  118. }
  119. void deallocate(void* p) override {
  120. auto block = AllocatedBlock::fromPayload(p);
  121. allocatedBytes_ -= block->size;
  122. log_.append(Deallocate(block ? block->size : 0));
  123. upstream_->deallocate(block);
  124. }
  125. void* reallocate(void* p, size_t n) override {
  126. auto block = AllocatedBlock::fromPayload(p);
  127. auto oldSize = block ? block->size : 0;
  128. block = reinterpret_cast<AllocatedBlock*>(
  129. upstream_->reallocate(block, sizeof(AllocatedBlock) + n - 1));
  130. if (block) {
  131. log_.append(Reallocate(oldSize, n));
  132. block->size = n;
  133. allocatedBytes_ += n - oldSize;
  134. return block->payload;
  135. } else {
  136. log_.append(ReallocateFail(oldSize, n));
  137. return nullptr;
  138. }
  139. }
  140. void clearLog() {
  141. log_.clear();
  142. }
  143. const AllocatorLog& log() const {
  144. return log_;
  145. }
  146. private:
  147. struct AllocatedBlock {
  148. size_t size;
  149. char payload[1];
  150. static AllocatedBlock* fromPayload(void* p) {
  151. if (!p)
  152. return nullptr;
  153. return reinterpret_cast<AllocatedBlock*>(
  154. // Cast to void* to silence "cast increases required alignment of
  155. // target type [-Werror=cast-align]"
  156. reinterpret_cast<void*>(reinterpret_cast<char*>(p) -
  157. offsetof(AllocatedBlock, payload)));
  158. }
  159. };
  160. AllocatorLog log_;
  161. Allocator* upstream_;
  162. size_t allocatedBytes_ = 0;
  163. };
  164. class KillswitchAllocator : public ArduinoJson::Allocator {
  165. public:
  166. KillswitchAllocator(
  167. Allocator* upstream = ArduinoJson::detail::DefaultAllocator::instance())
  168. : working_(true), upstream_(upstream) {}
  169. virtual ~KillswitchAllocator() {}
  170. void* allocate(size_t n) override {
  171. return working_ ? upstream_->allocate(n) : 0;
  172. }
  173. void deallocate(void* p) override {
  174. upstream_->deallocate(p);
  175. }
  176. void* reallocate(void* ptr, size_t n) override {
  177. return working_ ? upstream_->reallocate(ptr, n) : 0;
  178. }
  179. // Turn the killswitch on, so all allocation fail
  180. void on() {
  181. working_ = false;
  182. }
  183. private:
  184. bool working_;
  185. Allocator* upstream_;
  186. };
  187. class TimebombAllocator : public ArduinoJson::Allocator {
  188. public:
  189. TimebombAllocator(
  190. size_t initialCountdown,
  191. Allocator* upstream = ArduinoJson::detail::DefaultAllocator::instance())
  192. : countdown_(initialCountdown), upstream_(upstream) {}
  193. virtual ~TimebombAllocator() {}
  194. void* allocate(size_t n) override {
  195. if (!countdown_)
  196. return nullptr;
  197. countdown_--;
  198. return upstream_->allocate(n);
  199. }
  200. void deallocate(void* p) override {
  201. upstream_->deallocate(p);
  202. }
  203. void* reallocate(void* ptr, size_t n) override {
  204. if (!countdown_)
  205. return nullptr;
  206. countdown_--;
  207. return upstream_->reallocate(ptr, n);
  208. }
  209. void setCountdown(size_t value) {
  210. countdown_ = value;
  211. }
  212. private:
  213. size_t countdown_ = 0;
  214. Allocator* upstream_;
  215. };
  216. inline size_t sizeofPoolList(size_t n = ARDUINOJSON_INITIAL_POOL_COUNT) {
  217. return sizeof(ArduinoJson::detail::VariantPool) * n;
  218. }
  219. inline size_t sizeofPool(
  220. ArduinoJson::detail::SlotCount n = ARDUINOJSON_POOL_CAPACITY) {
  221. return ArduinoJson::detail::VariantPool::slotsToBytes(n);
  222. }
  223. inline size_t sizeofStringBuffer(size_t iteration = 1) {
  224. // returns 31, 63, 127, 255, etc.
  225. auto capacity = ArduinoJson::detail::StringBuilder::initialCapacity;
  226. for (size_t i = 1; i < iteration; i++)
  227. capacity = capacity * 2 + 1;
  228. return ArduinoJson::detail::sizeofString(capacity);
  229. }
  230. inline size_t sizeofString(const char* s) {
  231. return ArduinoJson::detail::sizeofString(strlen(s));
  232. }