mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 16:14:11 +01:00 
			
		
		
		
	Removed the automatic expansion of DynamicJsonDocument
				
					
				
			This commit is contained in:
		| @@ -1,6 +1,11 @@ | ||||
| ArduinoJson: change log | ||||
| ======================= | ||||
|  | ||||
| HEAD | ||||
| ---- | ||||
|  | ||||
| * Removed the automatic expansion of `DynamicJsonDocument`, it now has a fixed capacity. | ||||
|  | ||||
| v6.6.0-beta (2018-11-13) | ||||
| ----------- | ||||
|  | ||||
|   | ||||
| @@ -7,10 +7,12 @@ | ||||
| #include "ArduinoJson/Namespace.hpp" | ||||
|  | ||||
| #include "ArduinoJson/JsonArray.hpp" | ||||
| #include "ArduinoJson/JsonDocument.hpp" | ||||
| #include "ArduinoJson/JsonObject.hpp" | ||||
| #include "ArduinoJson/JsonVariant.hpp" | ||||
|  | ||||
| #include "ArduinoJson/DynamicJsonDocument.hpp" | ||||
| #include "ArduinoJson/StaticJsonDocument.hpp" | ||||
|  | ||||
| #include "ArduinoJson/Data/VariantAsImpl.hpp" | ||||
| #include "ArduinoJson/JsonArrayImpl.hpp" | ||||
| #include "ArduinoJson/JsonArraySubscript.hpp" | ||||
|   | ||||
							
								
								
									
										49
									
								
								src/ArduinoJson/DynamicJsonDocument.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								src/ArduinoJson/DynamicJsonDocument.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "JsonDocument.hpp" | ||||
|  | ||||
| #include <stdlib.h>  // malloc, free | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
|  | ||||
| class DynamicJsonDocument : public JsonDocument { | ||||
|  public: | ||||
|   DynamicJsonDocument(size_t capa = ARDUINOJSON_DEFAULT_POOL_SIZE) | ||||
|       : JsonDocument(alloc(capa), addPadding(capa)) {} | ||||
|  | ||||
|   DynamicJsonDocument(const DynamicJsonDocument& src) | ||||
|       : JsonDocument(alloc(src.memoryUsage()), addPadding(src.memoryUsage())) { | ||||
|     copy(src); | ||||
|   } | ||||
|  | ||||
|   DynamicJsonDocument(const JsonDocument& src) | ||||
|       : JsonDocument(alloc(src.memoryUsage()), addPadding(src.memoryUsage())) { | ||||
|     copy(src); | ||||
|   } | ||||
|  | ||||
|   ~DynamicJsonDocument() { | ||||
|     free(memoryPool().buffer()); | ||||
|   } | ||||
|  | ||||
|   DynamicJsonDocument& operator=(const DynamicJsonDocument& src) { | ||||
|     copy(src); | ||||
|     return *this; | ||||
|   } | ||||
|  | ||||
|   template <typename T> | ||||
|   DynamicJsonDocument& operator=(const JsonDocument& src) { | ||||
|     copy(src); | ||||
|     return *this; | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   static char* alloc(size_t capa) { | ||||
|     return reinterpret_cast<char*>(malloc(addPadding(capa))); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
| @@ -6,18 +6,14 @@ | ||||
|  | ||||
| #include "Data/JsonVariantTo.hpp" | ||||
| #include "JsonVariant.hpp" | ||||
| #include "Memory/DynamicMemoryPool.hpp" | ||||
| #include "Memory/StaticMemoryPool.hpp" | ||||
| #include "Memory/MemoryPool.hpp" | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
|  | ||||
| template <typename TMemoryPool> | ||||
| class JsonDocument : public Visitable { | ||||
|  public: | ||||
|   uint8_t nestingLimit; | ||||
|  | ||||
|   JsonDocument() : nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT) {} | ||||
|  | ||||
|   template <typename Visitor> | ||||
|   void accept(Visitor& visitor) const { | ||||
|     return getVariant().accept(visitor); | ||||
| @@ -47,7 +43,12 @@ class JsonDocument : public Visitable { | ||||
|     return _memoryPool.size(); | ||||
|   } | ||||
|  | ||||
|   TMemoryPool& memoryPool() { | ||||
|   size_t capacity() const { | ||||
|     return _memoryPool.capacity(); | ||||
|   } | ||||
|  | ||||
|   // for internal use only | ||||
|   MemoryPool& memoryPool() { | ||||
|     return _memoryPool; | ||||
|   } | ||||
|  | ||||
| @@ -58,10 +59,13 @@ class JsonDocument : public Visitable { | ||||
|   } | ||||
|  | ||||
|  protected: | ||||
|   template <typename T> | ||||
|   void copy(const JsonDocument<T>& src) { | ||||
|   JsonDocument(char* buf, size_t capa) | ||||
|       : nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT), | ||||
|         _memoryPool(buf, capa) {} | ||||
|  | ||||
|   void copy(const JsonDocument& src) { | ||||
|     nestingLimit = src.nestingLimit; | ||||
|     to<JsonVariant>().set(src.template as<JsonVariant>()); | ||||
|     to<JsonVariant>().set(src.as<JsonVariant>()); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
| @@ -73,59 +77,8 @@ class JsonDocument : public Visitable { | ||||
|     return JsonVariantConst(&_rootData); | ||||
|   } | ||||
|  | ||||
|   TMemoryPool _memoryPool; | ||||
|   MemoryPool _memoryPool; | ||||
|   JsonVariantData _rootData; | ||||
| }; | ||||
|  | ||||
| class DynamicJsonDocument : public JsonDocument<DynamicMemoryPool> { | ||||
|  public: | ||||
|   DynamicJsonDocument() {} | ||||
|   DynamicJsonDocument(size_t capacity) { | ||||
|     memoryPool().reserve(capacity); | ||||
|   } | ||||
|  | ||||
|   DynamicJsonDocument(const DynamicJsonDocument& src) { | ||||
|     memoryPool().reserve(src.memoryUsage()); | ||||
|     copy(src); | ||||
|   } | ||||
|  | ||||
|   template <typename T> | ||||
|   DynamicJsonDocument(const JsonDocument<T>& src) { | ||||
|     memoryPool().reserve(src.memoryUsage()); | ||||
|     copy(src); | ||||
|   } | ||||
|  | ||||
|   DynamicJsonDocument& operator=(const DynamicJsonDocument& src) { | ||||
|     copy(src); | ||||
|     return *this; | ||||
|   } | ||||
|  | ||||
|   template <typename T> | ||||
|   DynamicJsonDocument& operator=(const JsonDocument<T>& src) { | ||||
|     copy(src); | ||||
|     return *this; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template <size_t CAPACITY> | ||||
| class StaticJsonDocument : public JsonDocument<StaticMemoryPool<CAPACITY> > { | ||||
|  public: | ||||
|   StaticJsonDocument() {} | ||||
|  | ||||
|   template <typename T> | ||||
|   StaticJsonDocument(const JsonDocument<T>& src) { | ||||
|     this->copy(src); | ||||
|   } | ||||
|  | ||||
|   StaticMemoryPoolBase& memoryPool() { | ||||
|     return JsonDocument<StaticMemoryPool<CAPACITY> >::memoryPool(); | ||||
|   } | ||||
|  | ||||
|   template <typename T> | ||||
|   StaticJsonDocument operator=(const JsonDocument<T>& src) { | ||||
|     this->copy(src); | ||||
|     return *this; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
|   | ||||
| @@ -1,187 +0,0 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "../Strings/StringInMemoryPool.hpp" | ||||
| #include "Alignment.hpp" | ||||
| #include "MemoryPool.hpp" | ||||
| #include "StaticMemoryPool.hpp" | ||||
|  | ||||
| #include <stdlib.h>  // malloc, free | ||||
|  | ||||
| #if defined(__clang__) | ||||
| #pragma clang diagnostic push | ||||
| #pragma clang diagnostic ignored "-Wnon-virtual-dtor" | ||||
| #elif defined(__GNUC__) | ||||
| #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) | ||||
| #pragma GCC diagnostic push | ||||
| #endif | ||||
| #pragma GCC diagnostic ignored "-Wnon-virtual-dtor" | ||||
| #endif | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
| class DefaultAllocator { | ||||
|  public: | ||||
|   void* allocate(size_t size) { | ||||
|     return malloc(size); | ||||
|   } | ||||
|   void deallocate(void* pointer) { | ||||
|     free(pointer); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template <typename TAllocator> | ||||
| class DynamicMemoryPoolBase : public MemoryPool { | ||||
|   class Block : public StaticMemoryPoolBase { | ||||
|    public: | ||||
|     Block(char* buf, size_t sz, Block* nxt) | ||||
|         : StaticMemoryPoolBase(buf, sz), next(nxt) {} | ||||
|     Block* next; | ||||
|   }; | ||||
|  | ||||
|  public: | ||||
|   enum { EmptyBlockSize = sizeof(Block) }; | ||||
|  | ||||
|   DynamicMemoryPoolBase(size_t initialSize = ARDUINOJSON_DEFAULT_POOL_SIZE) | ||||
|       : _head(NULL), _nextBlockCapacity(initialSize) {} | ||||
|  | ||||
|   ~DynamicMemoryPoolBase() { | ||||
|     clear(); | ||||
|   } | ||||
|  | ||||
|   void reserve(size_t capacity) { | ||||
|     _nextBlockCapacity = capacity; | ||||
|   } | ||||
|  | ||||
|   virtual size_t size() const { | ||||
|     size_t sum = 0; | ||||
|     for (Block* b = _head; b; b = b->next) { | ||||
|       sum += b->size(); | ||||
|     } | ||||
|     return sum; | ||||
|   } | ||||
|  | ||||
|   virtual VariantSlot* allocVariant() { | ||||
|     for (Block* b = _head; b; b = b->next) { | ||||
|       VariantSlot* s = b->allocVariant(); | ||||
|       if (s) return s; | ||||
|     } | ||||
|  | ||||
|     if (!addNewBlock(sizeof(VariantSlot))) return 0; | ||||
|  | ||||
|     return _head->allocVariant(); | ||||
|   } | ||||
|  | ||||
|   virtual void freeVariant(VariantSlot* slot) { | ||||
|     for (Block* b = _head; b; b = b->next) { | ||||
|       if (b->owns(slot)) { | ||||
|         b->freeVariant(slot); | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   virtual void freeString(StringSlot* slot) { | ||||
|     for (Block* b = _head; b; b = b->next) { | ||||
|       if (b->owns(slot)) { | ||||
|         b->freeString(slot); | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   virtual StringSlot* allocFrozenString(size_t n) { | ||||
|     for (Block* b = _head; b; b = b->next) { | ||||
|       StringSlot* s = b->allocFrozenString(n); | ||||
|       if (s) return s; | ||||
|     } | ||||
|  | ||||
|     if (!addNewBlock(sizeof(StringSlot) + n)) return 0; | ||||
|  | ||||
|     return _head->allocFrozenString(n); | ||||
|   } | ||||
|  | ||||
|   virtual StringSlot* allocExpandableString() { | ||||
|     for (Block* b = _head; b; b = b->next) { | ||||
|       StringSlot* s = b->allocExpandableString(); | ||||
|       if (s) return s; | ||||
|     } | ||||
|  | ||||
|     if (!addNewBlock(sizeof(StringSlot))) return 0; | ||||
|  | ||||
|     return _head->allocExpandableString(); | ||||
|   } | ||||
|  | ||||
|   virtual StringSlot* expandString(StringSlot* oldSlot) { | ||||
|     if (!addNewBlock(sizeof(StringSlot) + oldSlot->size)) return 0; | ||||
|  | ||||
|     StringSlot* newSlot = _head->allocExpandableString(); | ||||
|  | ||||
|     ARDUINOJSON_ASSERT(newSlot->size > oldSlot->size); | ||||
|     memcpy(newSlot->value, oldSlot->value, oldSlot->size); | ||||
|     freeString(oldSlot); | ||||
|  | ||||
|     return newSlot; | ||||
|   } | ||||
|  | ||||
|   virtual void freezeString(StringSlot* slot, size_t newSize) { | ||||
|     for (Block* b = _head; b; b = b->next) { | ||||
|       if (b->owns(slot)) { | ||||
|         b->freezeString(slot, newSize); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // Resets the memoryPool. | ||||
|   // USE WITH CAUTION: this invalidates all previously allocated data | ||||
|   void clear() { | ||||
|     Block* currentBlock = _head; | ||||
|     while (currentBlock != NULL) { | ||||
|       _nextBlockCapacity = currentBlock->capacity(); | ||||
|       Block* nextBlock = currentBlock->next; | ||||
|       _allocator.deallocate(currentBlock); | ||||
|       currentBlock = nextBlock; | ||||
|     } | ||||
|     _head = 0; | ||||
|   } | ||||
|  | ||||
|   size_t blockCount() const { | ||||
|     size_t sum = 0; | ||||
|     for (Block* b = _head; b; b = b->next) sum++; | ||||
|     return sum; | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   bool addNewBlock(size_t minCapacity) { | ||||
|     size_t capacity = _nextBlockCapacity; | ||||
|     if (minCapacity > capacity) capacity = minCapacity; | ||||
|     capacity = addPadding(capacity); | ||||
|     size_t bytes = sizeof(Block) + capacity; | ||||
|     char* p = reinterpret_cast<char*>(_allocator.allocate(bytes)); | ||||
|     if (!p) return false; | ||||
|     Block* block = new (p) Block(p + sizeof(Block), capacity, _head); | ||||
|     _nextBlockCapacity = capacity * 2; | ||||
|     _head = block; | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   TAllocator _allocator; | ||||
|   Block* _head; | ||||
|   size_t _nextBlockCapacity; | ||||
| }; | ||||
|  | ||||
| // Implements a MemoryPool with dynamic memory allocation. | ||||
| // You are strongly encouraged to consider using StaticMemoryPool which is much | ||||
| // more suitable for embedded systems. | ||||
| typedef DynamicMemoryPoolBase<DefaultAllocator> DynamicMemoryPool; | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
|  | ||||
| #if defined(__clang__) | ||||
| #pragma clang diagnostic pop | ||||
| #elif defined(__GNUC__) | ||||
| #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) | ||||
| #pragma GCC diagnostic pop | ||||
| #endif | ||||
| #endif | ||||
| @@ -4,31 +4,203 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <stddef.h>  // for size_t | ||||
|  | ||||
| #include "../Polyfills/attributes.hpp" | ||||
| #include "../Polyfills/assert.hpp" | ||||
| #include "../Polyfills/mpl/max.hpp" | ||||
| #include "../Strings/StringInMemoryPool.hpp" | ||||
| #include "Alignment.hpp" | ||||
| #include "MemoryPool.hpp" | ||||
| #include "SlotList.hpp" | ||||
| #include "StringSlot.hpp" | ||||
| #include "VariantSlot.hpp" | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
|  | ||||
| // _begin                                _end | ||||
| // v                                        v | ||||
| // +-------------+--------------+-----------+ | ||||
| // | strings...  |   (free)     |  ...slots | | ||||
| // +-------------+--------------+-----------+ | ||||
| //               ^              ^ | ||||
| //             _left          _right | ||||
|  | ||||
| class MemoryPool { | ||||
|   class UpdateStringSlotAddress { | ||||
|    public: | ||||
|     UpdateStringSlotAddress(const char* address, size_t offset) | ||||
|         : _address(address), _offset(offset) {} | ||||
|  | ||||
|     void operator()(StringSlot* slot) const { | ||||
|       ARDUINOJSON_ASSERT(slot != NULL); | ||||
|       if (slot->value > _address) slot->value -= _offset; | ||||
|     } | ||||
|  | ||||
|    private: | ||||
|     const char* _address; | ||||
|     size_t _offset; | ||||
|   }; | ||||
|  | ||||
|  public: | ||||
|   virtual StringSlot *allocExpandableString() = 0; | ||||
|   virtual StringSlot *allocFrozenString(size_t) = 0; | ||||
|   virtual StringSlot *expandString(StringSlot *) = 0; | ||||
|   virtual void freezeString(StringSlot *, size_t) = 0; | ||||
|   virtual void freeString(StringSlot *) = 0; | ||||
|   MemoryPool(char* buf, size_t capa) | ||||
|       : _begin(buf), | ||||
|         _left(buf), | ||||
|         _right(buf ? buf + capa : 0), | ||||
|         _end(buf ? buf + capa : 0) { | ||||
|     ARDUINOJSON_ASSERT(isAligned(_begin)); | ||||
|     ARDUINOJSON_ASSERT(isAligned(_right)); | ||||
|     ARDUINOJSON_ASSERT(isAligned(_end)); | ||||
|   } | ||||
|  | ||||
|   virtual VariantSlot *allocVariant() = 0; | ||||
|   virtual void freeVariant(VariantSlot *) = 0; | ||||
|   void* buffer() { | ||||
|     return _begin; | ||||
|   } | ||||
|  | ||||
|   virtual size_t size() const = 0; | ||||
|   // Gets the capacity of the memoryPool in bytes | ||||
|   size_t capacity() const { | ||||
|     return size_t(_end - _begin); | ||||
|   } | ||||
|  | ||||
|  protected: | ||||
|   // CAUTION: NO VIRTUAL DESTRUCTOR! | ||||
|   // If we add a virtual constructor the Arduino compiler will add malloc() | ||||
|   // and free() to the binary, adding 706 useless bytes. | ||||
|   ~MemoryPool() {} | ||||
|   size_t size() const { | ||||
|     return allocated_bytes() - _freeVariants.size() - _freeStrings.size(); | ||||
|   } | ||||
|  | ||||
|   VariantSlot* allocVariant() { | ||||
|     VariantSlot* s = _freeVariants.pop(); | ||||
|     if (s) return s; | ||||
|     return s ? s : allocRight<VariantSlot>(); | ||||
|   } | ||||
|  | ||||
|   void freeVariant(VariantSlot* slot) { | ||||
|     freeVariantSlot(slot); | ||||
|     compactRightSide(); | ||||
|   } | ||||
|  | ||||
|   void freeString(StringSlot* slot) { | ||||
|     freeStringSlot(slot); | ||||
|     compactLeftSide(slot->value, slot->size); | ||||
|     compactRightSide(); | ||||
|   } | ||||
|  | ||||
|   StringSlot* allocFrozenString(size_t n) { | ||||
|     StringSlot* s = allocStringSlot(); | ||||
|     if (!s) return 0; | ||||
|     if (!canAlloc(n)) return 0; | ||||
|  | ||||
|     s->value = _left; | ||||
|     s->size = n; | ||||
|     _left += n; | ||||
|     _usedString.push(s); | ||||
|     checkInvariants(); | ||||
|  | ||||
|     return s; | ||||
|   } | ||||
|  | ||||
|   StringSlot* allocExpandableString() { | ||||
|     StringSlot* s = allocStringSlot(); | ||||
|     if (!s) return 0; | ||||
|  | ||||
|     s->value = _left; | ||||
|     s->size = size_t(_right - _left); | ||||
|     _usedString.push(s); | ||||
|     _left = _right; | ||||
|  | ||||
|     checkInvariants(); | ||||
|     return s; | ||||
|   } | ||||
|  | ||||
|   void freezeString(StringSlot* slot, size_t newSize) { | ||||
|     _left -= (slot->size - newSize); | ||||
|     slot->size = newSize; | ||||
|     checkInvariants(); | ||||
|   } | ||||
|  | ||||
|   void clear() { | ||||
|     _left = _begin; | ||||
|     _right = _end; | ||||
|     _freeVariants.clear(); | ||||
|     _freeStrings.clear(); | ||||
|     _usedString.clear(); | ||||
|   } | ||||
|  | ||||
|   bool canAlloc(size_t bytes) const { | ||||
|     return _left + bytes <= _right; | ||||
|   } | ||||
|  | ||||
|   bool owns(void* p) const { | ||||
|     return _begin <= p && p < _end; | ||||
|   } | ||||
|  | ||||
|   template <typename T> | ||||
|   T* allocRight() { | ||||
|     return reinterpret_cast<T*>(allocRight(sizeof(T))); | ||||
|   } | ||||
|  | ||||
|   char* allocRight(size_t bytes) { | ||||
|     if (!canAlloc(bytes)) return 0; | ||||
|     _right -= bytes; | ||||
|     return _right; | ||||
|   } | ||||
|  | ||||
|   // Workaround for missing placement new | ||||
|   void* operator new(size_t, void* p) { | ||||
|     return p; | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   size_t allocated_bytes() const { | ||||
|     return size_t(_left - _begin + _end - _right); | ||||
|   } | ||||
|  | ||||
|   StringSlot* allocStringSlot() { | ||||
|     StringSlot* s = _freeStrings.pop(); | ||||
|     if (s) return s; | ||||
|     return allocRight<StringSlot>(); | ||||
|   } | ||||
|  | ||||
|   void freeVariantSlot(VariantSlot* slot) { | ||||
|     _freeVariants.push(slot); | ||||
|   } | ||||
|  | ||||
|   void freeStringSlot(StringSlot* slot) { | ||||
|     _usedString.remove(slot); | ||||
|     _freeStrings.push(slot); | ||||
|   } | ||||
|  | ||||
|   void compactLeftSide(char* holeAddress, size_t holeSize) { | ||||
|     ARDUINOJSON_ASSERT(holeAddress >= _begin); | ||||
|     ARDUINOJSON_ASSERT(holeAddress + holeSize <= _left); | ||||
|     char* holeEnd = holeAddress + holeSize; | ||||
|     memmove(holeAddress,               // where the hole begun | ||||
|             holeEnd,                   // where the hole ended | ||||
|             size_t(_left - holeEnd));  // everything after the hole | ||||
|     _left -= holeSize; | ||||
|     _usedString.forEach(UpdateStringSlotAddress(holeAddress, holeSize)); | ||||
|     checkInvariants(); | ||||
|   } | ||||
|  | ||||
|   void compactRightSide() { | ||||
|   loop: | ||||
|     if (_freeStrings.remove(_right)) { | ||||
|       _right += sizeof(StringSlot); | ||||
|       goto loop; | ||||
|     } | ||||
|     if (_freeVariants.remove(_right)) { | ||||
|       _right += sizeof(VariantSlot); | ||||
|       goto loop; | ||||
|     } | ||||
|     checkInvariants(); | ||||
|   } | ||||
|  | ||||
|   void checkInvariants() { | ||||
|     ARDUINOJSON_ASSERT(_begin <= _left); | ||||
|     ARDUINOJSON_ASSERT(_left <= _right); | ||||
|     ARDUINOJSON_ASSERT(_right <= _end); | ||||
|     ARDUINOJSON_ASSERT(isAligned(_right)); | ||||
|   } | ||||
|  | ||||
|   char *_begin, *_left, *_right, *_end; | ||||
|   SlotList<VariantSlot> _freeVariants; | ||||
|   SlotList<StringSlot> _freeStrings; | ||||
|   SlotList<StringSlot> _usedString; | ||||
| }; | ||||
|  | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
|   | ||||
| @@ -1,236 +0,0 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "../Polyfills/assert.hpp" | ||||
| #include "../Polyfills/mpl/max.hpp" | ||||
| #include "../Strings/StringInMemoryPool.hpp" | ||||
| #include "Alignment.hpp" | ||||
| #include "MemoryPool.hpp" | ||||
| #include "SlotList.hpp" | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
|  | ||||
| // _begin                                _end | ||||
| // v                                        v | ||||
| // +-------------+--------------+-----------+ | ||||
| // | strings...  |   (free)     |  ...slots | | ||||
| // +-------------+--------------+-----------+ | ||||
| //               ^              ^ | ||||
| //             _left          _right | ||||
|  | ||||
| class StaticMemoryPoolBase : public MemoryPool { | ||||
|   class UpdateStringSlotAddress { | ||||
|    public: | ||||
|     UpdateStringSlotAddress(const char* address, size_t offset) | ||||
|         : _address(address), _offset(offset) {} | ||||
|  | ||||
|     void operator()(StringSlot* slot) const { | ||||
|       ARDUINOJSON_ASSERT(slot != NULL); | ||||
|       if (slot->value > _address) slot->value -= _offset; | ||||
|     } | ||||
|  | ||||
|    private: | ||||
|     const char* _address; | ||||
|     size_t _offset; | ||||
|   }; | ||||
|  | ||||
|  public: | ||||
|   // Gets the capacity of the memoryPool in bytes | ||||
|   size_t capacity() const { | ||||
|     return size_t(_end - _begin); | ||||
|   } | ||||
|  | ||||
|   virtual size_t size() const { | ||||
|     return allocated_bytes() - _freeVariants.size() - _freeStrings.size(); | ||||
|   } | ||||
|  | ||||
|   virtual VariantSlot* allocVariant() { | ||||
|     VariantSlot* s = _freeVariants.pop(); | ||||
|     if (s) return s; | ||||
|     return s ? s : allocRight<VariantSlot>(); | ||||
|   } | ||||
|  | ||||
|   virtual void freeVariant(VariantSlot* slot) { | ||||
|     freeVariantSlot(slot); | ||||
|     compactRightSide(); | ||||
|   } | ||||
|  | ||||
|   virtual void freeString(StringSlot* slot) { | ||||
|     freeStringSlot(slot); | ||||
|     compactLeftSide(slot->value, slot->size); | ||||
|     compactRightSide(); | ||||
|   } | ||||
|  | ||||
|   virtual StringSlot* allocFrozenString(size_t n) { | ||||
|     StringSlot* s = allocStringSlot(); | ||||
|     if (!s) return 0; | ||||
|     if (!canAlloc(n)) return 0; | ||||
|  | ||||
|     s->value = _left; | ||||
|     s->size = n; | ||||
|     _left += n; | ||||
|     _usedString.push(s); | ||||
|     checkInvariants(); | ||||
|  | ||||
|     return s; | ||||
|   } | ||||
|  | ||||
|   virtual StringSlot* allocExpandableString() { | ||||
|     StringSlot* s = allocStringSlot(); | ||||
|     if (!s) return 0; | ||||
|  | ||||
|     s->value = _left; | ||||
|     s->size = size_t(_right - _left); | ||||
|     _usedString.push(s); | ||||
|     _left = _right; | ||||
|  | ||||
|     checkInvariants(); | ||||
|     return s; | ||||
|   } | ||||
|  | ||||
|   virtual StringSlot* expandString(StringSlot*) { | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   virtual void freezeString(StringSlot* slot, size_t newSize) { | ||||
|     _left -= (slot->size - newSize); | ||||
|     slot->size = newSize; | ||||
|     checkInvariants(); | ||||
|   } | ||||
|  | ||||
|   void clear() { | ||||
|     _left = _begin; | ||||
|     _right = _end; | ||||
|     _freeVariants.clear(); | ||||
|     _freeStrings.clear(); | ||||
|     _usedString.clear(); | ||||
|   } | ||||
|  | ||||
|   bool canAlloc(size_t bytes) const { | ||||
|     return _left + bytes <= _right; | ||||
|   } | ||||
|  | ||||
|   bool owns(void* p) const { | ||||
|     return _begin <= p && p < _end; | ||||
|   } | ||||
|  | ||||
|   template <typename T> | ||||
|   T* allocRight() { | ||||
|     return reinterpret_cast<T*>(allocRight(sizeof(T))); | ||||
|   } | ||||
|  | ||||
|   char* allocRight(size_t bytes) { | ||||
|     if (!canAlloc(bytes)) return 0; | ||||
|     _right -= bytes; | ||||
|     return _right; | ||||
|   } | ||||
|  | ||||
|   // Workaround for missing placement new | ||||
|   void* operator new(size_t, void* p) { | ||||
|     return p; | ||||
|   } | ||||
|  | ||||
|  protected: | ||||
|   StaticMemoryPoolBase(char* buffer, size_t capa) | ||||
|       : _begin(buffer), | ||||
|         _left(buffer), | ||||
|         _right(buffer + capa), | ||||
|         _end(buffer + capa) {} | ||||
|  | ||||
|   ~StaticMemoryPoolBase() {} | ||||
|  | ||||
|   // Gets the current usage of the memoryPool in bytes | ||||
|   size_t allocated_bytes() const { | ||||
|     return size_t(_left - _begin + _end - _right); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   StringSlot* allocStringSlot() { | ||||
|     StringSlot* s = _freeStrings.pop(); | ||||
|     if (s) return s; | ||||
|     return allocRight<StringSlot>(); | ||||
|   } | ||||
|  | ||||
|   void freeVariantSlot(VariantSlot* slot) { | ||||
|     _freeVariants.push(slot); | ||||
|   } | ||||
|  | ||||
|   void freeStringSlot(StringSlot* slot) { | ||||
|     _usedString.remove(slot); | ||||
|     _freeStrings.push(slot); | ||||
|   } | ||||
|  | ||||
|   void compactLeftSide(char* holeAddress, size_t holeSize) { | ||||
|     ARDUINOJSON_ASSERT(holeAddress >= _begin); | ||||
|     ARDUINOJSON_ASSERT(holeAddress + holeSize <= _left); | ||||
|     char* holeEnd = holeAddress + holeSize; | ||||
|     memmove(holeAddress,               // where the hole begun | ||||
|             holeEnd,                   // where the hole ended | ||||
|             size_t(_left - holeEnd));  // everything after the hole | ||||
|     _left -= holeSize; | ||||
|     _usedString.forEach(UpdateStringSlotAddress(holeAddress, holeSize)); | ||||
|     checkInvariants(); | ||||
|   } | ||||
|  | ||||
|   void compactRightSide() { | ||||
|   loop: | ||||
|     if (_freeStrings.remove(_right)) { | ||||
|       _right += sizeof(StringSlot); | ||||
|       goto loop; | ||||
|     } | ||||
|     if (_freeVariants.remove(_right)) { | ||||
|       _right += sizeof(VariantSlot); | ||||
|       goto loop; | ||||
|     } | ||||
|     checkInvariants(); | ||||
|   } | ||||
|  | ||||
|   void checkInvariants() { | ||||
|     ARDUINOJSON_ASSERT(_begin <= _left); | ||||
|     ARDUINOJSON_ASSERT(_left <= _right); | ||||
|     ARDUINOJSON_ASSERT(_right <= _end); | ||||
|   } | ||||
|  | ||||
|   char *_begin, *_left, *_right, *_end; | ||||
|   SlotList<VariantSlot> _freeVariants; | ||||
|   SlotList<StringSlot> _freeStrings; | ||||
|   SlotList<StringSlot> _usedString; | ||||
| };  // namespace ARDUINOJSON_NAMESPACE | ||||
|  | ||||
| #if defined(__clang__) | ||||
| #pragma clang diagnostic push | ||||
| #pragma clang diagnostic ignored "-Wnon-virtual-dtor" | ||||
| #elif defined(__GNUC__) | ||||
| #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) | ||||
| #pragma GCC diagnostic push | ||||
| #endif | ||||
| #pragma GCC diagnostic ignored "-Wnon-virtual-dtor" | ||||
| #endif | ||||
|  | ||||
| // Implements a MemoryPool with fixed memory allocation. | ||||
| // The template paramenter CAPACITY specifies the capacity of the memoryPool in | ||||
| // bytes. | ||||
| template <size_t CAPACITY> | ||||
| class StaticMemoryPool : public StaticMemoryPoolBase { | ||||
|   static const size_t ACTUAL_CAPACITY = | ||||
|       AddPadding<Max<1, CAPACITY>::value>::value; | ||||
|  | ||||
|  public: | ||||
|   explicit StaticMemoryPool() | ||||
|       : StaticMemoryPoolBase(_buffer, ACTUAL_CAPACITY) {} | ||||
|  | ||||
|  private: | ||||
|   char _buffer[ACTUAL_CAPACITY]; | ||||
| }; | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
|  | ||||
| #if defined(__clang__) | ||||
| #pragma clang diagnostic pop | ||||
| #elif defined(__GNUC__) | ||||
| #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) | ||||
| #pragma GCC diagnostic pop | ||||
| #endif | ||||
| #endif | ||||
| @@ -29,8 +29,8 @@ class StringBuilder { | ||||
|     if (!_slot) return; | ||||
|  | ||||
|     if (_size >= _slot->size) { | ||||
|       _slot = _parent->expandString(_slot); | ||||
|       if (!_slot) return; | ||||
|       _slot = 0; | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     _slot->value[_size++] = c; | ||||
|   | ||||
							
								
								
									
										33
									
								
								src/ArduinoJson/StaticJsonDocument.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/ArduinoJson/StaticJsonDocument.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "JsonDocument.hpp" | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
|  | ||||
| template <size_t CAPACITY> | ||||
| class StaticJsonDocument : public JsonDocument { | ||||
|   static const size_t ACTUAL_CAPACITY = | ||||
|       AddPadding<Max<1, CAPACITY>::value>::value; | ||||
|  | ||||
|  public: | ||||
|   StaticJsonDocument() : JsonDocument(_buffer, ACTUAL_CAPACITY) {} | ||||
|  | ||||
|   StaticJsonDocument(const JsonDocument& src) | ||||
|       : JsonDocument(_buffer, ACTUAL_CAPACITY) { | ||||
|     copy(src); | ||||
|   } | ||||
|  | ||||
|   StaticJsonDocument operator=(const JsonDocument& src) { | ||||
|     copy(src); | ||||
|     return *this; | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   char _buffer[ACTUAL_CAPACITY]; | ||||
| }; | ||||
|  | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
| @@ -71,7 +71,6 @@ if(MSVC) | ||||
| 	) | ||||
| endif() | ||||
|  | ||||
| add_subdirectory(DynamicMemoryPool) | ||||
| add_subdirectory(IntegrationTests) | ||||
| add_subdirectory(JsonArray) | ||||
| add_subdirectory(JsonDeserializer) | ||||
| @@ -80,9 +79,9 @@ add_subdirectory(JsonObject) | ||||
| add_subdirectory(JsonSerializer) | ||||
| add_subdirectory(JsonVariant) | ||||
| add_subdirectory(JsonWriter) | ||||
| add_subdirectory(MemoryPool) | ||||
| add_subdirectory(Misc) | ||||
| add_subdirectory(MixedConfiguration) | ||||
| add_subdirectory(MsgPackDeserializer) | ||||
| add_subdirectory(MsgPackSerializer) | ||||
| add_subdirectory(Numbers) | ||||
| add_subdirectory(StaticMemoryPool) | ||||
| add_subdirectory(MixedConfiguration) | ||||
|   | ||||
| @@ -1,16 +0,0 @@ | ||||
| # ArduinoJson - arduinojson.org | ||||
| # Copyright Benoit Blanchon 2014-2018 | ||||
| # MIT License | ||||
|  | ||||
| add_executable(DynamicMemoryPoolTests | ||||
| 	allocString.cpp | ||||
| 	allocVariant.cpp | ||||
| 	blocks.cpp | ||||
| 	clear.cpp | ||||
| 	no_memory.cpp | ||||
| 	size.cpp | ||||
| 	StringBuilder.cpp | ||||
| ) | ||||
|  | ||||
| target_link_libraries(DynamicMemoryPoolTests catch) | ||||
| add_test(DynamicMemoryPool DynamicMemoryPoolTests) | ||||
| @@ -1,41 +0,0 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #include <ArduinoJson/Memory/DynamicMemoryPool.hpp> | ||||
| #include <ArduinoJson/Memory/StringBuilder.hpp> | ||||
| #include <catch.hpp> | ||||
|  | ||||
| using namespace ARDUINOJSON_NAMESPACE; | ||||
|  | ||||
| TEST_CASE("DynamicMemoryPool::startString()") { | ||||
|   SECTION("WorksWhenBufferIsBigEnough") { | ||||
|     DynamicMemoryPool memoryPool(JSON_STRING_SIZE(8)); | ||||
|  | ||||
|     StringBuilder str(&memoryPool); | ||||
|     str.append("abcdefg"); | ||||
|  | ||||
|     REQUIRE(memoryPool.blockCount() == 1); | ||||
|     REQUIRE(str.complete().equals("abcdefg")); | ||||
|   } | ||||
|  | ||||
|   SECTION("GrowsWhenBufferIsTooSmall") { | ||||
|     DynamicMemoryPool memoryPool(JSON_STRING_SIZE(8)); | ||||
|  | ||||
|     StringBuilder str(&memoryPool); | ||||
|     str.append("abcdefghABC"); | ||||
|  | ||||
|     REQUIRE(memoryPool.blockCount() == 2); | ||||
|     REQUIRE(str.complete().equals("abcdefghABC")); | ||||
|   } | ||||
|  | ||||
|   SECTION("SizeIncreases") { | ||||
|     DynamicMemoryPool memoryPool(JSON_STRING_SIZE(5)); | ||||
|  | ||||
|     StringBuilder str(&memoryPool); | ||||
|     str.append('h'); | ||||
|     str.complete(); | ||||
|  | ||||
|     REQUIRE(JSON_STRING_SIZE(2) == memoryPool.size()); | ||||
|   } | ||||
| } | ||||
| @@ -1,28 +0,0 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #include <ArduinoJson/Memory/DynamicMemoryPool.hpp> | ||||
| #include <catch.hpp> | ||||
| #include <sstream> | ||||
|  | ||||
| using namespace ARDUINOJSON_NAMESPACE; | ||||
|  | ||||
| TEST_CASE("DynamicMemoryPool::allocFrozenString()") { | ||||
|   DynamicMemoryPool pool; | ||||
|  | ||||
|   SECTION("Returns different pointers") { | ||||
|     StringSlot* a = pool.allocFrozenString(1); | ||||
|     StringSlot* b = pool.allocFrozenString(2); | ||||
|     REQUIRE(a != b); | ||||
|     REQUIRE(a->value != b->value); | ||||
|   } | ||||
|  | ||||
|   SECTION("Returns same slot after freeString") { | ||||
|     StringSlot* a = pool.allocFrozenString(1); | ||||
|     pool.freeString(a); | ||||
|     StringSlot* b = pool.allocFrozenString(2); | ||||
|     REQUIRE(a == b); | ||||
|     REQUIRE(a->value == b->value); | ||||
|   } | ||||
| } | ||||
| @@ -1,41 +0,0 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #include <ArduinoJson/Memory/DynamicMemoryPool.hpp> | ||||
| #include <catch.hpp> | ||||
|  | ||||
| using namespace ARDUINOJSON_NAMESPACE; | ||||
|  | ||||
| TEST_CASE("DynamicMemoryPool::allocVariant()") { | ||||
|   DynamicMemoryPool memoryPool; | ||||
|  | ||||
|   SECTION("Returns different pointer") { | ||||
|     VariantSlot* s1 = memoryPool.allocVariant(); | ||||
|     VariantSlot* s2 = memoryPool.allocVariant(); | ||||
|  | ||||
|     REQUIRE(s1 != s2); | ||||
|   } | ||||
|  | ||||
|   SECTION("Returns same pointer after freeSlot()") { | ||||
|     VariantSlot* s1 = memoryPool.allocVariant(); | ||||
|     memoryPool.freeVariant(s1); | ||||
|     VariantSlot* s2 = memoryPool.allocVariant(); | ||||
|  | ||||
|     REQUIRE(s1 == s2); | ||||
|   } | ||||
|  | ||||
|   SECTION("Returns aligned pointers") { | ||||
|     // make room for two but not three | ||||
|     // pass an uneven capacity | ||||
|     DynamicMemoryPool pool(2 * sizeof(VariantSlot) + 1); | ||||
|  | ||||
|     REQUIRE(isAligned(pool.allocVariant())); | ||||
|     REQUIRE(isAligned(pool.allocVariant())); | ||||
|     REQUIRE(pool.blockCount() == 1); | ||||
|  | ||||
|     REQUIRE(isAligned(pool.allocVariant())); | ||||
|     REQUIRE(isAligned(pool.allocVariant())); | ||||
|     REQUIRE(pool.blockCount() == 2); | ||||
|   } | ||||
| } | ||||
| @@ -1,69 +0,0 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #include <ArduinoJson/Memory/DynamicMemoryPool.hpp> | ||||
| #include <catch.hpp> | ||||
| #include <sstream> | ||||
|  | ||||
| using namespace ARDUINOJSON_NAMESPACE; | ||||
|  | ||||
| std::stringstream allocatorLog; | ||||
|  | ||||
| struct SpyingAllocator : DefaultAllocator { | ||||
|   void* allocate(size_t n) { | ||||
|     allocatorLog << "A" << (n - DynamicMemoryPool::EmptyBlockSize); | ||||
|     return DefaultAllocator::allocate(n); | ||||
|   } | ||||
|   void deallocate(void* p) { | ||||
|     allocatorLog << "F"; | ||||
|     return DefaultAllocator::deallocate(p); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| TEST_CASE("DynamicMemoryPool blocks") { | ||||
|   SECTION("Doubles allocation size when full") { | ||||
|     allocatorLog.str(""); | ||||
|     { | ||||
|       DynamicMemoryPoolBase<SpyingAllocator> memoryPool(sizeof(VariantSlot)); | ||||
|       memoryPool.allocVariant(); | ||||
|       memoryPool.allocVariant(); | ||||
|     } | ||||
|     std::stringstream expected; | ||||
|     expected << "A" << sizeof(VariantSlot)      // block 1 | ||||
|              << "A" << 2 * sizeof(VariantSlot)  // block 2, twice bigger | ||||
|              << "FF"; | ||||
|  | ||||
|     REQUIRE(allocatorLog.str() == expected.str()); | ||||
|   } | ||||
|  | ||||
|   SECTION("Resets allocation size after clear()") { | ||||
|     allocatorLog.str(""); | ||||
|     { | ||||
|       DynamicMemoryPoolBase<SpyingAllocator> memoryPool(sizeof(VariantSlot)); | ||||
|       memoryPool.allocVariant(); | ||||
|       memoryPool.allocVariant(); | ||||
|       memoryPool.clear(); | ||||
|       memoryPool.allocVariant(); | ||||
|     } | ||||
|     std::stringstream expected; | ||||
|     expected << "A" << sizeof(VariantSlot)      // block 1 | ||||
|              << "A" << 2 * sizeof(VariantSlot)  // block 2, twice bigger | ||||
|              << "FF"                            // clear | ||||
|              << "A" << sizeof(VariantSlot)      // block 1 | ||||
|              << "F"; | ||||
|     REQUIRE(allocatorLog.str() == expected.str()); | ||||
|   } | ||||
|  | ||||
|   /* SECTION("Alloc big block for large string") { | ||||
|      allocatorLog.str(""); | ||||
|      { | ||||
|        DynamicMemoryPoolBase<SpyingAllocator> memoryPool(1); | ||||
|        memoryPool.allocString(42); | ||||
|      } | ||||
|      std::stringstream expected; | ||||
|      expected << "A" << JSON_STRING_SIZE(42)  // block 1 | ||||
|               << "F"; | ||||
|      REQUIRE(allocatorLog.str() == expected.str()); | ||||
|    }*/ | ||||
| } | ||||
| @@ -1,47 +0,0 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #include <ArduinoJson/Memory/DynamicMemoryPool.hpp> | ||||
| #include <catch.hpp> | ||||
|  | ||||
| using namespace ARDUINOJSON_NAMESPACE; | ||||
|  | ||||
| TEST_CASE("StaticMemoryPool::clear()") { | ||||
|   DynamicMemoryPool memoryPool; | ||||
|  | ||||
|   SECTION("Discards allocated variants") { | ||||
|     memoryPool.allocVariant(); | ||||
|     REQUIRE(memoryPool.size() > 0); | ||||
|  | ||||
|     memoryPool.clear(); | ||||
|     CHECK(memoryPool.size() == 0); | ||||
|   } | ||||
|  | ||||
|   SECTION("Discards allocated strings") { | ||||
|     memoryPool.allocFrozenString(10); | ||||
|     REQUIRE(memoryPool.size() > 0); | ||||
|  | ||||
|     memoryPool.clear(); | ||||
|  | ||||
|     CHECK(memoryPool.size() == 0); | ||||
|   } | ||||
|  | ||||
|   SECTION("Purges variant cache") { | ||||
|     memoryPool.freeVariant(memoryPool.allocVariant()); | ||||
|     REQUIRE(memoryPool.size() == 0); | ||||
|  | ||||
|     memoryPool.clear(); | ||||
|  | ||||
|     CHECK(memoryPool.size() == 0); | ||||
|   } | ||||
|  | ||||
|   SECTION("Purges string cache") { | ||||
|     memoryPool.freeString(memoryPool.allocFrozenString(10)); | ||||
|     // REQUIRE(memoryPool.size() == 0); | ||||
|  | ||||
|     memoryPool.clear(); | ||||
|  | ||||
|     CHECK(memoryPool.size() == 0); | ||||
|   } | ||||
| } | ||||
| @@ -1,41 +0,0 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #include <ArduinoJson/Memory/DynamicMemoryPool.hpp> | ||||
| #include <ArduinoJson/Memory/StringBuilder.hpp> | ||||
| #include <catch.hpp> | ||||
|  | ||||
| using namespace ARDUINOJSON_NAMESPACE; | ||||
|  | ||||
| struct NoMemoryAllocator { | ||||
|   void* allocate(size_t) { | ||||
|     return NULL; | ||||
|   } | ||||
|   void deallocate(void*) {} | ||||
| }; | ||||
|  | ||||
| TEST_CASE("DynamicMemoryPool no memory") { | ||||
|   DynamicMemoryPoolBase<NoMemoryAllocator> _memoryPool; | ||||
|  | ||||
|   SECTION("FixCodeCoverage") { | ||||
|     // call this function to fix code coverage | ||||
|     NoMemoryAllocator().deallocate(NULL); | ||||
|   } | ||||
|  | ||||
|   // TODO: uncomment | ||||
|   // SECTION("deserializeJson()") { | ||||
|   //   char json[] = "{[]}"; | ||||
|   //   DynamicJsonDocument obj; | ||||
|  | ||||
|   //   DeserializationError err = deserializeJson(obj, json); | ||||
|  | ||||
|   //   REQUIRE(err != DeserializationError::Ok); | ||||
|   // } | ||||
|  | ||||
|   SECTION("StringBuilder returns null") { | ||||
|     StringBuilder str(&_memoryPool); | ||||
|     str.append('!'); | ||||
|     REQUIRE(str.complete().isNull()); | ||||
|   } | ||||
| } | ||||
| @@ -1,56 +0,0 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #include <ArduinoJson/Memory/DynamicMemoryPool.hpp> | ||||
| #include <catch.hpp> | ||||
|  | ||||
| using namespace ARDUINOJSON_NAMESPACE; | ||||
|  | ||||
| TEST_CASE("DynamicMemoryPool::size()") { | ||||
|   DynamicMemoryPool memoryPool; | ||||
|  | ||||
|   SECTION("Initial size is 0") { | ||||
|     REQUIRE(0 == memoryPool.size()); | ||||
|   } | ||||
|  | ||||
|   SECTION("Increases after allocExpandableString()") { | ||||
|     StringSlot* a = memoryPool.allocExpandableString(); | ||||
|     memoryPool.freezeString(a, 1); | ||||
|     REQUIRE(memoryPool.size() == JSON_STRING_SIZE(1)); | ||||
|  | ||||
|     StringSlot* b = memoryPool.allocExpandableString(); | ||||
|     memoryPool.freezeString(b, 1); | ||||
|     REQUIRE(memoryPool.size() == 2 * JSON_STRING_SIZE(1)); | ||||
|   } | ||||
|  | ||||
|   SECTION("Increases after allocVariant()") { | ||||
|     memoryPool.allocVariant(); | ||||
|     REQUIRE(sizeof(VariantSlot) == memoryPool.size()); | ||||
|  | ||||
|     memoryPool.allocVariant(); | ||||
|     REQUIRE(2 * sizeof(VariantSlot) == memoryPool.size()); | ||||
|   } | ||||
|  | ||||
|   SECTION("Decreases after freeVariant()") { | ||||
|     VariantSlot* a = memoryPool.allocVariant(); | ||||
|     VariantSlot* b = memoryPool.allocVariant(); | ||||
|  | ||||
|     memoryPool.freeVariant(b); | ||||
|     REQUIRE(sizeof(VariantSlot) == memoryPool.size()); | ||||
|  | ||||
|     memoryPool.freeVariant(a); | ||||
|     REQUIRE(0 == memoryPool.size()); | ||||
|   } | ||||
|  | ||||
|   SECTION("Decreases after freeString()") { | ||||
|     StringSlot* a = memoryPool.allocFrozenString(5); | ||||
|     StringSlot* b = memoryPool.allocFrozenString(6); | ||||
|  | ||||
|     memoryPool.freeString(b); | ||||
|     REQUIRE(memoryPool.size() == JSON_STRING_SIZE(5)); | ||||
|  | ||||
|     memoryPool.freeString(a); | ||||
|     REQUIRE(memoryPool.size() == 0); | ||||
|   } | ||||
| } | ||||
| @@ -39,6 +39,18 @@ TEST_CASE("DynamicJsonDocument") { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   SECTION("capacity()") { | ||||
|     SECTION("matches constructor argument") { | ||||
|       DynamicJsonDocument doc2(256); | ||||
|       REQUIRE(doc2.capacity() == 256); | ||||
|     } | ||||
|  | ||||
|     SECTION("rounds up constructor argument") { | ||||
|       DynamicJsonDocument doc2(253); | ||||
|       REQUIRE(doc2.capacity() == 256); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   SECTION("Copy constructor") { | ||||
|     deserializeJson(doc, "{\"hello\":\"world\"}"); | ||||
|     doc.nestingLimit = 42; | ||||
|   | ||||
| @@ -6,6 +6,18 @@ | ||||
| #include <catch.hpp> | ||||
|  | ||||
| TEST_CASE("StaticJsonDocument") { | ||||
|   SECTION("capacity()") { | ||||
|     SECTION("matches template argument") { | ||||
|       StaticJsonDocument<256> doc; | ||||
|       REQUIRE(doc.capacity() == 256); | ||||
|     } | ||||
|  | ||||
|     SECTION("rounds up template argument") { | ||||
|       StaticJsonDocument<253> doc; | ||||
|       REQUIRE(doc.capacity() == 256); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   SECTION("serializeJson()") { | ||||
|     StaticJsonDocument<200> doc; | ||||
|     JsonObject obj = doc.to<JsonObject>(); | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
| # Copyright Benoit Blanchon 2014-2018 | ||||
| # MIT License | ||||
| 
 | ||||
| add_executable(StaticMemoryPoolTests  | ||||
| add_executable(MemoryPoolTests  | ||||
| 	allocVariant.cpp | ||||
| 	allocString.cpp | ||||
| 	clear.cpp | ||||
| @@ -10,5 +10,5 @@ add_executable(StaticMemoryPoolTests | ||||
| 	StringBuilder.cpp | ||||
| ) | ||||
| 
 | ||||
| target_link_libraries(StaticMemoryPoolTests catch) | ||||
| add_test(StaticMemoryPool StaticMemoryPoolTests) | ||||
| target_link_libraries(MemoryPoolTests catch) | ||||
| add_test(MemoryPool MemoryPoolTests) | ||||
| @@ -2,15 +2,17 @@ | ||||
| // Copyright Benoit Blanchon 2014-2018
 | ||||
| // MIT License
 | ||||
| 
 | ||||
| #include <ArduinoJson/Memory/StaticMemoryPool.hpp> | ||||
| #include <ArduinoJson/Memory/MemoryPool.hpp> | ||||
| #include <ArduinoJson/Memory/StringBuilder.hpp> | ||||
| #include <catch.hpp> | ||||
| 
 | ||||
| using namespace ARDUINOJSON_NAMESPACE; | ||||
| 
 | ||||
| static char buffer[4096]; | ||||
| 
 | ||||
| TEST_CASE("StringBuilder") { | ||||
|   SECTION("WorksWhenBufferIsBigEnough") { | ||||
|     StaticMemoryPool<JSON_STRING_SIZE(6)> memoryPool; | ||||
|   SECTION("Works when buffer is big enough") { | ||||
|     MemoryPool memoryPool(buffer, addPadding(JSON_STRING_SIZE(6))); | ||||
| 
 | ||||
|     StringBuilder str(&memoryPool); | ||||
|     str.append("hello"); | ||||
| @@ -18,17 +20,17 @@ TEST_CASE("StringBuilder") { | ||||
|     REQUIRE(str.complete().equals("hello")); | ||||
|   } | ||||
| 
 | ||||
|   SECTION("ReturnsNullWhenTooSmall") { | ||||
|     StaticMemoryPool<1> memoryPool; | ||||
|   SECTION("Returns null when too small") { | ||||
|     MemoryPool memoryPool(buffer, sizeof(void*)); | ||||
| 
 | ||||
|     StringBuilder str(&memoryPool); | ||||
|     str.append("hello!!!"); | ||||
|     str.append("hello world!"); | ||||
| 
 | ||||
|     REQUIRE(str.complete().isNull()); | ||||
|   } | ||||
| 
 | ||||
|   SECTION("Increases size of memory pool") { | ||||
|     StaticMemoryPool<JSON_STRING_SIZE(6)> memoryPool; | ||||
|     MemoryPool memoryPool(buffer, addPadding(JSON_STRING_SIZE(6))); | ||||
| 
 | ||||
|     StringBuilder str(&memoryPool); | ||||
|     str.append('h'); | ||||
| @@ -2,15 +2,16 @@ | ||||
| // Copyright Benoit Blanchon 2014-2018
 | ||||
| // MIT License
 | ||||
| 
 | ||||
| #include <ArduinoJson/Memory/StaticMemoryPool.hpp> | ||||
| #include <ArduinoJson/Memory/MemoryPool.hpp> | ||||
| #include <catch.hpp> | ||||
| 
 | ||||
| using namespace ARDUINOJSON_NAMESPACE; | ||||
| 
 | ||||
| TEST_CASE("StaticMemoryPool::allocFrozenString()") { | ||||
| TEST_CASE("MemoryPool::allocFrozenString()") { | ||||
|   const size_t poolCapacity = 64; | ||||
|   const size_t longestString = poolCapacity - sizeof(StringSlot); | ||||
|   StaticMemoryPool<poolCapacity> pool; | ||||
|   char buffer[poolCapacity]; | ||||
|   MemoryPool pool(buffer, poolCapacity); | ||||
| 
 | ||||
|   SECTION("Returns different addresses") { | ||||
|     StringSlot *a = pool.allocFrozenString(1); | ||||
| @@ -35,6 +36,16 @@ TEST_CASE("StaticMemoryPool::allocFrozenString()") { | ||||
|     REQUIRE(0 == p); | ||||
|   } | ||||
| 
 | ||||
|   SECTION("Returns NULL when buffer is NULL") { | ||||
|     MemoryPool pool2(0, poolCapacity); | ||||
|     REQUIRE(0 == pool2.allocFrozenString(2)); | ||||
|   } | ||||
| 
 | ||||
|   SECTION("Returns NULL when capacity is 0") { | ||||
|     MemoryPool pool2(buffer, 0); | ||||
|     REQUIRE(0 == pool2.allocFrozenString(2)); | ||||
|   } | ||||
| 
 | ||||
|   SECTION("Returns aligned pointers") { | ||||
|     REQUIRE(isAligned(pool.allocFrozenString(1))); | ||||
|     REQUIRE(isAligned(pool.allocFrozenString(1))); | ||||
| @@ -74,10 +85,11 @@ TEST_CASE("StaticMemoryPool::allocFrozenString()") { | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| TEST_CASE("StaticMemoryPool::freeString()") { | ||||
| TEST_CASE("MemoryPool::freeString()") { | ||||
|   const size_t poolCapacity = 512; | ||||
|   const size_t longestString = poolCapacity - sizeof(StringSlot); | ||||
|   StaticMemoryPool<poolCapacity> pool; | ||||
|   char buffer[poolCapacity]; | ||||
|   MemoryPool pool(buffer, poolCapacity); | ||||
| 
 | ||||
|   static const size_t testStringSize = | ||||
|       (poolCapacity - sizeof(StringSlot) * 4 - sizeof(VariantSlot) * 4) / 4; | ||||
							
								
								
									
										60
									
								
								test/MemoryPool/allocVariant.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								test/MemoryPool/allocVariant.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #include <ArduinoJson/Memory/MemoryPool.hpp> | ||||
| #include <catch.hpp> | ||||
|  | ||||
| using namespace ARDUINOJSON_NAMESPACE; | ||||
|  | ||||
| static char buffer[4096]; | ||||
|  | ||||
| TEST_CASE("MemoryPool::allocVariant()") { | ||||
|   SECTION("Returns different pointer") { | ||||
|     MemoryPool pool(buffer, sizeof(buffer)); | ||||
|  | ||||
|     VariantSlot* s1 = pool.allocVariant(); | ||||
|     REQUIRE(s1 != 0); | ||||
|     VariantSlot* s2 = pool.allocVariant(); | ||||
|     REQUIRE(s2 != 0); | ||||
|  | ||||
|     REQUIRE(s1 != s2); | ||||
|   } | ||||
|  | ||||
|   SECTION("Returns same pointer after freeSlot()") { | ||||
|     MemoryPool pool(buffer, sizeof(buffer)); | ||||
|  | ||||
|     VariantSlot* s1 = pool.allocVariant(); | ||||
|     pool.freeVariant(s1); | ||||
|     VariantSlot* s2 = pool.allocVariant(); | ||||
|  | ||||
|     REQUIRE(s1 == s2); | ||||
|   } | ||||
|  | ||||
|   SECTION("Returns aligned pointers") { | ||||
|     MemoryPool pool(buffer, sizeof(buffer)); | ||||
|  | ||||
|     REQUIRE(isAligned(pool.allocVariant())); | ||||
|     REQUIRE(isAligned(pool.allocVariant())); | ||||
|   } | ||||
|  | ||||
|   SECTION("Returns zero if capacity is 0") { | ||||
|     MemoryPool pool(buffer, 0); | ||||
|  | ||||
|     REQUIRE(pool.allocVariant() == 0); | ||||
|   } | ||||
|  | ||||
|   SECTION("Returns zero if buffer is null") { | ||||
|     MemoryPool pool(0, sizeof(buffer)); | ||||
|  | ||||
|     REQUIRE(pool.allocVariant() == 0); | ||||
|   } | ||||
|  | ||||
|   SECTION("Returns zero if capacity is insufficient") { | ||||
|     MemoryPool pool(buffer, sizeof(VariantSlot)); | ||||
|  | ||||
|     pool.allocVariant(); | ||||
|  | ||||
|     REQUIRE(pool.allocVariant() == 0); | ||||
|   } | ||||
| } | ||||
| @@ -2,15 +2,16 @@ | ||||
| // Copyright Benoit Blanchon 2014-2018
 | ||||
| // MIT License
 | ||||
| 
 | ||||
| #include <ArduinoJson/Memory/StaticMemoryPool.hpp> | ||||
| #include <ArduinoJson/Memory/MemoryPool.hpp> | ||||
| #include <catch.hpp> | ||||
| 
 | ||||
| using namespace ARDUINOJSON_NAMESPACE; | ||||
| 
 | ||||
| static const size_t poolCapacity = 512; | ||||
| 
 | ||||
| TEST_CASE("StaticMemoryPool::clear()") { | ||||
|   StaticMemoryPool<poolCapacity> memoryPool; | ||||
| TEST_CASE("MemoryPool::clear()") { | ||||
|   char buffer[poolCapacity]; | ||||
|   MemoryPool memoryPool(buffer, sizeof(buffer)); | ||||
| 
 | ||||
|   SECTION("Discards allocated variants") { | ||||
|     memoryPool.allocVariant(); | ||||
| @@ -21,6 +22,7 @@ TEST_CASE("StaticMemoryPool::clear()") { | ||||
| 
 | ||||
|   SECTION("Discards allocated strings") { | ||||
|     memoryPool.allocFrozenString(10); | ||||
|     REQUIRE(memoryPool.size() > 0); | ||||
| 
 | ||||
|     memoryPool.clear(); | ||||
| 
 | ||||
| @@ -2,44 +2,61 @@ | ||||
| // Copyright Benoit Blanchon 2014-2018
 | ||||
| // MIT License
 | ||||
| 
 | ||||
| #include <ArduinoJson/Memory/StaticMemoryPool.hpp> | ||||
| #include <ArduinoJson/Memory/MemoryPool.hpp> | ||||
| #include <catch.hpp> | ||||
| 
 | ||||
| using namespace ARDUINOJSON_NAMESPACE; | ||||
| 
 | ||||
| TEST_CASE("StaticMemoryPool::size()") { | ||||
|   SECTION("Capacity equals template parameter") { | ||||
|     const size_t capacity = 64; | ||||
|     StaticMemoryPool<capacity> memoryPool; | ||||
|     REQUIRE(capacity == memoryPool.capacity()); | ||||
|   } | ||||
| char buffer[4096]; | ||||
| 
 | ||||
| TEST_CASE("MemoryPool::capacity()") { | ||||
|   const size_t capacity = 64; | ||||
|   MemoryPool memoryPool(buffer, capacity); | ||||
|   REQUIRE(capacity == memoryPool.capacity()); | ||||
| } | ||||
| 
 | ||||
| TEST_CASE("MemoryPool::size()") { | ||||
|   MemoryPool memoryPool(buffer, sizeof(buffer)); | ||||
| 
 | ||||
|   SECTION("Initial size is 0") { | ||||
|     StaticMemoryPool<32> memoryPool; | ||||
|     REQUIRE(0 == memoryPool.size()); | ||||
|   } | ||||
| 
 | ||||
|   SECTION("size() == capacity() after allocExpandableString()") { | ||||
|     memoryPool.allocExpandableString(); | ||||
|     REQUIRE(memoryPool.size() == memoryPool.capacity()); | ||||
|   } | ||||
| 
 | ||||
|   SECTION("Decreases after freezeString()") { | ||||
|     StringSlot* a = memoryPool.allocExpandableString(); | ||||
|     memoryPool.freezeString(a, 1); | ||||
|     REQUIRE(memoryPool.size() == JSON_STRING_SIZE(1)); | ||||
| 
 | ||||
|     StringSlot* b = memoryPool.allocExpandableString(); | ||||
|     memoryPool.freezeString(b, 1); | ||||
|     REQUIRE(memoryPool.size() == 2 * JSON_STRING_SIZE(1)); | ||||
|   } | ||||
| 
 | ||||
|   SECTION("Increases after allocFrozenString()") { | ||||
|     StaticMemoryPool<128> memoryPool; | ||||
|     memoryPool.allocFrozenString(0); | ||||
|     REQUIRE(memoryPool.size() == JSON_STRING_SIZE(0)); | ||||
| 
 | ||||
|     memoryPool.allocFrozenString(0); | ||||
|     REQUIRE(memoryPool.size() == 2 * JSON_STRING_SIZE(0)); | ||||
|   } | ||||
| 
 | ||||
|   SECTION("Decreases after freeVariant()") { | ||||
|     StaticMemoryPool<128> memoryPool; | ||||
|     VariantSlot* a = memoryPool.allocVariant(); | ||||
|     VariantSlot* b = memoryPool.allocVariant(); | ||||
| 
 | ||||
|     memoryPool.freeVariant(b); | ||||
|     REQUIRE(memoryPool.size() == sizeof(VariantSlot)); | ||||
| 
 | ||||
|     memoryPool.freeVariant(a); | ||||
|     REQUIRE(memoryPool.size() == 0); | ||||
|   } | ||||
| 
 | ||||
|   SECTION("Decreases after calling freeString() in order") { | ||||
|     StaticMemoryPool<128> memoryPool; | ||||
|     StringSlot* a = memoryPool.allocFrozenString(5); | ||||
|     REQUIRE(a != 0); | ||||
|     StringSlot* b = memoryPool.allocFrozenString(6); | ||||
| @@ -52,7 +69,6 @@ TEST_CASE("StaticMemoryPool::size()") { | ||||
|   } | ||||
| 
 | ||||
|   SECTION("Decreases after calling freeString() in reverse order") { | ||||
|     StaticMemoryPool<128> memoryPool; | ||||
|     StringSlot* a = memoryPool.allocFrozenString(5); | ||||
|     REQUIRE(a != 0); | ||||
|     StringSlot* b = memoryPool.allocFrozenString(6); | ||||
| @@ -65,15 +81,13 @@ TEST_CASE("StaticMemoryPool::size()") { | ||||
|   } | ||||
| 
 | ||||
|   SECTION("Doesn't grow when memory pool is full") { | ||||
|     const size_t variantCount = 4; | ||||
|     const size_t capacity = variantCount * sizeof(VariantSlot); | ||||
|     StaticMemoryPool<capacity> memoryPool; | ||||
|     const size_t variantCount = sizeof(buffer) / sizeof(VariantSlot); | ||||
| 
 | ||||
|     for (size_t i = 0; i < variantCount; i++) memoryPool.allocVariant(); | ||||
|     REQUIRE(capacity == memoryPool.size()); | ||||
|     size_t size = memoryPool.size(); | ||||
| 
 | ||||
|     memoryPool.allocVariant(); | ||||
| 
 | ||||
|     REQUIRE(capacity == memoryPool.size()); | ||||
|     REQUIRE(size == memoryPool.size()); | ||||
|   } | ||||
| } | ||||
| @@ -26,7 +26,7 @@ static void check(const JsonArray array, const std::string& expected) { | ||||
| } | ||||
|  | ||||
| TEST_CASE("serialize MsgPack array") { | ||||
|   DynamicJsonDocument doc; | ||||
|   DynamicJsonDocument doc(JSON_ARRAY_SIZE(65536)); | ||||
|   JsonArray array = doc.to<JsonArray>(); | ||||
|  | ||||
|   SECTION("empty") { | ||||
|   | ||||
| @@ -1,38 +0,0 @@ | ||||
| // ArduinoJson - arduinojson.org | ||||
| // Copyright Benoit Blanchon 2014-2018 | ||||
| // MIT License | ||||
|  | ||||
| #include <ArduinoJson/Memory/StaticMemoryPool.hpp> | ||||
| #include <catch.hpp> | ||||
|  | ||||
| using namespace ARDUINOJSON_NAMESPACE; | ||||
|  | ||||
| TEST_CASE("StaticMemoryPool::allocVariant()") { | ||||
|   StaticMemoryPool<128> memoryPool; | ||||
|  | ||||
|   SECTION("Returns different pointer") { | ||||
|     VariantSlot* s1 = memoryPool.allocVariant(); | ||||
|     REQUIRE(s1 != 0); | ||||
|     VariantSlot* s2 = memoryPool.allocVariant(); | ||||
|     REQUIRE(s2 != 0); | ||||
|  | ||||
|     REQUIRE(s1 != s2); | ||||
|   } | ||||
|  | ||||
|   SECTION("Returns same pointer after freeSlot()") { | ||||
|     VariantSlot* s1 = memoryPool.allocVariant(); | ||||
|     memoryPool.freeVariant(s1); | ||||
|     VariantSlot* s2 = memoryPool.allocVariant(); | ||||
|  | ||||
|     REQUIRE(s1 == s2); | ||||
|   } | ||||
|  | ||||
|   SECTION("Returns aligned pointers") { | ||||
|     // make room for two | ||||
|     // pass an uneven capacity | ||||
|     StaticMemoryPool<2 * sizeof(VariantSlot) + 1> pool; | ||||
|  | ||||
|     REQUIRE(isAligned(pool.allocVariant())); | ||||
|     REQUIRE(isAligned(pool.allocVariant())); | ||||
|   } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user