From 2bd280df807db950b0dbc6f19645d4ecff3ca5b8 Mon Sep 17 00:00:00 2001 From: Benoit Blanchon Date: Fri, 16 Nov 2018 10:26:59 +0100 Subject: [PATCH] Removed the automatic expansion of `DynamicJsonDocument` --- CHANGELOG.md | 5 + src/ArduinoJson.hpp | 4 +- src/ArduinoJson/DynamicJsonDocument.hpp | 49 ++++ src/ArduinoJson/JsonDocument.hpp | 75 ++---- src/ArduinoJson/Memory/DynamicMemoryPool.hpp | 187 -------------- src/ArduinoJson/Memory/MemoryPool.hpp | 204 +++++++++++++-- src/ArduinoJson/Memory/StaticMemoryPool.hpp | 236 ------------------ src/ArduinoJson/Memory/StringBuilder.hpp | 4 +- src/ArduinoJson/StaticJsonDocument.hpp | 33 +++ test/CMakeLists.txt | 5 +- test/DynamicMemoryPool/CMakeLists.txt | 16 -- test/DynamicMemoryPool/StringBuilder.cpp | 41 --- test/DynamicMemoryPool/allocString.cpp | 28 --- test/DynamicMemoryPool/allocVariant.cpp | 41 --- test/DynamicMemoryPool/blocks.cpp | 69 ----- test/DynamicMemoryPool/clear.cpp | 47 ---- test/DynamicMemoryPool/no_memory.cpp | 41 --- test/DynamicMemoryPool/size.cpp | 56 ----- test/JsonDocument/DynamicJsonDocument.cpp | 12 + test/JsonDocument/StaticJsonDocument.cpp | 12 + .../CMakeLists.txt | 6 +- .../StringBuilder.cpp | 16 +- .../allocString.cpp | 22 +- test/MemoryPool/allocVariant.cpp | 60 +++++ .../clear.cpp | 8 +- .../{StaticMemoryPool => MemoryPool}/size.cpp | 48 ++-- test/MsgPackSerializer/serializeArray.cpp | 2 +- test/StaticMemoryPool/allocVariant.cpp | 38 --- 28 files changed, 446 insertions(+), 919 deletions(-) create mode 100644 src/ArduinoJson/DynamicJsonDocument.hpp delete mode 100644 src/ArduinoJson/Memory/DynamicMemoryPool.hpp delete mode 100644 src/ArduinoJson/Memory/StaticMemoryPool.hpp create mode 100644 src/ArduinoJson/StaticJsonDocument.hpp delete mode 100644 test/DynamicMemoryPool/CMakeLists.txt delete mode 100644 test/DynamicMemoryPool/StringBuilder.cpp delete mode 100644 test/DynamicMemoryPool/allocString.cpp delete mode 100644 test/DynamicMemoryPool/allocVariant.cpp delete mode 100644 test/DynamicMemoryPool/blocks.cpp delete mode 100644 test/DynamicMemoryPool/clear.cpp delete mode 100644 test/DynamicMemoryPool/no_memory.cpp delete mode 100644 test/DynamicMemoryPool/size.cpp rename test/{StaticMemoryPool => MemoryPool}/CMakeLists.txt (54%) rename test/{StaticMemoryPool => MemoryPool}/StringBuilder.cpp (61%) rename test/{StaticMemoryPool => MemoryPool}/allocString.cpp (85%) create mode 100644 test/MemoryPool/allocVariant.cpp rename test/{StaticMemoryPool => MemoryPool}/clear.cpp (90%) rename test/{StaticMemoryPool => MemoryPool}/size.cpp (63%) delete mode 100644 test/StaticMemoryPool/allocVariant.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index adaf46dc..1a96f62f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) ----------- diff --git a/src/ArduinoJson.hpp b/src/ArduinoJson.hpp index 12d0e9da..3d91bd86 100644 --- a/src/ArduinoJson.hpp +++ b/src/ArduinoJson.hpp @@ -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" diff --git a/src/ArduinoJson/DynamicJsonDocument.hpp b/src/ArduinoJson/DynamicJsonDocument.hpp new file mode 100644 index 00000000..a1514cde --- /dev/null +++ b/src/ArduinoJson/DynamicJsonDocument.hpp @@ -0,0 +1,49 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 +// MIT License + +#pragma once + +#include "JsonDocument.hpp" + +#include // 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 + DynamicJsonDocument& operator=(const JsonDocument& src) { + copy(src); + return *this; + } + + private: + static char* alloc(size_t capa) { + return reinterpret_cast(malloc(addPadding(capa))); + } +}; + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/JsonDocument.hpp b/src/ArduinoJson/JsonDocument.hpp index f1cb234a..db2f6610 100644 --- a/src/ArduinoJson/JsonDocument.hpp +++ b/src/ArduinoJson/JsonDocument.hpp @@ -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 class JsonDocument : public Visitable { public: uint8_t nestingLimit; - JsonDocument() : nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT) {} - template 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 - void copy(const JsonDocument& src) { + JsonDocument(char* buf, size_t capa) + : nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT), + _memoryPool(buf, capa) {} + + void copy(const JsonDocument& src) { nestingLimit = src.nestingLimit; - to().set(src.template as()); + to().set(src.as()); } private: @@ -73,59 +77,8 @@ class JsonDocument : public Visitable { return JsonVariantConst(&_rootData); } - TMemoryPool _memoryPool; + MemoryPool _memoryPool; JsonVariantData _rootData; }; -class DynamicJsonDocument : public JsonDocument { - public: - DynamicJsonDocument() {} - DynamicJsonDocument(size_t capacity) { - memoryPool().reserve(capacity); - } - - DynamicJsonDocument(const DynamicJsonDocument& src) { - memoryPool().reserve(src.memoryUsage()); - copy(src); - } - - template - DynamicJsonDocument(const JsonDocument& src) { - memoryPool().reserve(src.memoryUsage()); - copy(src); - } - - DynamicJsonDocument& operator=(const DynamicJsonDocument& src) { - copy(src); - return *this; - } - - template - DynamicJsonDocument& operator=(const JsonDocument& src) { - copy(src); - return *this; - } -}; - -template -class StaticJsonDocument : public JsonDocument > { - public: - StaticJsonDocument() {} - - template - StaticJsonDocument(const JsonDocument& src) { - this->copy(src); - } - - StaticMemoryPoolBase& memoryPool() { - return JsonDocument >::memoryPool(); - } - - template - StaticJsonDocument operator=(const JsonDocument& src) { - this->copy(src); - return *this; - } -}; - } // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Memory/DynamicMemoryPool.hpp b/src/ArduinoJson/Memory/DynamicMemoryPool.hpp deleted file mode 100644 index b4292cba..00000000 --- a/src/ArduinoJson/Memory/DynamicMemoryPool.hpp +++ /dev/null @@ -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 // 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 -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(_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 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 diff --git a/src/ArduinoJson/Memory/MemoryPool.hpp b/src/ArduinoJson/Memory/MemoryPool.hpp index 41b803db..0bf24dd3 100644 --- a/src/ArduinoJson/Memory/MemoryPool.hpp +++ b/src/ArduinoJson/Memory/MemoryPool.hpp @@ -4,31 +4,203 @@ #pragma once -#include // 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(); + } + + 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 + T* allocRight() { + return reinterpret_cast(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(); + } + + 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 _freeVariants; + SlotList _freeStrings; + SlotList _usedString; }; + } // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Memory/StaticMemoryPool.hpp b/src/ArduinoJson/Memory/StaticMemoryPool.hpp deleted file mode 100644 index a1a34d52..00000000 --- a/src/ArduinoJson/Memory/StaticMemoryPool.hpp +++ /dev/null @@ -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(); - } - - 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 - T* allocRight() { - return reinterpret_cast(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(); - } - - 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 _freeVariants; - SlotList _freeStrings; - SlotList _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 -class StaticMemoryPool : public StaticMemoryPoolBase { - static const size_t ACTUAL_CAPACITY = - AddPadding::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 diff --git a/src/ArduinoJson/Memory/StringBuilder.hpp b/src/ArduinoJson/Memory/StringBuilder.hpp index 7a967913..49ea70e1 100644 --- a/src/ArduinoJson/Memory/StringBuilder.hpp +++ b/src/ArduinoJson/Memory/StringBuilder.hpp @@ -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; diff --git a/src/ArduinoJson/StaticJsonDocument.hpp b/src/ArduinoJson/StaticJsonDocument.hpp new file mode 100644 index 00000000..2f1fb5f4 --- /dev/null +++ b/src/ArduinoJson/StaticJsonDocument.hpp @@ -0,0 +1,33 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 +// MIT License + +#pragma once + +#include "JsonDocument.hpp" + +namespace ARDUINOJSON_NAMESPACE { + +template +class StaticJsonDocument : public JsonDocument { + static const size_t ACTUAL_CAPACITY = + AddPadding::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 diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8b96326f..5ed00b24 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -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) diff --git a/test/DynamicMemoryPool/CMakeLists.txt b/test/DynamicMemoryPool/CMakeLists.txt deleted file mode 100644 index e95b7bb4..00000000 --- a/test/DynamicMemoryPool/CMakeLists.txt +++ /dev/null @@ -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) diff --git a/test/DynamicMemoryPool/StringBuilder.cpp b/test/DynamicMemoryPool/StringBuilder.cpp deleted file mode 100644 index 12aaf159..00000000 --- a/test/DynamicMemoryPool/StringBuilder.cpp +++ /dev/null @@ -1,41 +0,0 @@ -// ArduinoJson - arduinojson.org -// Copyright Benoit Blanchon 2014-2018 -// MIT License - -#include -#include -#include - -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()); - } -} diff --git a/test/DynamicMemoryPool/allocString.cpp b/test/DynamicMemoryPool/allocString.cpp deleted file mode 100644 index 22d20710..00000000 --- a/test/DynamicMemoryPool/allocString.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// ArduinoJson - arduinojson.org -// Copyright Benoit Blanchon 2014-2018 -// MIT License - -#include -#include -#include - -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); - } -} diff --git a/test/DynamicMemoryPool/allocVariant.cpp b/test/DynamicMemoryPool/allocVariant.cpp deleted file mode 100644 index 70540b9f..00000000 --- a/test/DynamicMemoryPool/allocVariant.cpp +++ /dev/null @@ -1,41 +0,0 @@ -// ArduinoJson - arduinojson.org -// Copyright Benoit Blanchon 2014-2018 -// MIT License - -#include -#include - -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); - } -} diff --git a/test/DynamicMemoryPool/blocks.cpp b/test/DynamicMemoryPool/blocks.cpp deleted file mode 100644 index d9fcb912..00000000 --- a/test/DynamicMemoryPool/blocks.cpp +++ /dev/null @@ -1,69 +0,0 @@ -// ArduinoJson - arduinojson.org -// Copyright Benoit Blanchon 2014-2018 -// MIT License - -#include -#include -#include - -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 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 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 memoryPool(1); - memoryPool.allocString(42); - } - std::stringstream expected; - expected << "A" << JSON_STRING_SIZE(42) // block 1 - << "F"; - REQUIRE(allocatorLog.str() == expected.str()); - }*/ -} diff --git a/test/DynamicMemoryPool/clear.cpp b/test/DynamicMemoryPool/clear.cpp deleted file mode 100644 index 38e1b9a6..00000000 --- a/test/DynamicMemoryPool/clear.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// ArduinoJson - arduinojson.org -// Copyright Benoit Blanchon 2014-2018 -// MIT License - -#include -#include - -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); - } -} diff --git a/test/DynamicMemoryPool/no_memory.cpp b/test/DynamicMemoryPool/no_memory.cpp deleted file mode 100644 index 554b34df..00000000 --- a/test/DynamicMemoryPool/no_memory.cpp +++ /dev/null @@ -1,41 +0,0 @@ -// ArduinoJson - arduinojson.org -// Copyright Benoit Blanchon 2014-2018 -// MIT License - -#include -#include -#include - -using namespace ARDUINOJSON_NAMESPACE; - -struct NoMemoryAllocator { - void* allocate(size_t) { - return NULL; - } - void deallocate(void*) {} -}; - -TEST_CASE("DynamicMemoryPool no memory") { - DynamicMemoryPoolBase _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()); - } -} diff --git a/test/DynamicMemoryPool/size.cpp b/test/DynamicMemoryPool/size.cpp deleted file mode 100644 index f3f69384..00000000 --- a/test/DynamicMemoryPool/size.cpp +++ /dev/null @@ -1,56 +0,0 @@ -// ArduinoJson - arduinojson.org -// Copyright Benoit Blanchon 2014-2018 -// MIT License - -#include -#include - -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); - } -} diff --git a/test/JsonDocument/DynamicJsonDocument.cpp b/test/JsonDocument/DynamicJsonDocument.cpp index e6a99240..32643f07 100644 --- a/test/JsonDocument/DynamicJsonDocument.cpp +++ b/test/JsonDocument/DynamicJsonDocument.cpp @@ -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; diff --git a/test/JsonDocument/StaticJsonDocument.cpp b/test/JsonDocument/StaticJsonDocument.cpp index fe8c7e68..ebf34aca 100644 --- a/test/JsonDocument/StaticJsonDocument.cpp +++ b/test/JsonDocument/StaticJsonDocument.cpp @@ -6,6 +6,18 @@ #include 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(); diff --git a/test/StaticMemoryPool/CMakeLists.txt b/test/MemoryPool/CMakeLists.txt similarity index 54% rename from test/StaticMemoryPool/CMakeLists.txt rename to test/MemoryPool/CMakeLists.txt index 9fa5f180..d63db0f1 100644 --- a/test/StaticMemoryPool/CMakeLists.txt +++ b/test/MemoryPool/CMakeLists.txt @@ -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) diff --git a/test/StaticMemoryPool/StringBuilder.cpp b/test/MemoryPool/StringBuilder.cpp similarity index 61% rename from test/StaticMemoryPool/StringBuilder.cpp rename to test/MemoryPool/StringBuilder.cpp index 69c83614..0fc9b02b 100644 --- a/test/StaticMemoryPool/StringBuilder.cpp +++ b/test/MemoryPool/StringBuilder.cpp @@ -2,15 +2,17 @@ // Copyright Benoit Blanchon 2014-2018 // MIT License -#include +#include #include #include using namespace ARDUINOJSON_NAMESPACE; +static char buffer[4096]; + TEST_CASE("StringBuilder") { - SECTION("WorksWhenBufferIsBigEnough") { - StaticMemoryPool 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 memoryPool; + MemoryPool memoryPool(buffer, addPadding(JSON_STRING_SIZE(6))); StringBuilder str(&memoryPool); str.append('h'); diff --git a/test/StaticMemoryPool/allocString.cpp b/test/MemoryPool/allocString.cpp similarity index 85% rename from test/StaticMemoryPool/allocString.cpp rename to test/MemoryPool/allocString.cpp index eb033e09..7955b0ea 100644 --- a/test/StaticMemoryPool/allocString.cpp +++ b/test/MemoryPool/allocString.cpp @@ -2,15 +2,16 @@ // Copyright Benoit Blanchon 2014-2018 // MIT License -#include +#include #include 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 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 pool; + char buffer[poolCapacity]; + MemoryPool pool(buffer, poolCapacity); static const size_t testStringSize = (poolCapacity - sizeof(StringSlot) * 4 - sizeof(VariantSlot) * 4) / 4; diff --git a/test/MemoryPool/allocVariant.cpp b/test/MemoryPool/allocVariant.cpp new file mode 100644 index 00000000..75edd138 --- /dev/null +++ b/test/MemoryPool/allocVariant.cpp @@ -0,0 +1,60 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2018 +// MIT License + +#include +#include + +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); + } +} diff --git a/test/StaticMemoryPool/clear.cpp b/test/MemoryPool/clear.cpp similarity index 90% rename from test/StaticMemoryPool/clear.cpp rename to test/MemoryPool/clear.cpp index cfa4b7aa..89d72605 100644 --- a/test/StaticMemoryPool/clear.cpp +++ b/test/MemoryPool/clear.cpp @@ -2,15 +2,16 @@ // Copyright Benoit Blanchon 2014-2018 // MIT License -#include +#include #include using namespace ARDUINOJSON_NAMESPACE; static const size_t poolCapacity = 512; -TEST_CASE("StaticMemoryPool::clear()") { - StaticMemoryPool 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(); diff --git a/test/StaticMemoryPool/size.cpp b/test/MemoryPool/size.cpp similarity index 63% rename from test/StaticMemoryPool/size.cpp rename to test/MemoryPool/size.cpp index 771a09be..9ab5831d 100644 --- a/test/StaticMemoryPool/size.cpp +++ b/test/MemoryPool/size.cpp @@ -2,44 +2,61 @@ // Copyright Benoit Blanchon 2014-2018 // MIT License -#include +#include #include using namespace ARDUINOJSON_NAMESPACE; -TEST_CASE("StaticMemoryPool::size()") { - SECTION("Capacity equals template parameter") { - const size_t capacity = 64; - StaticMemoryPool 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 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()); } } diff --git a/test/MsgPackSerializer/serializeArray.cpp b/test/MsgPackSerializer/serializeArray.cpp index ca5e5060..2b7877c4 100644 --- a/test/MsgPackSerializer/serializeArray.cpp +++ b/test/MsgPackSerializer/serializeArray.cpp @@ -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(); SECTION("empty") { diff --git a/test/StaticMemoryPool/allocVariant.cpp b/test/StaticMemoryPool/allocVariant.cpp deleted file mode 100644 index 1c93f575..00000000 --- a/test/StaticMemoryPool/allocVariant.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// ArduinoJson - arduinojson.org -// Copyright Benoit Blanchon 2014-2018 -// MIT License - -#include -#include - -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())); - } -}