| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288 |
- // ArduinoJson - https://arduinojson.org
- // Copyright © 2014-2024, Benoit BLANCHON
- // MIT License
- #pragma once
- #include <ArduinoJson/Memory/Allocator.hpp>
- #include <ArduinoJson/Memory/MemoryPool.hpp>
- #include <ArduinoJson/Memory/StringBuilder.hpp>
- #include <sstream>
- namespace {
- struct FailingAllocator : ArduinoJson::Allocator {
- static FailingAllocator* instance() {
- static FailingAllocator allocator;
- return &allocator;
- }
- private:
- FailingAllocator() = default;
- ~FailingAllocator() = default;
- void* allocate(size_t) override {
- return nullptr;
- }
- void deallocate(void*) override {}
- void* reallocate(void*, size_t) override {
- return nullptr;
- }
- };
- class AllocatorLogEntry {
- public:
- AllocatorLogEntry(std::string s, size_t n = 1) : str_(s), count_(n) {}
- const std::string& str() const {
- return str_;
- }
- size_t count() const {
- return count_;
- }
- AllocatorLogEntry operator*(size_t n) const {
- return AllocatorLogEntry(str_, n);
- }
- private:
- std::string str_;
- size_t count_;
- };
- inline AllocatorLogEntry Allocate(size_t s) {
- char buffer[32];
- snprintf(buffer, sizeof(buffer), "allocate(%zu)", s);
- return AllocatorLogEntry(buffer);
- }
- inline AllocatorLogEntry AllocateFail(size_t s) {
- char buffer[32];
- snprintf(buffer, sizeof(buffer), "allocate(%zu) -> nullptr", s);
- return AllocatorLogEntry(buffer);
- }
- inline AllocatorLogEntry Reallocate(size_t s1, size_t s2) {
- char buffer[32];
- snprintf(buffer, sizeof(buffer), "reallocate(%zu, %zu)", s1, s2);
- return AllocatorLogEntry(buffer);
- }
- inline AllocatorLogEntry ReallocateFail(size_t s1, size_t s2) {
- char buffer[32];
- snprintf(buffer, sizeof(buffer), "reallocate(%zu, %zu) -> nullptr", s1, s2);
- return AllocatorLogEntry(buffer);
- }
- inline AllocatorLogEntry Deallocate(size_t s) {
- char buffer[32];
- snprintf(buffer, sizeof(buffer), "deallocate(%zu)", s);
- return AllocatorLogEntry(buffer);
- }
- class AllocatorLog {
- public:
- AllocatorLog() = default;
- AllocatorLog(std::initializer_list<AllocatorLogEntry> list) {
- for (auto& entry : list)
- append(entry);
- }
- void clear() {
- log_.str("");
- }
- void append(const AllocatorLogEntry& entry) {
- for (size_t i = 0; i < entry.count(); i++)
- log_ << entry.str() << "\n";
- }
- std::string str() const {
- auto s = log_.str();
- if (s.empty())
- return "(empty)";
- s.pop_back(); // remove the trailing '\n'
- return s;
- }
- bool operator==(const AllocatorLog& other) const {
- return str() == other.str();
- }
- friend std::ostream& operator<<(std::ostream& os, const AllocatorLog& log) {
- os << log.str();
- return os;
- }
- private:
- std::ostringstream log_;
- };
- class SpyingAllocator : public ArduinoJson::Allocator {
- public:
- SpyingAllocator(
- Allocator* upstream = ArduinoJson::detail::DefaultAllocator::instance())
- : upstream_(upstream) {}
- virtual ~SpyingAllocator() {}
- size_t allocatedBytes() const {
- return allocatedBytes_;
- }
- void* allocate(size_t n) override {
- auto block = reinterpret_cast<AllocatedBlock*>(
- upstream_->allocate(sizeof(AllocatedBlock) + n - 1));
- if (block) {
- log_.append(Allocate(n));
- allocatedBytes_ += n;
- block->size = n;
- return block->payload;
- } else {
- log_.append(AllocateFail(n));
- return nullptr;
- }
- }
- void deallocate(void* p) override {
- auto block = AllocatedBlock::fromPayload(p);
- allocatedBytes_ -= block->size;
- log_.append(Deallocate(block ? block->size : 0));
- upstream_->deallocate(block);
- }
- void* reallocate(void* p, size_t n) override {
- auto block = AllocatedBlock::fromPayload(p);
- auto oldSize = block ? block->size : 0;
- block = reinterpret_cast<AllocatedBlock*>(
- upstream_->reallocate(block, sizeof(AllocatedBlock) + n - 1));
- if (block) {
- log_.append(Reallocate(oldSize, n));
- block->size = n;
- allocatedBytes_ += n - oldSize;
- return block->payload;
- } else {
- log_.append(ReallocateFail(oldSize, n));
- return nullptr;
- }
- }
- void clearLog() {
- log_.clear();
- }
- const AllocatorLog& log() const {
- return log_;
- }
- private:
- struct AllocatedBlock {
- size_t size;
- char payload[1];
- static AllocatedBlock* fromPayload(void* p) {
- if (!p)
- return nullptr;
- return reinterpret_cast<AllocatedBlock*>(
- // Cast to void* to silence "cast increases required alignment of
- // target type [-Werror=cast-align]"
- reinterpret_cast<void*>(reinterpret_cast<char*>(p) -
- offsetof(AllocatedBlock, payload)));
- }
- };
- AllocatorLog log_;
- Allocator* upstream_;
- size_t allocatedBytes_ = 0;
- };
- class KillswitchAllocator : public ArduinoJson::Allocator {
- public:
- KillswitchAllocator(
- Allocator* upstream = ArduinoJson::detail::DefaultAllocator::instance())
- : working_(true), upstream_(upstream) {}
- virtual ~KillswitchAllocator() {}
- void* allocate(size_t n) override {
- return working_ ? upstream_->allocate(n) : 0;
- }
- void deallocate(void* p) override {
- upstream_->deallocate(p);
- }
- void* reallocate(void* ptr, size_t n) override {
- return working_ ? upstream_->reallocate(ptr, n) : 0;
- }
- // Turn the killswitch on, so all allocation fail
- void on() {
- working_ = false;
- }
- private:
- bool working_;
- Allocator* upstream_;
- };
- class TimebombAllocator : public ArduinoJson::Allocator {
- public:
- TimebombAllocator(
- size_t initialCountdown,
- Allocator* upstream = ArduinoJson::detail::DefaultAllocator::instance())
- : countdown_(initialCountdown), upstream_(upstream) {}
- virtual ~TimebombAllocator() {}
- void* allocate(size_t n) override {
- if (!countdown_)
- return nullptr;
- countdown_--;
- return upstream_->allocate(n);
- }
- void deallocate(void* p) override {
- upstream_->deallocate(p);
- }
- void* reallocate(void* ptr, size_t n) override {
- if (!countdown_)
- return nullptr;
- countdown_--;
- return upstream_->reallocate(ptr, n);
- }
- void setCountdown(size_t value) {
- countdown_ = value;
- }
- private:
- size_t countdown_ = 0;
- Allocator* upstream_;
- };
- } // namespace
- inline size_t sizeofPoolList(size_t n = ARDUINOJSON_INITIAL_POOL_COUNT) {
- using namespace ArduinoJson::detail;
- return sizeof(MemoryPool<VariantData>) * n;
- }
- inline size_t sizeofPool(
- ArduinoJson::detail::SlotCount n = ARDUINOJSON_POOL_CAPACITY) {
- using namespace ArduinoJson::detail;
- return MemoryPool<VariantData>::slotsToBytes(n);
- }
- inline size_t sizeofStringBuffer(size_t iteration = 1) {
- // returns 31, 63, 127, 255, etc.
- auto capacity = ArduinoJson::detail::StringBuilder::initialCapacity;
- for (size_t i = 1; i < iteration; i++)
- capacity = capacity * 2 + 1;
- return ArduinoJson::detail::sizeofString(capacity);
- }
- inline size_t sizeofString(const char* s) {
- return ArduinoJson::detail::sizeofString(strlen(s));
- }
|