diff --git a/CHANGELOG.md b/CHANGELOG.md index e2009f11..b329d441 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ HEAD * Added overflow handling in `JsonVariant::as()` and `JsonVariant::is()`. - `as()` returns `0` if the integer `T` overflows - `is()` returns `false` if the integer `T` overflows +* Added `BasicJsonDocument` to support custom allocator (issue #876) v6.9.1 (2019-03-01) ------ diff --git a/src/ArduinoJson.hpp b/src/ArduinoJson.hpp index 5188d5ea..cb3704ee 100644 --- a/src/ArduinoJson.hpp +++ b/src/ArduinoJson.hpp @@ -50,6 +50,7 @@ typedef ARDUINOJSON_NAMESPACE::String JsonString; typedef ARDUINOJSON_NAMESPACE::UInt JsonUInt; typedef ARDUINOJSON_NAMESPACE::VariantConstRef JsonVariantConst; typedef ARDUINOJSON_NAMESPACE::VariantRef JsonVariant; +using ARDUINOJSON_NAMESPACE::BasicJsonDocument; using ARDUINOJSON_NAMESPACE::copyArray; using ARDUINOJSON_NAMESPACE::DeserializationError; using ARDUINOJSON_NAMESPACE::deserializeJson; diff --git a/src/ArduinoJson/Document/BasicJsonDocument.hpp b/src/ArduinoJson/Document/BasicJsonDocument.hpp new file mode 100644 index 00000000..3919cb43 --- /dev/null +++ b/src/ArduinoJson/Document/BasicJsonDocument.hpp @@ -0,0 +1,89 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2019 +// MIT License + +#pragma once + +#include "JsonDocument.hpp" + +namespace ARDUINOJSON_NAMESPACE { + +template +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 +class BasicJsonDocument : AllocatorOwner, public JsonDocument { + public: + explicit BasicJsonDocument(size_t capa, TAllocator allocator = TAllocator()) + : AllocatorOwner(allocator), JsonDocument(allocPool(capa)) {} + + BasicJsonDocument(const BasicJsonDocument& src) + : AllocatorOwner(src), + JsonDocument(allocPool(src.memoryUsage())) { + set(src); + } + + template + BasicJsonDocument(const T& src, + typename enable_if::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 + 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(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 diff --git a/src/ArduinoJson/Document/DynamicJsonDocument.hpp b/src/ArduinoJson/Document/DynamicJsonDocument.hpp index a52f6509..380adae1 100644 --- a/src/ArduinoJson/Document/DynamicJsonDocument.hpp +++ b/src/ArduinoJson/Document/DynamicJsonDocument.hpp @@ -4,66 +4,22 @@ #pragma once -#include "JsonDocument.hpp" +#include "BasicJsonDocument.hpp" #include // malloc, free namespace ARDUINOJSON_NAMESPACE { -class DynamicJsonDocument : public JsonDocument { - public: - explicit DynamicJsonDocument(size_t capa) : JsonDocument(allocPool(capa)) {} - - DynamicJsonDocument(const DynamicJsonDocument& src) - : JsonDocument(allocPool(src.memoryUsage())) { - set(src); +struct DefaultAllocator { + void* allocate(size_t n) { + return malloc(n); } - template - DynamicJsonDocument(const T& src, - typename enable_if::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 - 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(malloc(capa)), capa); - } - - void reallocPoolIfTooSmall(size_t requiredSize) { - if (requiredSize <= capacity()) return; - freePool(); - replacePool(allocPool(addPadding(requiredSize))); - } - - void freePool() { - free(memoryPool().buffer()); + void deallocate(void* p) { + free(p); } }; +typedef BasicJsonDocument DynamicJsonDocument; + } // namespace ARDUINOJSON_NAMESPACE diff --git a/test/JsonDocument/BasicJsonDocument.cpp b/test/JsonDocument/BasicJsonDocument.cpp new file mode 100644 index 00000000..e31b0d74 --- /dev/null +++ b/test/JsonDocument/BasicJsonDocument.cpp @@ -0,0 +1,49 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2019 +// MIT License + +#include +#include // malloc, free +#include +#include + +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 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"); + } +} diff --git a/test/JsonDocument/CMakeLists.txt b/test/JsonDocument/CMakeLists.txt index 04d7e227..29d78dc6 100644 --- a/test/JsonDocument/CMakeLists.txt +++ b/test/JsonDocument/CMakeLists.txt @@ -4,6 +4,7 @@ add_executable(JsonDocumentTests add.cpp + BasicJsonDocument.cpp createNested.cpp DynamicJsonDocument.cpp isNull.cpp