Added DynamicJsonBuffer::clear()

This commit is contained in:
Benoit Blanchon
2017-06-17 16:48:40 +02:00
parent 789fa507b5
commit 476e5aaa86
6 changed files with 105 additions and 25 deletions

View File

@ -6,6 +6,7 @@ HEAD
* Made `JsonBuffer` non-copyable (PR #524 by @luisrayas3) * Made `JsonBuffer` non-copyable (PR #524 by @luisrayas3)
* Added `StaticJsonBuffer::clear()` * Added `StaticJsonBuffer::clear()`
* Added `DynamicJsonBuffer::clear()`
v5.10.1 v5.10.1
------- -------

View File

@ -46,30 +46,35 @@ class DynamicJsonBufferBase
}; };
public: public:
enum { EmptyBlockSize = sizeof(EmptyBlock) };
DynamicJsonBufferBase(size_t initialSize = 256) DynamicJsonBufferBase(size_t initialSize = 256)
: _head(NULL), _nextBlockCapacity(initialSize) {} : _head(NULL), _nextBlockCapacity(initialSize) {}
~DynamicJsonBufferBase() { ~DynamicJsonBufferBase() {
Block* currentBlock = _head; freeAllBlocks();
while (currentBlock != NULL) {
Block* nextBlock = currentBlock->next;
_allocator.deallocate(currentBlock);
currentBlock = nextBlock;
}
} }
// Gets the number of bytes occupied in the buffer
size_t size() const { size_t size() const {
size_t total = 0; size_t total = 0;
for (const Block* b = _head; b; b = b->next) total += b->size; for (const Block* b = _head; b; b = b->next) total += b->size;
return total; return total;
} }
// Allocates the specified amount of bytes in the buffer
virtual void* alloc(size_t bytes) { virtual void* alloc(size_t bytes) {
alignNextAlloc(); alignNextAlloc();
return canAllocInHead(bytes) ? allocInHead(bytes) : allocInNewBlock(bytes); return canAllocInHead(bytes) ? allocInHead(bytes) : allocInNewBlock(bytes);
} }
// Resets the buffer.
// USE WITH CAUTION: this invalidates all previously allocated data
void clear() {
freeAllBlocks();
_head = 0;
}
class String { class String {
public: public:
String(DynamicJsonBufferBase* parent) String(DynamicJsonBufferBase* parent)
@ -129,7 +134,7 @@ class DynamicJsonBufferBase
} }
bool addNewBlock(size_t capacity) { bool addNewBlock(size_t capacity) {
size_t bytes = sizeof(EmptyBlock) + capacity; size_t bytes = EmptyBlockSize + capacity;
Block* block = static_cast<Block*>(_allocator.allocate(bytes)); Block* block = static_cast<Block*>(_allocator.allocate(bytes));
if (block == NULL) return false; if (block == NULL) return false;
block->capacity = capacity; block->capacity = capacity;
@ -139,6 +144,16 @@ class DynamicJsonBufferBase
return true; return true;
} }
void freeAllBlocks() {
Block* currentBlock = _head;
while (currentBlock != NULL) {
Block* nextBlock = currentBlock->next;
_allocator.deallocate(currentBlock);
currentBlock = nextBlock;
}
}
TAllocator _allocator; TAllocator _allocator;
Block* _head; Block* _head;
size_t _nextBlockCapacity; size_t _nextBlockCapacity;

View File

@ -71,7 +71,7 @@ class StaticJsonBufferBase : public JsonBufferBase<StaticJsonBufferBase> {
return doAlloc(bytes); return doAlloc(bytes);
} }
// Resets the size to zero. // Resets the buffer.
// USE WITH CAUTION: this invalidates all previously allocated data // USE WITH CAUTION: this invalidates all previously allocated data
void clear() { void clear() {
_size = 0; _size = 0;

View File

@ -8,10 +8,11 @@
add_executable(DynamicJsonBufferTests add_executable(DynamicJsonBufferTests
alloc.cpp alloc.cpp
createArray.cpp createArray.cpp
no_memory.cpp
createObject.cpp createObject.cpp
strdup.cpp no_memory.cpp
size.cpp
startString.cpp startString.cpp
strdup.cpp
) )
target_link_libraries(DynamicJsonBufferTests catch) target_link_libraries(DynamicJsonBufferTests catch)

View File

@ -7,6 +7,7 @@
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <catch.hpp> #include <catch.hpp>
#include <sstream>
static bool isAligned(void* ptr) { static bool isAligned(void* ptr) {
const size_t mask = sizeof(void*) - 1; const size_t mask = sizeof(void*) - 1;
@ -14,26 +15,58 @@ static bool isAligned(void* ptr) {
return (addr & mask) == 0; return (addr & mask) == 0;
} }
std::stringstream allocatorLog;
struct SpyingAllocator : DefaultAllocator {
void* allocate(size_t n) {
allocatorLog << "A" << (n - DynamicJsonBuffer::EmptyBlockSize);
return DefaultAllocator::allocate(n);
}
void deallocate(void* p) {
allocatorLog << "F";
return DefaultAllocator::deallocate(p);
}
};
TEST_CASE("DynamicJsonBuffer::alloc()") { TEST_CASE("DynamicJsonBuffer::alloc()") {
DynamicJsonBuffer buffer; SECTION("Returns different pointers") {
DynamicJsonBuffer buffer;
SECTION("InitialSizeIsZero") {
REQUIRE(0 == buffer.size());
}
SECTION("SizeIncreasesAfterAlloc") {
buffer.alloc(1);
REQUIRE(1U <= buffer.size());
buffer.alloc(1);
REQUIRE(2U <= buffer.size());
}
SECTION("ReturnDifferentPointer") {
void* p1 = buffer.alloc(1); void* p1 = buffer.alloc(1);
void* p2 = buffer.alloc(2); void* p2 = buffer.alloc(2);
REQUIRE(p1 != p2); REQUIRE(p1 != p2);
} }
SECTION("Doubles allocation size when full") {
allocatorLog.str("");
{
DynamicJsonBufferBase<SpyingAllocator> buffer(1);
buffer.alloc(1);
buffer.alloc(1);
}
REQUIRE(allocatorLog.str() == "A1A2FF");
}
SECTION("Keeps increasing allocation size after clear") {
allocatorLog.str("");
{
DynamicJsonBufferBase<SpyingAllocator> buffer(1);
buffer.alloc(1);
buffer.alloc(1);
buffer.clear();
buffer.alloc(1);
}
REQUIRE(allocatorLog.str() == "A1A2FFA4F");
}
SECTION("Makes a big allocation when needed") {
allocatorLog.str("");
{
DynamicJsonBufferBase<SpyingAllocator> buffer(1);
buffer.alloc(42);
}
REQUIRE(allocatorLog.str() == "A42F");
}
SECTION("Alignment") { SECTION("Alignment") {
// make room for two but not three // make room for two but not three
DynamicJsonBuffer tinyBuf(2 * sizeof(void*) + 1); DynamicJsonBuffer tinyBuf(2 * sizeof(void*) + 1);

View File

@ -0,0 +1,30 @@
// Copyright Benoit Blanchon 2014-2017
// MIT License
//
// Arduino JSON library
// https://bblanchon.github.io/ArduinoJson/
// If you like this project, please add a star!
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("DynamicJsonBuffer::size()") {
DynamicJsonBuffer buffer;
SECTION("Initial size is 0") {
REQUIRE(0 == buffer.size());
}
SECTION("Increases after alloc()") {
buffer.alloc(1);
REQUIRE(1U <= buffer.size());
buffer.alloc(1);
REQUIRE(2U <= buffer.size());
}
SECTION("Goes back to 0 after clear()") {
buffer.alloc(1);
buffer.clear();
REQUIRE(0 == buffer.size());
}
}