forked from bblanchon/ArduinoJson
MemoryPool calls the Allocator directly
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
#include <ArduinoJson/Memory/MemoryPool.hpp>
|
||||
#include <ArduinoJson/Object/JsonObject.hpp>
|
||||
#include <ArduinoJson/Object/MemberProxy.hpp>
|
||||
#include <ArduinoJson/Polyfills/utility.hpp>
|
||||
#include <ArduinoJson/Strings/StoragePolicy.hpp>
|
||||
#include <ArduinoJson/Variant/JsonVariantConst.hpp>
|
||||
#include <ArduinoJson/Variant/VariantTo.hpp>
|
||||
@@ -23,16 +24,16 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
||||
public:
|
||||
explicit JsonDocument(size_t capa,
|
||||
Allocator* alloc = detail::DefaultAllocator::instance())
|
||||
: _allocator(alloc), _pool(allocPool(capa)) {}
|
||||
: _pool(capa, alloc) {}
|
||||
|
||||
// Copy-constructor
|
||||
JsonDocument(const JsonDocument& src)
|
||||
: JsonDocument(src.capacity(), src._allocator) {
|
||||
: JsonDocument(src.capacity(), src.allocator()) {
|
||||
set(src);
|
||||
}
|
||||
|
||||
// Move-constructor
|
||||
JsonDocument(JsonDocument&& src) : _allocator(src._allocator), _pool(0, 0) {
|
||||
JsonDocument(JsonDocument&& src) : _pool(0, src.allocator()) {
|
||||
// TODO: use the copy and swap idiom
|
||||
moveAssignFrom(src);
|
||||
}
|
||||
@@ -57,10 +58,6 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
||||
set(src);
|
||||
}
|
||||
|
||||
~JsonDocument() {
|
||||
freePool();
|
||||
}
|
||||
|
||||
JsonDocument& operator=(const JsonDocument& src) {
|
||||
// TODO: use the copy and swap idiom
|
||||
copyAssignFrom(src);
|
||||
@@ -77,26 +74,19 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
||||
JsonDocument& operator=(const T& src) {
|
||||
size_t requiredSize = src.memoryUsage();
|
||||
if (requiredSize > capacity())
|
||||
reallocPool(requiredSize);
|
||||
_pool.reallocPool(requiredSize);
|
||||
set(src);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Allocator* allocator() const {
|
||||
return _pool.allocator();
|
||||
}
|
||||
|
||||
// Reduces the capacity of the memory pool to match the current usage.
|
||||
// https://arduinojson.org/v6/api/JsonDocument/shrinktofit/
|
||||
void shrinkToFit() {
|
||||
ptrdiff_t bytes_reclaimed = _pool.squash();
|
||||
if (bytes_reclaimed == 0)
|
||||
return;
|
||||
|
||||
void* old_ptr = _pool.buffer();
|
||||
void* new_ptr = _allocator->reallocate(old_ptr, _pool.capacity());
|
||||
|
||||
ptrdiff_t ptr_offset =
|
||||
static_cast<char*>(new_ptr) - static_cast<char*>(old_ptr);
|
||||
|
||||
_pool.movePointers(ptr_offset);
|
||||
_data.movePointers(ptr_offset, ptr_offset - bytes_reclaimed);
|
||||
_pool.shrinkToFit(_data);
|
||||
}
|
||||
|
||||
// Reclaims the memory leaked when removing and replacing values.
|
||||
@@ -365,10 +355,6 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
||||
}
|
||||
|
||||
private:
|
||||
void replacePool(detail::MemoryPool pool) {
|
||||
_pool = pool;
|
||||
}
|
||||
|
||||
JsonVariant getVariant() {
|
||||
return JsonVariant(&_pool, &_data);
|
||||
}
|
||||
@@ -377,36 +363,15 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
||||
return JsonVariantConst(&_data);
|
||||
}
|
||||
|
||||
detail::MemoryPool allocPool(size_t requiredSize) {
|
||||
size_t capa = detail::addPadding(requiredSize);
|
||||
return {reinterpret_cast<char*>(_allocator->allocate(capa)), capa};
|
||||
}
|
||||
|
||||
void reallocPool(size_t requiredSize) {
|
||||
size_t capa = detail::addPadding(requiredSize);
|
||||
if (capa == _pool.capacity())
|
||||
return;
|
||||
freePool();
|
||||
replacePool(allocPool(detail::addPadding(requiredSize)));
|
||||
}
|
||||
|
||||
void freePool() {
|
||||
auto p = getPool()->buffer();
|
||||
if (p)
|
||||
_allocator->deallocate(p);
|
||||
}
|
||||
|
||||
void copyAssignFrom(const JsonDocument& src) {
|
||||
reallocPool(src.capacity());
|
||||
_pool.reallocPool(src.capacity());
|
||||
set(src);
|
||||
}
|
||||
|
||||
void moveAssignFrom(JsonDocument& src) {
|
||||
freePool();
|
||||
_data = src._data;
|
||||
_pool = src._pool;
|
||||
src._data.setNull();
|
||||
src._pool = {0, 0};
|
||||
_pool = move(src._pool);
|
||||
}
|
||||
|
||||
detail::MemoryPool* getPool() {
|
||||
@@ -425,7 +390,6 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
||||
return &_data;
|
||||
}
|
||||
|
||||
Allocator* _allocator;
|
||||
detail::MemoryPool _pool;
|
||||
detail::VariantData _data;
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Memory/Alignment.hpp>
|
||||
#include <ArduinoJson/Memory/Allocator.hpp>
|
||||
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||
#include <ArduinoJson/Polyfills/mpl/max.hpp>
|
||||
#include <ArduinoJson/Strings/StringAdapters.hpp>
|
||||
@@ -36,15 +37,42 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
class MemoryPool {
|
||||
public:
|
||||
MemoryPool(char* buf, size_t capa)
|
||||
: _begin(buf),
|
||||
_left(buf),
|
||||
_right(buf ? buf + capa : 0),
|
||||
_end(buf ? buf + capa : 0),
|
||||
_overflowed(false) {
|
||||
ARDUINOJSON_ASSERT(isAligned(_begin));
|
||||
ARDUINOJSON_ASSERT(isAligned(_right));
|
||||
ARDUINOJSON_ASSERT(isAligned(_end));
|
||||
MemoryPool(size_t capa, Allocator* allocator = DefaultAllocator::instance())
|
||||
: _allocator(allocator), _overflowed(false) {
|
||||
allocPool(addPadding(capa));
|
||||
}
|
||||
|
||||
~MemoryPool() {
|
||||
if (_begin)
|
||||
_allocator->deallocate(_begin);
|
||||
}
|
||||
|
||||
MemoryPool(const MemoryPool&) = delete;
|
||||
MemoryPool& operator=(const MemoryPool& src) = delete;
|
||||
|
||||
MemoryPool& operator=(MemoryPool&& src) {
|
||||
if (_begin)
|
||||
_allocator->deallocate(_begin);
|
||||
_allocator = src._allocator;
|
||||
_begin = src._begin;
|
||||
_end = src._end;
|
||||
_left = src._left;
|
||||
_right = src._right;
|
||||
_overflowed = src._overflowed;
|
||||
src._begin = src._end = src._left = src._right = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Allocator* allocator() const {
|
||||
return _allocator;
|
||||
}
|
||||
|
||||
void reallocPool(size_t requiredSize) {
|
||||
size_t capa = addPadding(requiredSize);
|
||||
if (capa == capacity())
|
||||
return;
|
||||
_allocator->deallocate(_begin);
|
||||
allocPool(requiredSize);
|
||||
}
|
||||
|
||||
void* buffer() {
|
||||
@@ -132,6 +160,23 @@ class MemoryPool {
|
||||
return p;
|
||||
}
|
||||
|
||||
void shrinkToFit(VariantData& variant) {
|
||||
ptrdiff_t bytes_reclaimed = squash();
|
||||
if (bytes_reclaimed == 0)
|
||||
return;
|
||||
|
||||
void* old_ptr = _begin;
|
||||
void* new_ptr = _allocator->reallocate(old_ptr, capacity());
|
||||
|
||||
ptrdiff_t ptr_offset =
|
||||
static_cast<char*>(new_ptr) - static_cast<char*>(old_ptr);
|
||||
|
||||
movePointers(ptr_offset);
|
||||
reinterpret_cast<VariantSlot&>(variant).movePointers(
|
||||
ptr_offset, ptr_offset - bytes_reclaimed);
|
||||
}
|
||||
|
||||
private:
|
||||
// Squash the free space between strings and variants
|
||||
//
|
||||
// _begin _end
|
||||
@@ -166,7 +211,6 @@ class MemoryPool {
|
||||
_end += offset;
|
||||
}
|
||||
|
||||
private:
|
||||
void checkInvariants() {
|
||||
ARDUINOJSON_ASSERT(_begin <= _left);
|
||||
ARDUINOJSON_ASSERT(_left <= _right);
|
||||
@@ -215,6 +259,16 @@ class MemoryPool {
|
||||
return _right;
|
||||
}
|
||||
|
||||
void allocPool(size_t capa) {
|
||||
auto buf = capa ? reinterpret_cast<char*>(_allocator->allocate(capa)) : 0;
|
||||
_begin = _left = buf;
|
||||
_end = _right = buf ? buf + capa : 0;
|
||||
ARDUINOJSON_ASSERT(isAligned(_begin));
|
||||
ARDUINOJSON_ASSERT(isAligned(_right));
|
||||
ARDUINOJSON_ASSERT(isAligned(_end));
|
||||
}
|
||||
|
||||
Allocator* _allocator;
|
||||
char *_begin, *_left, *_right, *_end;
|
||||
bool _overflowed;
|
||||
};
|
||||
|
||||
@@ -13,4 +13,9 @@ T&& forward(typename remove_reference<T>::type& t) noexcept {
|
||||
return static_cast<T&&>(t);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename remove_reference<T>::type&& move(T&& t) {
|
||||
return static_cast<typename remove_reference<T>::type&&>(t);
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
||||
Reference in New Issue
Block a user