forked from bblanchon/ArduinoJson
Merged the two StringBuilder classes into one
This commit is contained in:
@ -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;
|
||||
|
@ -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!
|
||||
|
@ -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;
|
||||
}
|
||||
|
35
src/ArduinoJson/Memory/StringBuilder.hpp
Normal file
35
src/ArduinoJson/Memory/StringBuilder.hpp
Normal 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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user