[209] | 1 | // Copyright Benoit Blanchon 2014-2016
|
---|
| 2 | // MIT License
|
---|
| 3 | //
|
---|
| 4 | // Arduino JSON library
|
---|
| 5 | // https://github.com/bblanchon/ArduinoJson
|
---|
| 6 | // If you like this project, please add a star!
|
---|
| 7 |
|
---|
| 8 | #pragma once
|
---|
| 9 |
|
---|
| 10 | #include "../JsonBuffer.hpp"
|
---|
| 11 |
|
---|
| 12 | #include <stdlib.h>
|
---|
| 13 |
|
---|
| 14 | namespace ArduinoJson {
|
---|
| 15 | namespace Internals {
|
---|
| 16 | class DefaultAllocator {
|
---|
| 17 | public:
|
---|
| 18 | void* allocate(size_t size) { return malloc(size); }
|
---|
| 19 | void deallocate(void* pointer) { free(pointer); }
|
---|
| 20 | };
|
---|
| 21 |
|
---|
| 22 | template <typename TAllocator>
|
---|
| 23 | class BlockJsonBuffer : public JsonBuffer {
|
---|
| 24 | struct Block;
|
---|
| 25 | struct EmptyBlock {
|
---|
| 26 | Block* next;
|
---|
| 27 | size_t capacity;
|
---|
| 28 | size_t size;
|
---|
| 29 | };
|
---|
| 30 | struct Block : EmptyBlock {
|
---|
| 31 | uint8_t data[1];
|
---|
| 32 | };
|
---|
| 33 |
|
---|
| 34 | public:
|
---|
| 35 | BlockJsonBuffer(size_t initialSize = 256)
|
---|
| 36 | : _head(NULL), _nextBlockSize(initialSize) {}
|
---|
| 37 |
|
---|
| 38 | ~BlockJsonBuffer() {
|
---|
| 39 | Block* currentBlock = _head;
|
---|
| 40 |
|
---|
| 41 | while (currentBlock != NULL) {
|
---|
| 42 | Block* nextBlock = currentBlock->next;
|
---|
| 43 | _allocator.deallocate(currentBlock);
|
---|
| 44 | currentBlock = nextBlock;
|
---|
| 45 | }
|
---|
| 46 | }
|
---|
| 47 |
|
---|
| 48 | size_t size() const {
|
---|
| 49 | size_t total = 0;
|
---|
| 50 | for (const Block* b = _head; b; b = b->next) total += b->size;
|
---|
| 51 | return total;
|
---|
| 52 | }
|
---|
| 53 |
|
---|
| 54 | protected:
|
---|
| 55 | virtual void* alloc(size_t bytes) {
|
---|
| 56 | return canAllocInHead(bytes) ? allocInHead(bytes) : allocInNewBlock(bytes);
|
---|
| 57 | }
|
---|
| 58 |
|
---|
| 59 | private:
|
---|
| 60 | bool canAllocInHead(size_t bytes) const {
|
---|
| 61 | return _head != NULL && _head->size + bytes <= _head->capacity;
|
---|
| 62 | }
|
---|
| 63 |
|
---|
| 64 | void* allocInHead(size_t bytes) {
|
---|
| 65 | void* p = _head->data + _head->size;
|
---|
| 66 | _head->size += round_size_up(bytes);
|
---|
| 67 | return p;
|
---|
| 68 | }
|
---|
| 69 |
|
---|
| 70 | void* allocInNewBlock(size_t bytes) {
|
---|
| 71 | size_t capacity = _nextBlockSize;
|
---|
| 72 | if (bytes > capacity) capacity = bytes;
|
---|
| 73 | if (!addNewBlock(capacity)) return NULL;
|
---|
| 74 | _nextBlockSize *= 2;
|
---|
| 75 | return allocInHead(bytes);
|
---|
| 76 | }
|
---|
| 77 |
|
---|
| 78 | bool addNewBlock(size_t capacity) {
|
---|
| 79 | size_t bytes = sizeof(EmptyBlock) + capacity;
|
---|
| 80 | Block* block = static_cast<Block*>(_allocator.allocate(bytes));
|
---|
| 81 | if (block == NULL) return false;
|
---|
| 82 | block->capacity = capacity;
|
---|
| 83 | block->size = 0;
|
---|
| 84 | block->next = _head;
|
---|
| 85 | _head = block;
|
---|
| 86 | return true;
|
---|
| 87 | }
|
---|
| 88 |
|
---|
| 89 | TAllocator _allocator;
|
---|
| 90 | Block* _head;
|
---|
| 91 | size_t _nextBlockSize;
|
---|
| 92 | };
|
---|
| 93 | }
|
---|
| 94 | }
|
---|