Просмотр исходного кода

Added `BasicJsonDocument` to support custom allocator (issue #876)

Benoit Blanchon 7 лет назад
Родитель
Сommit
dee8c8e242

+ 1 - 0
CHANGELOG.md

@@ -8,6 +8,7 @@ HEAD
 * Added overflow handling in `JsonVariant::as<T>()` and `JsonVariant::is<T>()`.
    - `as<T>()` returns `0` 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)
 ------

+ 1 - 0
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;

+ 89 - 0
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 <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

+ 8 - 52
src/ArduinoJson/Document/DynamicJsonDocument.hpp

@@ -4,66 +4,22 @@
 
 #pragma once
 
-#include "JsonDocument.hpp"
+#include "BasicJsonDocument.hpp"
 
 #include <stdlib.h>  // 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);
-  }
-
-  template <typename T>
-  DynamicJsonDocument(const T& src,
-                      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)));
+struct DefaultAllocator {
+  void* allocate(size_t n) {
+    return malloc(n);
   }
 
-  void freePool() {
-    free(memoryPool().buffer());
+  void deallocate(void* p) {
+    free(p);
   }
 };
 
+typedef BasicJsonDocument<DefaultAllocator> DynamicJsonDocument;
+
 }  // namespace ARDUINOJSON_NAMESPACE

+ 49 - 0
test/JsonDocument/BasicJsonDocument.cpp

@@ -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");
+  }
+}

+ 1 - 0
test/JsonDocument/CMakeLists.txt

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