mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 08:42:39 +01:00 
			
		
		
		
	Added BasicJsonDocument to support custom allocator (issue #876)
				
					
				
			This commit is contained in:
		| @@ -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) | ||||
| ------ | ||||
|   | ||||
| @@ -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
									
								
								src/ArduinoJson/Document/BasicJsonDocument.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								src/ArduinoJson/Document/BasicJsonDocument.hpp
									
									
									
									
									
										Normal 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 | ||||
| @@ -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); | ||||
| struct DefaultAllocator { | ||||
|   void* allocate(size_t n) { | ||||
|     return malloc(n); | ||||
|   } | ||||
|  | ||||
|   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))); | ||||
|   } | ||||
|  | ||||
|   void freePool() { | ||||
|     free(memoryPool().buffer()); | ||||
|   void deallocate(void* p) { | ||||
|     free(p); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| typedef BasicJsonDocument<DefaultAllocator> DynamicJsonDocument; | ||||
|  | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
|   | ||||
							
								
								
									
										49
									
								
								test/JsonDocument/BasicJsonDocument.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								test/JsonDocument/BasicJsonDocument.cpp
									
									
									
									
									
										Normal 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"); | ||||
|   } | ||||
| } | ||||
| @@ -4,6 +4,7 @@ | ||||
|  | ||||
| add_executable(JsonDocumentTests | ||||
| 	add.cpp | ||||
| 	BasicJsonDocument.cpp | ||||
| 	createNested.cpp | ||||
| 	DynamicJsonDocument.cpp | ||||
| 	isNull.cpp | ||||
|   | ||||
		Reference in New Issue
	
	Block a user