diff options
Diffstat (limited to 'include/lib/ArduinoJson/DynamicJsonBuffer.hpp')
-rw-r--r-- | include/lib/ArduinoJson/DynamicJsonBuffer.hpp | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/include/lib/ArduinoJson/DynamicJsonBuffer.hpp b/include/lib/ArduinoJson/DynamicJsonBuffer.hpp new file mode 100644 index 0000000..bdbd5dd --- /dev/null +++ b/include/lib/ArduinoJson/DynamicJsonBuffer.hpp @@ -0,0 +1,170 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 +// MIT License + +#pragma once + +#include "JsonBufferBase.hpp" + +#include <stdlib.h> + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnon-virtual-dtor" +#elif defined(__GNUC__) +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) +#pragma GCC diagnostic push +#endif +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +#endif + +namespace ArduinoJson { +namespace Internals { +class DefaultAllocator { + public: + void* allocate(size_t size) { + return malloc(size); + } + void deallocate(void* pointer) { + free(pointer); + } +}; + +template <typename TAllocator> +class DynamicJsonBufferBase + : public JsonBufferBase<DynamicJsonBufferBase<TAllocator> > { + struct Block; + struct EmptyBlock { + Block* next; + size_t capacity; + size_t size; + }; + struct Block : EmptyBlock { + uint8_t data[1]; + }; + + public: + enum { EmptyBlockSize = sizeof(EmptyBlock) }; + + DynamicJsonBufferBase(size_t initialSize = 256) + : _head(NULL), _nextBlockCapacity(initialSize) {} + + ~DynamicJsonBufferBase() { + clear(); + } + + // Gets the number of bytes occupied in the buffer + size_t size() const { + size_t total = 0; + for (const Block* b = _head; b; b = b->next) total += b->size; + return total; + } + + // Allocates the specified amount of bytes in the buffer + virtual void* alloc(size_t bytes) { + alignNextAlloc(); + return canAllocInHead(bytes) ? allocInHead(bytes) : allocInNewBlock(bytes); + } + + // Resets the buffer. + // USE WITH CAUTION: this invalidates all previously allocated data + void clear() { + Block* currentBlock = _head; + while (currentBlock != NULL) { + _nextBlockCapacity = currentBlock->capacity; + Block* nextBlock = currentBlock->next; + _allocator.deallocate(currentBlock); + currentBlock = nextBlock; + } + _head = 0; + } + + class String { + public: + String(DynamicJsonBufferBase* parent) + : _parent(parent), _start(NULL), _length(0) {} + + void append(char c) { + if (_parent->canAllocInHead(1)) { + char* end = static_cast<char*>(_parent->allocInHead(1)); + *end = c; + if (_length == 0) _start = end; + } else { + char* newStart = + static_cast<char*>(_parent->allocInNewBlock(_length + 1)); + if (_start && newStart) memcpy(newStart, _start, _length); + if (newStart) newStart[_length] = c; + _start = newStart; + } + _length++; + } + + const char* c_str() { + append(0); + return _start; + } + + private: + DynamicJsonBufferBase* _parent; + char* _start; + size_t _length; + }; + + String startString() { + return String(this); + } + + private: + void alignNextAlloc() { + if (_head) _head->size = this->round_size_up(_head->size); + } + + bool canAllocInHead(size_t bytes) const { + return _head != NULL && _head->size + bytes <= _head->capacity; + } + + void* allocInHead(size_t bytes) { + void* p = _head->data + _head->size; + _head->size += bytes; + return p; + } + + void* allocInNewBlock(size_t bytes) { + size_t capacity = _nextBlockCapacity; + if (bytes > capacity) capacity = bytes; + if (!addNewBlock(capacity)) return NULL; + _nextBlockCapacity *= 2; + return allocInHead(bytes); + } + + bool addNewBlock(size_t capacity) { + size_t bytes = EmptyBlockSize + capacity; + Block* block = static_cast<Block*>(_allocator.allocate(bytes)); + if (block == NULL) return false; + block->capacity = capacity; + block->size = 0; + block->next = _head; + _head = block; + return true; + } + + TAllocator _allocator; + Block* _head; + size_t _nextBlockCapacity; +}; +} + +#if defined(__clang__) +#pragma clang diagnostic pop +#elif defined(__GNUC__) +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) +#pragma GCC diagnostic pop +#endif +#endif + +// Implements a JsonBuffer with dynamic memory allocation. +// You are strongly encouraged to consider using StaticJsonBuffer which is much +// more suitable for embedded systems. +typedef Internals::DynamicJsonBufferBase<Internals::DefaultAllocator> + DynamicJsonBuffer; +} |