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 "../Strings/StringInMemoryPool.hpp"
|
||||||
#include "MemoryPool.hpp"
|
#include "MemoryPool.hpp"
|
||||||
|
#include "StringBuilder.hpp"
|
||||||
|
|
||||||
#include <stdlib.h> // malloc, free
|
#include <stdlib.h> // malloc, free
|
||||||
|
|
||||||
@ -39,7 +40,7 @@ class DynamicMemoryPoolBase : public MemoryPool {
|
|||||||
size_t size;
|
size_t size;
|
||||||
};
|
};
|
||||||
struct Block : EmptyBlock {
|
struct Block : EmptyBlock {
|
||||||
uint8_t data[1];
|
char data[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -64,11 +65,23 @@ class DynamicMemoryPoolBase : public MemoryPool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Allocates the specified amount of bytes in the memoryPool
|
// Allocates the specified amount of bytes in the memoryPool
|
||||||
virtual void* alloc(size_t bytes) {
|
virtual char* alloc(size_t bytes) {
|
||||||
alignNextAlloc();
|
alignNextAlloc();
|
||||||
return canAllocInHead(bytes) ? allocInHead(bytes) : allocInNewBlock(bytes);
|
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.
|
// Resets the memoryPool.
|
||||||
// USE WITH CAUTION: this invalidates all previously allocated data
|
// USE WITH CAUTION: this invalidates all previously allocated data
|
||||||
void clear() {
|
void clear() {
|
||||||
@ -82,37 +95,6 @@ class DynamicMemoryPoolBase : public MemoryPool {
|
|||||||
_head = 0;
|
_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() {
|
StringBuilder startString() {
|
||||||
return StringBuilder(this);
|
return StringBuilder(this);
|
||||||
}
|
}
|
||||||
@ -126,13 +108,13 @@ class DynamicMemoryPoolBase : public MemoryPool {
|
|||||||
return _head != NULL && _head->size + bytes <= _head->capacity;
|
return _head != NULL && _head->size + bytes <= _head->capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* allocInHead(size_t bytes) {
|
char* allocInHead(size_t bytes) {
|
||||||
void* p = _head->data + _head->size;
|
char* p = _head->data + _head->size;
|
||||||
_head->size += bytes;
|
_head->size += bytes;
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* allocInNewBlock(size_t bytes) {
|
char* allocInNewBlock(size_t bytes) {
|
||||||
size_t capacity = _nextBlockCapacity;
|
size_t capacity = _nextBlockCapacity;
|
||||||
if (bytes > capacity) capacity = bytes;
|
if (bytes > capacity) capacity = bytes;
|
||||||
if (!addNewBlock(capacity)) return NULL;
|
if (!addNewBlock(capacity)) return NULL;
|
||||||
|
@ -19,7 +19,9 @@ class MemoryPool {
|
|||||||
public:
|
public:
|
||||||
// Allocates n bytes in the MemoryPool.
|
// Allocates n bytes in the MemoryPool.
|
||||||
// Return a pointer to the allocated memory or NULL if allocation fails.
|
// 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:
|
protected:
|
||||||
// CAUTION: NO VIRTUAL DESTRUCTOR!
|
// CAUTION: NO VIRTUAL DESTRUCTOR!
|
||||||
|
@ -7,39 +7,12 @@
|
|||||||
#include "../Polyfills/mpl/max.hpp"
|
#include "../Polyfills/mpl/max.hpp"
|
||||||
#include "../Strings/StringInMemoryPool.hpp"
|
#include "../Strings/StringInMemoryPool.hpp"
|
||||||
#include "MemoryPool.hpp"
|
#include "MemoryPool.hpp"
|
||||||
|
#include "StringBuilder.hpp"
|
||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
class StaticMemoryPoolBase : public MemoryPool {
|
class StaticMemoryPoolBase : public MemoryPool {
|
||||||
public:
|
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
|
// Gets the capacity of the memoryPool in bytes
|
||||||
size_t capacity() const {
|
size_t capacity() const {
|
||||||
return _capacity;
|
return _capacity;
|
||||||
@ -51,12 +24,19 @@ class StaticMemoryPoolBase : public MemoryPool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Allocates the specified amount of bytes in the memoryPool
|
// Allocates the specified amount of bytes in the memoryPool
|
||||||
virtual void* alloc(size_t bytes) {
|
virtual char* alloc(size_t bytes) {
|
||||||
alignNextAlloc();
|
alignNextAlloc();
|
||||||
if (!canAlloc(bytes)) return NULL;
|
if (!canAlloc(bytes)) return NULL;
|
||||||
return doAlloc(bytes);
|
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.
|
// Resets the memoryPool.
|
||||||
// USE WITH CAUTION: this invalidates all previously allocated data
|
// USE WITH CAUTION: this invalidates all previously allocated data
|
||||||
void clear() {
|
void clear() {
|
||||||
@ -82,8 +62,8 @@ class StaticMemoryPoolBase : public MemoryPool {
|
|||||||
return _size + bytes <= _capacity;
|
return _size + bytes <= _capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* doAlloc(size_t bytes) {
|
char* doAlloc(size_t bytes) {
|
||||||
void* p = &_buffer[_size];
|
char* p = &_buffer[_size];
|
||||||
_size += bytes;
|
_size += bytes;
|
||||||
return p;
|
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
|
#pragma once
|
||||||
|
|
||||||
|
#include "../Memory/MemoryPool.hpp"
|
||||||
|
#include "../Memory/StringBuilder.hpp"
|
||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
template <typename TMemoryPool>
|
|
||||||
class StringCopier {
|
class StringCopier {
|
||||||
public:
|
public:
|
||||||
StringCopier(TMemoryPool& memoryPool) : _memoryPool(&memoryPool) {}
|
typedef ARDUINOJSON_NAMESPACE::StringBuilder StringBuilder;
|
||||||
|
|
||||||
typedef typename TMemoryPool::StringBuilder StringBuilder;
|
StringCopier(MemoryPool* memoryPool) : _memoryPool(memoryPool) {}
|
||||||
|
|
||||||
StringBuilder startString() {
|
StringBuilder startString() {
|
||||||
return _memoryPool->startString();
|
return StringBuilder(_memoryPool);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TMemoryPool* _memoryPool;
|
MemoryPool* _memoryPool;
|
||||||
};
|
};
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
|
@ -9,34 +9,34 @@
|
|||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
template <typename TMemoryPool, typename TInput, typename Enable = void>
|
template <typename TInput, typename Enable = void>
|
||||||
struct StringStorage {
|
struct StringStorage {
|
||||||
typedef StringCopier<TMemoryPool> type;
|
typedef StringCopier type;
|
||||||
|
|
||||||
static type create(TMemoryPool& jb, TInput&) {
|
static type create(MemoryPool& pool, TInput&) {
|
||||||
return type(jb);
|
return type(&pool);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename TMemoryPool, typename TChar>
|
template <typename TChar>
|
||||||
struct StringStorage<TMemoryPool, TChar*,
|
struct StringStorage<TChar*,
|
||||||
typename enable_if<!is_const<TChar>::value>::type> {
|
typename enable_if<!is_const<TChar>::value>::type> {
|
||||||
typedef StringMover<TChar> type;
|
typedef StringMover<TChar> type;
|
||||||
|
|
||||||
static type create(TMemoryPool&, TChar* input) {
|
static type create(MemoryPool&, TChar* input) {
|
||||||
return type(input);
|
return type(input);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename TMemoryPool, typename TInput>
|
template <typename TInput>
|
||||||
typename StringStorage<TMemoryPool, TInput>::type makeStringStorage(
|
typename StringStorage<TInput>::type makeStringStorage(MemoryPool& pool,
|
||||||
TMemoryPool& jb, TInput& input) {
|
TInput& input) {
|
||||||
return StringStorage<TMemoryPool, TInput>::create(jb, input);
|
return StringStorage<TInput>::create(pool, input);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TMemoryPool, typename TChar>
|
template <typename TChar>
|
||||||
typename StringStorage<TMemoryPool, TChar*>::type makeStringStorage(
|
typename StringStorage<TChar*>::type makeStringStorage(MemoryPool& pool,
|
||||||
TMemoryPool& jb, TChar* input) {
|
TChar* input) {
|
||||||
return StringStorage<TMemoryPool, TChar*>::create(jb, input);
|
return StringStorage<TChar*>::create(pool, input);
|
||||||
}
|
}
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
|
@ -17,8 +17,6 @@ struct NoMemoryAllocator {
|
|||||||
TEST_CASE("DynamicMemoryPool no memory") {
|
TEST_CASE("DynamicMemoryPool no memory") {
|
||||||
DynamicMemoryPoolBase<NoMemoryAllocator> _memoryPool;
|
DynamicMemoryPoolBase<NoMemoryAllocator> _memoryPool;
|
||||||
|
|
||||||
typedef DynamicMemoryPoolBase<NoMemoryAllocator>::StringBuilder StringBuilder;
|
|
||||||
|
|
||||||
SECTION("FixCodeCoverage") {
|
SECTION("FixCodeCoverage") {
|
||||||
// call this function to fix code coverage
|
// call this function to fix code coverage
|
||||||
NoMemoryAllocator().deallocate(NULL);
|
NoMemoryAllocator().deallocate(NULL);
|
||||||
|
@ -7,8 +7,6 @@
|
|||||||
|
|
||||||
using namespace ARDUINOJSON_NAMESPACE;
|
using namespace ARDUINOJSON_NAMESPACE;
|
||||||
|
|
||||||
typedef DynamicMemoryPool::StringBuilder StringBuilder;
|
|
||||||
|
|
||||||
TEST_CASE("DynamicMemoryPool::startString()") {
|
TEST_CASE("DynamicMemoryPool::startString()") {
|
||||||
SECTION("WorksWhenBufferIsBigEnough") {
|
SECTION("WorksWhenBufferIsBigEnough") {
|
||||||
DynamicMemoryPool memoryPool(6);
|
DynamicMemoryPool memoryPool(6);
|
||||||
@ -40,12 +38,9 @@ TEST_CASE("DynamicMemoryPool::startString()") {
|
|||||||
DynamicMemoryPool memoryPool(5);
|
DynamicMemoryPool memoryPool(5);
|
||||||
|
|
||||||
StringBuilder str = memoryPool.startString();
|
StringBuilder str = memoryPool.startString();
|
||||||
REQUIRE(0 == memoryPool.size());
|
|
||||||
|
|
||||||
str.append('h');
|
str.append('h');
|
||||||
REQUIRE(1 == memoryPool.size());
|
|
||||||
|
|
||||||
str.complete();
|
str.complete();
|
||||||
|
|
||||||
REQUIRE(2 == memoryPool.size());
|
REQUIRE(2 == memoryPool.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,6 @@
|
|||||||
using namespace ARDUINOJSON_NAMESPACE;
|
using namespace ARDUINOJSON_NAMESPACE;
|
||||||
|
|
||||||
TEST_CASE("StaticMemoryPool::startString()") {
|
TEST_CASE("StaticMemoryPool::startString()") {
|
||||||
typedef StaticMemoryPoolBase::StringBuilder StringBuilder;
|
|
||||||
|
|
||||||
SECTION("WorksWhenBufferIsBigEnough") {
|
SECTION("WorksWhenBufferIsBigEnough") {
|
||||||
StaticMemoryPool<6> memoryPool;
|
StaticMemoryPool<6> memoryPool;
|
||||||
|
|
||||||
@ -40,12 +38,9 @@ TEST_CASE("StaticMemoryPool::startString()") {
|
|||||||
StaticMemoryPool<5> memoryPool;
|
StaticMemoryPool<5> memoryPool;
|
||||||
|
|
||||||
StringBuilder str = memoryPool.startString();
|
StringBuilder str = memoryPool.startString();
|
||||||
REQUIRE(0 == memoryPool.size());
|
|
||||||
|
|
||||||
str.append('h');
|
str.append('h');
|
||||||
REQUIRE(1 == memoryPool.size());
|
|
||||||
|
|
||||||
str.complete();
|
str.complete();
|
||||||
|
|
||||||
REQUIRE(2 == memoryPool.size());
|
REQUIRE(2 == memoryPool.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user