Added BasicJsonDocument to support custom allocator (issue #876)

This commit is contained in:
Benoit Blanchon
2019-03-17 21:48:10 +01:00
parent 576543c4b4
commit dee8c8e242
6 changed files with 149 additions and 52 deletions

View File

@ -8,6 +8,7 @@ HEAD
* Added overflow handling in `JsonVariant::as<T>()` and `JsonVariant::is<T>()`. * Added overflow handling in `JsonVariant::as<T>()` and `JsonVariant::is<T>()`.
- `as<T>()` returns `0` if the integer `T` overflows - `as<T>()` returns `0` if the integer `T` overflows
- `is<T>()` returns `false` if the integer `T` overflows - `is<T>()` returns `false` if the integer `T` overflows
* Added `BasicJsonDocument` to support custom allocator (issue #876)
v6.9.1 (2019-03-01) v6.9.1 (2019-03-01)
------ ------

View File

@ -50,6 +50,7 @@ typedef ARDUINOJSON_NAMESPACE::String JsonString;
typedef ARDUINOJSON_NAMESPACE::UInt JsonUInt; typedef ARDUINOJSON_NAMESPACE::UInt JsonUInt;
typedef ARDUINOJSON_NAMESPACE::VariantConstRef JsonVariantConst; typedef ARDUINOJSON_NAMESPACE::VariantConstRef JsonVariantConst;
typedef ARDUINOJSON_NAMESPACE::VariantRef JsonVariant; typedef ARDUINOJSON_NAMESPACE::VariantRef JsonVariant;
using ARDUINOJSON_NAMESPACE::BasicJsonDocument;
using ARDUINOJSON_NAMESPACE::copyArray; using ARDUINOJSON_NAMESPACE::copyArray;
using ARDUINOJSON_NAMESPACE::DeserializationError; using ARDUINOJSON_NAMESPACE::DeserializationError;
using ARDUINOJSON_NAMESPACE::deserializeJson; using ARDUINOJSON_NAMESPACE::deserializeJson;

View File

@ -0,0 +1,89 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2019
// MIT License
#pragma once
#include "JsonDocument.hpp"
namespace ARDUINOJSON_NAMESPACE {
template <typename TAllocator>
class AllocatorOwner {
protected:
AllocatorOwner() {}
AllocatorOwner(const AllocatorOwner& src) : _allocator(src._allocator) {}
AllocatorOwner(TAllocator allocator) : _allocator(allocator) {}
void* allocate(size_t n) {
return _allocator.allocate(n);
}
void deallocate(void* p) {
_allocator.deallocate(p);
}
private:
TAllocator _allocator;
};
template <typename TAllocator>
class BasicJsonDocument : AllocatorOwner<TAllocator>, public JsonDocument {
public:
explicit BasicJsonDocument(size_t capa, TAllocator allocator = TAllocator())
: AllocatorOwner<TAllocator>(allocator), JsonDocument(allocPool(capa)) {}
BasicJsonDocument(const BasicJsonDocument& src)
: AllocatorOwner<TAllocator>(src),
JsonDocument(allocPool(src.memoryUsage())) {
set(src);
}
template <typename T>
BasicJsonDocument(const T& src,
typename enable_if<IsVisitable<T>::value>::type* = 0)
: JsonDocument(allocPool(src.memoryUsage())) {
set(src);
}
// disambiguate
BasicJsonDocument(VariantRef src)
: JsonDocument(allocPool(src.memoryUsage())) {
set(src);
}
~BasicJsonDocument() {
freePool();
}
BasicJsonDocument& operator=(const BasicJsonDocument& src) {
reallocPoolIfTooSmall(src.memoryUsage());
set(src);
return *this;
}
template <typename T>
BasicJsonDocument& operator=(const T& src) {
reallocPoolIfTooSmall(src.memoryUsage());
set(src);
return *this;
}
private:
MemoryPool allocPool(size_t requiredSize) {
size_t capa = addPadding(requiredSize);
return MemoryPool(reinterpret_cast<char*>(this->allocate(capa)), capa);
}
void reallocPoolIfTooSmall(size_t requiredSize) {
if (requiredSize <= capacity()) return;
freePool();
replacePool(allocPool(addPadding(requiredSize)));
}
void freePool() {
this->deallocate(memoryPool().buffer());
}
};
} // namespace ARDUINOJSON_NAMESPACE

View File

@ -4,66 +4,22 @@
#pragma once #pragma once
#include "JsonDocument.hpp" #include "BasicJsonDocument.hpp"
#include <stdlib.h> // malloc, free #include <stdlib.h> // malloc, free
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
class DynamicJsonDocument : public JsonDocument { struct DefaultAllocator {
public: void* allocate(size_t n) {
explicit DynamicJsonDocument(size_t capa) : JsonDocument(allocPool(capa)) {} return malloc(n);
DynamicJsonDocument(const DynamicJsonDocument& src)
: JsonDocument(allocPool(src.memoryUsage())) {
set(src);
} }
template <typename T> void deallocate(void* p) {
DynamicJsonDocument(const T& src, free(p);
typename enable_if<IsVisitable<T>::value>::type* = 0)
: JsonDocument(allocPool(src.memoryUsage())) {
set(src);
}
// disambiguate
DynamicJsonDocument(VariantRef src)
: JsonDocument(allocPool(src.memoryUsage())) {
set(src);
}
~DynamicJsonDocument() {
freePool();
}
DynamicJsonDocument& operator=(const DynamicJsonDocument& src) {
reallocPoolIfTooSmall(src.memoryUsage());
set(src);
return *this;
}
template <typename T>
DynamicJsonDocument& operator=(const T& src) {
reallocPoolIfTooSmall(src.memoryUsage());
set(src);
return *this;
}
private:
MemoryPool allocPool(size_t requiredSize) {
size_t capa = addPadding(requiredSize);
return MemoryPool(reinterpret_cast<char*>(malloc(capa)), capa);
}
void reallocPoolIfTooSmall(size_t requiredSize) {
if (requiredSize <= capacity()) return;
freePool();
replacePool(allocPool(addPadding(requiredSize)));
}
void freePool() {
free(memoryPool().buffer());
} }
}; };
typedef BasicJsonDocument<DefaultAllocator> DynamicJsonDocument;
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@ -0,0 +1,49 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2019
// MIT License
#include <ArduinoJson.h>
#include <stdlib.h> // malloc, free
#include <catch.hpp>
#include <sstream>
using ARDUINOJSON_NAMESPACE::addPadding;
class SpyingAllocator {
public:
SpyingAllocator(std::ostream& log) : _log(log) {}
void* allocate(size_t n) {
_log << "A" << n;
return malloc(n);
}
void deallocate(void* p) {
_log << "F";
free(p);
}
private:
SpyingAllocator& operator=(const SpyingAllocator& src);
std::ostream& _log;
};
typedef BasicJsonDocument<SpyingAllocator> MyJsonDocument;
TEST_CASE("BasicJsonDocument") {
std::stringstream log;
SECTION("Construct/Destruct") {
{ MyJsonDocument doc(4096, log); }
REQUIRE(log.str() == "A4096F");
}
SECTION("Copy construct") {
{
MyJsonDocument doc1(4096, log);
doc1.set(std::string("The size of this string is 32!!"));
MyJsonDocument doc2(doc1);
}
REQUIRE(log.str() == "A4096A32FF");
}
}

View File

@ -4,6 +4,7 @@
add_executable(JsonDocumentTests add_executable(JsonDocumentTests
add.cpp add.cpp
BasicJsonDocument.cpp
createNested.cpp createNested.cpp
DynamicJsonDocument.cpp DynamicJsonDocument.cpp
isNull.cpp isNull.cpp