Merged the two StringBuilder classes into one

This commit is contained in:
Benoit Blanchon
2018-10-18 17:54:33 +02:00
parent 1a4515c0b9
commit ae089dcff7
9 changed files with 91 additions and 102 deletions

View File

@ -6,6 +6,7 @@
#include "../Strings/StringInMemoryPool.hpp"
#include "MemoryPool.hpp"
#include "StringBuilder.hpp"
#include <stdlib.h> // malloc, free
@ -39,7 +40,7 @@ class DynamicMemoryPoolBase : public MemoryPool {
size_t size;
};
struct Block : EmptyBlock {
uint8_t data[1];
char data[1];
};
public:
@ -64,11 +65,23 @@ class DynamicMemoryPoolBase : public MemoryPool {
}
// Allocates the specified amount of bytes in the memoryPool
virtual void* alloc(size_t bytes) {
virtual char* alloc(size_t bytes) {
alignNextAlloc();
return canAllocInHead(bytes) ? allocInHead(bytes) : allocInNewBlock(bytes);
}
virtual char* realloc(char* oldPtr, size_t oldSize, size_t newSize) {
size_t n = newSize - oldSize;
if (canAllocInHead(n)) {
allocInHead(n);
return oldPtr;
} else {
char* newPtr = allocInNewBlock(newSize);
if (oldPtr && newPtr) memcpy(newPtr, oldPtr, oldSize);
return newPtr;
}
}
// Resets the memoryPool.
// USE WITH CAUTION: this invalidates all previously allocated data
void clear() {
@ -82,37 +95,6 @@ class DynamicMemoryPoolBase : public MemoryPool {
_head = 0;
}
class StringBuilder {
public:
explicit StringBuilder(DynamicMemoryPoolBase* 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++;
}
StringInMemoryPool complete() {
append(0);
return _start;
}
private:
DynamicMemoryPoolBase* _parent;
char* _start;
size_t _length;
};
StringBuilder startString() {
return StringBuilder(this);
}
@ -126,13 +108,13 @@ class DynamicMemoryPoolBase : public MemoryPool {
return _head != NULL && _head->size + bytes <= _head->capacity;
}
void* allocInHead(size_t bytes) {
void* p = _head->data + _head->size;
char* allocInHead(size_t bytes) {
char* p = _head->data + _head->size;
_head->size += bytes;
return p;
}
void* allocInNewBlock(size_t bytes) {
char* allocInNewBlock(size_t bytes) {
size_t capacity = _nextBlockCapacity;
if (bytes > capacity) capacity = bytes;
if (!addNewBlock(capacity)) return NULL;

View File

@ -19,7 +19,9 @@ class MemoryPool {
public:
// Allocates n bytes in the MemoryPool.
// Return a pointer to the allocated memory or NULL if allocation fails.
virtual void *alloc(size_t size) = 0;
virtual char *alloc(size_t size) = 0;
virtual char *realloc(char *oldPtr, size_t oldSize, size_t newSize) = 0;
protected:
// CAUTION: NO VIRTUAL DESTRUCTOR!

View File

@ -7,39 +7,12 @@
#include "../Polyfills/mpl/max.hpp"
#include "../Strings/StringInMemoryPool.hpp"
#include "MemoryPool.hpp"
#include "StringBuilder.hpp"
namespace ARDUINOJSON_NAMESPACE {
class StaticMemoryPoolBase : public MemoryPool {
public:
class StringBuilder {
public:
explicit StringBuilder(StaticMemoryPoolBase* parent) : _parent(parent) {
_start = parent->_buffer + parent->_size;
}
void append(char c) {
if (_parent->canAlloc(1)) {
char* last = static_cast<char*>(_parent->doAlloc(1));
*last = c;
}
}
StringInMemoryPool complete() const {
if (_parent->canAlloc(1)) {
char* last = static_cast<char*>(_parent->doAlloc(1));
*last = '\0';
return _start;
} else {
return NULL;
}
}
private:
StaticMemoryPoolBase* _parent;
char* _start;
};
// Gets the capacity of the memoryPool in bytes
size_t capacity() const {
return _capacity;
@ -51,12 +24,19 @@ class StaticMemoryPoolBase : public MemoryPool {
}
// Allocates the specified amount of bytes in the memoryPool
virtual void* alloc(size_t bytes) {
virtual char* alloc(size_t bytes) {
alignNextAlloc();
if (!canAlloc(bytes)) return NULL;
return doAlloc(bytes);
}
virtual char* realloc(char* oldPtr, size_t oldSize, size_t newSize) {
size_t n = newSize - oldSize;
if (!canAlloc(n)) return NULL;
doAlloc(n);
return oldPtr;
}
// Resets the memoryPool.
// USE WITH CAUTION: this invalidates all previously allocated data
void clear() {
@ -82,8 +62,8 @@ class StaticMemoryPoolBase : public MemoryPool {
return _size + bytes <= _capacity;
}
void* doAlloc(size_t bytes) {
void* p = &_buffer[_size];
char* doAlloc(size_t bytes) {
char* p = &_buffer[_size];
_size += bytes;
return p;
}

View File

@ -0,0 +1,35 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include "../Strings/StringInMemoryPool.hpp"
#include "MemoryPool.hpp"
namespace ARDUINOJSON_NAMESPACE {
class StringBuilder {
public:
explicit StringBuilder(MemoryPool* parent)
: _parent(parent), _start(0), _size(0) {
_start = _parent->alloc(1);
}
void append(char c) {
_start = _parent->realloc(_start, _size + 1, _size + 2);
if (_start) _start[_size++] = c;
}
StringInMemoryPool complete() {
if (_start) _start[_size] = 0;
return _start;
}
private:
MemoryPool* _parent;
char* _start;
size_t _size;
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -4,20 +4,22 @@
#pragma once
#include "../Memory/MemoryPool.hpp"
#include "../Memory/StringBuilder.hpp"
namespace ARDUINOJSON_NAMESPACE {
template <typename TMemoryPool>
class StringCopier {
public:
StringCopier(TMemoryPool& memoryPool) : _memoryPool(&memoryPool) {}
typedef ARDUINOJSON_NAMESPACE::StringBuilder StringBuilder;
typedef typename TMemoryPool::StringBuilder StringBuilder;
StringCopier(MemoryPool* memoryPool) : _memoryPool(memoryPool) {}
StringBuilder startString() {
return _memoryPool->startString();
return StringBuilder(_memoryPool);
}
private:
TMemoryPool* _memoryPool;
MemoryPool* _memoryPool;
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -9,34 +9,34 @@
namespace ARDUINOJSON_NAMESPACE {
template <typename TMemoryPool, typename TInput, typename Enable = void>
template <typename TInput, typename Enable = void>
struct StringStorage {
typedef StringCopier<TMemoryPool> type;
typedef StringCopier type;
static type create(TMemoryPool& jb, TInput&) {
return type(jb);
static type create(MemoryPool& pool, TInput&) {
return type(&pool);
}
};
template <typename TMemoryPool, typename TChar>
struct StringStorage<TMemoryPool, TChar*,
template <typename TChar>
struct StringStorage<TChar*,
typename enable_if<!is_const<TChar>::value>::type> {
typedef StringMover<TChar> type;
static type create(TMemoryPool&, TChar* input) {
static type create(MemoryPool&, TChar* input) {
return type(input);
}
};
template <typename TMemoryPool, typename TInput>
typename StringStorage<TMemoryPool, TInput>::type makeStringStorage(
TMemoryPool& jb, TInput& input) {
return StringStorage<TMemoryPool, TInput>::create(jb, input);
template <typename TInput>
typename StringStorage<TInput>::type makeStringStorage(MemoryPool& pool,
TInput& input) {
return StringStorage<TInput>::create(pool, input);
}
template <typename TMemoryPool, typename TChar>
typename StringStorage<TMemoryPool, TChar*>::type makeStringStorage(
TMemoryPool& jb, TChar* input) {
return StringStorage<TMemoryPool, TChar*>::create(jb, input);
template <typename TChar>
typename StringStorage<TChar*>::type makeStringStorage(MemoryPool& pool,
TChar* input) {
return StringStorage<TChar*>::create(pool, input);
}
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -17,8 +17,6 @@ struct NoMemoryAllocator {
TEST_CASE("DynamicMemoryPool no memory") {
DynamicMemoryPoolBase<NoMemoryAllocator> _memoryPool;
typedef DynamicMemoryPoolBase<NoMemoryAllocator>::StringBuilder StringBuilder;
SECTION("FixCodeCoverage") {
// call this function to fix code coverage
NoMemoryAllocator().deallocate(NULL);

View File

@ -7,8 +7,6 @@
using namespace ARDUINOJSON_NAMESPACE;
typedef DynamicMemoryPool::StringBuilder StringBuilder;
TEST_CASE("DynamicMemoryPool::startString()") {
SECTION("WorksWhenBufferIsBigEnough") {
DynamicMemoryPool memoryPool(6);
@ -40,12 +38,9 @@ TEST_CASE("DynamicMemoryPool::startString()") {
DynamicMemoryPool memoryPool(5);
StringBuilder str = memoryPool.startString();
REQUIRE(0 == memoryPool.size());
str.append('h');
REQUIRE(1 == memoryPool.size());
str.complete();
REQUIRE(2 == memoryPool.size());
}
}

View File

@ -8,8 +8,6 @@
using namespace ARDUINOJSON_NAMESPACE;
TEST_CASE("StaticMemoryPool::startString()") {
typedef StaticMemoryPoolBase::StringBuilder StringBuilder;
SECTION("WorksWhenBufferIsBigEnough") {
StaticMemoryPool<6> memoryPool;
@ -40,12 +38,9 @@ TEST_CASE("StaticMemoryPool::startString()") {
StaticMemoryPool<5> memoryPool;
StringBuilder str = memoryPool.startString();
REQUIRE(0 == memoryPool.size());
str.append('h');
REQUIRE(1 == memoryPool.size());
str.complete();
REQUIRE(2 == memoryPool.size());
}
}