diff --git a/src/ArduinoJson/Memory/DynamicMemoryPool.hpp b/src/ArduinoJson/Memory/DynamicMemoryPool.hpp index e4f2c3ff..d8c8af34 100644 --- a/src/ArduinoJson/Memory/DynamicMemoryPool.hpp +++ b/src/ArduinoJson/Memory/DynamicMemoryPool.hpp @@ -6,6 +6,7 @@ #include "../Strings/StringInMemoryPool.hpp" #include "MemoryPool.hpp" +#include "StringBuilder.hpp" #include // 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(_parent->allocInHead(1)); - *end = c; - if (_length == 0) _start = end; - } else { - char* newStart = - static_cast(_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; diff --git a/src/ArduinoJson/Memory/MemoryPool.hpp b/src/ArduinoJson/Memory/MemoryPool.hpp index 3ed98b5c..dd9ca7bc 100644 --- a/src/ArduinoJson/Memory/MemoryPool.hpp +++ b/src/ArduinoJson/Memory/MemoryPool.hpp @@ -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! diff --git a/src/ArduinoJson/Memory/StaticMemoryPool.hpp b/src/ArduinoJson/Memory/StaticMemoryPool.hpp index f6f47771..9477952c 100644 --- a/src/ArduinoJson/Memory/StaticMemoryPool.hpp +++ b/src/ArduinoJson/Memory/StaticMemoryPool.hpp @@ -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(_parent->doAlloc(1)); - *last = c; - } - } - - StringInMemoryPool complete() const { - if (_parent->canAlloc(1)) { - char* last = static_cast(_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; } diff --git a/src/ArduinoJson/Memory/StringBuilder.hpp b/src/ArduinoJson/Memory/StringBuilder.hpp new file mode 100644 index 00000000..f3016def --- /dev/null +++ b/src/ArduinoJson/Memory/StringBuilder.hpp @@ -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 diff --git a/src/ArduinoJson/StringStorage/StringCopier.hpp b/src/ArduinoJson/StringStorage/StringCopier.hpp index 576acf24..e6c5b7cb 100644 --- a/src/ArduinoJson/StringStorage/StringCopier.hpp +++ b/src/ArduinoJson/StringStorage/StringCopier.hpp @@ -4,20 +4,22 @@ #pragma once +#include "../Memory/MemoryPool.hpp" +#include "../Memory/StringBuilder.hpp" + namespace ARDUINOJSON_NAMESPACE { -template 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 diff --git a/src/ArduinoJson/StringStorage/StringStorage.hpp b/src/ArduinoJson/StringStorage/StringStorage.hpp index d7c3fff3..28a82000 100644 --- a/src/ArduinoJson/StringStorage/StringStorage.hpp +++ b/src/ArduinoJson/StringStorage/StringStorage.hpp @@ -9,34 +9,34 @@ namespace ARDUINOJSON_NAMESPACE { -template +template struct StringStorage { - typedef StringCopier type; + typedef StringCopier type; - static type create(TMemoryPool& jb, TInput&) { - return type(jb); + static type create(MemoryPool& pool, TInput&) { + return type(&pool); } }; -template -struct StringStorage +struct StringStorage::value>::type> { typedef StringMover type; - static type create(TMemoryPool&, TChar* input) { + static type create(MemoryPool&, TChar* input) { return type(input); } }; -template -typename StringStorage::type makeStringStorage( - TMemoryPool& jb, TInput& input) { - return StringStorage::create(jb, input); +template +typename StringStorage::type makeStringStorage(MemoryPool& pool, + TInput& input) { + return StringStorage::create(pool, input); } -template -typename StringStorage::type makeStringStorage( - TMemoryPool& jb, TChar* input) { - return StringStorage::create(jb, input); +template +typename StringStorage::type makeStringStorage(MemoryPool& pool, + TChar* input) { + return StringStorage::create(pool, input); } } // namespace ARDUINOJSON_NAMESPACE diff --git a/test/DynamicMemoryPool/no_memory.cpp b/test/DynamicMemoryPool/no_memory.cpp index afc82d7f..c53d5b83 100644 --- a/test/DynamicMemoryPool/no_memory.cpp +++ b/test/DynamicMemoryPool/no_memory.cpp @@ -17,8 +17,6 @@ struct NoMemoryAllocator { TEST_CASE("DynamicMemoryPool no memory") { DynamicMemoryPoolBase _memoryPool; - typedef DynamicMemoryPoolBase::StringBuilder StringBuilder; - SECTION("FixCodeCoverage") { // call this function to fix code coverage NoMemoryAllocator().deallocate(NULL); diff --git a/test/DynamicMemoryPool/startString.cpp b/test/DynamicMemoryPool/startString.cpp index c891b4ce..1b0964e8 100644 --- a/test/DynamicMemoryPool/startString.cpp +++ b/test/DynamicMemoryPool/startString.cpp @@ -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()); } } diff --git a/test/StaticMemoryPool/startString.cpp b/test/StaticMemoryPool/startString.cpp index 38837aec..6eca182e 100644 --- a/test/StaticMemoryPool/startString.cpp +++ b/test/StaticMemoryPool/startString.cpp @@ -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()); } }