소스 검색

Added `DynamicJsonBuffer::clear()`

Benoit Blanchon 8 년 전
부모
커밋
476e5aaa86

+ 1 - 0
CHANGELOG.md

@@ -6,6 +6,7 @@ HEAD
 
 * Made `JsonBuffer` non-copyable (PR #524 by @luisrayas3)
 * Added `StaticJsonBuffer::clear()`
+* Added `DynamicJsonBuffer::clear()`
 
 v5.10.1
 -------

+ 23 - 8
src/ArduinoJson/DynamicJsonBuffer.hpp

@@ -46,30 +46,35 @@ class DynamicJsonBufferBase
   };
 
  public:
+  enum { EmptyBlockSize = sizeof(EmptyBlock) };
+
   DynamicJsonBufferBase(size_t initialSize = 256)
       : _head(NULL), _nextBlockCapacity(initialSize) {}
 
   ~DynamicJsonBufferBase() {
-    Block* currentBlock = _head;
-
-    while (currentBlock != NULL) {
-      Block* nextBlock = currentBlock->next;
-      _allocator.deallocate(currentBlock);
-      currentBlock = nextBlock;
-    }
+    freeAllBlocks();
   }
 
+  // Gets the number of bytes occupied in the buffer
   size_t size() const {
     size_t total = 0;
     for (const Block* b = _head; b; b = b->next) total += b->size;
     return total;
   }
 
+  // Allocates the specified amount of bytes in the buffer
   virtual void* alloc(size_t bytes) {
     alignNextAlloc();
     return canAllocInHead(bytes) ? allocInHead(bytes) : allocInNewBlock(bytes);
   }
 
+  // Resets the buffer.
+  // USE WITH CAUTION: this invalidates all previously allocated data
+  void clear() {
+    freeAllBlocks();
+    _head = 0;
+  }
+
   class String {
    public:
     String(DynamicJsonBufferBase* parent)
@@ -129,7 +134,7 @@ class DynamicJsonBufferBase
   }
 
   bool addNewBlock(size_t capacity) {
-    size_t bytes = sizeof(EmptyBlock) + capacity;
+    size_t bytes = EmptyBlockSize + capacity;
     Block* block = static_cast<Block*>(_allocator.allocate(bytes));
     if (block == NULL) return false;
     block->capacity = capacity;
@@ -139,6 +144,16 @@ class DynamicJsonBufferBase
     return true;
   }
 
+  void freeAllBlocks() {
+    Block* currentBlock = _head;
+
+    while (currentBlock != NULL) {
+      Block* nextBlock = currentBlock->next;
+      _allocator.deallocate(currentBlock);
+      currentBlock = nextBlock;
+    }
+  }
+
   TAllocator _allocator;
   Block* _head;
   size_t _nextBlockCapacity;

+ 1 - 1
src/ArduinoJson/StaticJsonBuffer.hpp

@@ -71,7 +71,7 @@ class StaticJsonBufferBase : public JsonBufferBase<StaticJsonBufferBase> {
     return doAlloc(bytes);
   }
 
-  // Resets the size to zero.
+  // Resets the buffer.
   // USE WITH CAUTION: this invalidates all previously allocated data
   void clear() {
     _size = 0;

+ 3 - 2
test/DynamicJsonBuffer/CMakeLists.txt

@@ -8,10 +8,11 @@
 add_executable(DynamicJsonBufferTests 
 	alloc.cpp
 	createArray.cpp
-	no_memory.cpp
 	createObject.cpp
-	strdup.cpp
+	no_memory.cpp
+	size.cpp
 	startString.cpp
+	strdup.cpp
 )
 
 target_link_libraries(DynamicJsonBufferTests catch)

+ 44 - 11
test/DynamicJsonBuffer/alloc.cpp

@@ -7,6 +7,7 @@
 
 #include <ArduinoJson.h>
 #include <catch.hpp>
+#include <sstream>
 
 static bool isAligned(void* ptr) {
   const size_t mask = sizeof(void*) - 1;
@@ -14,26 +15,58 @@ static bool isAligned(void* ptr) {
   return (addr & mask) == 0;
 }
 
-TEST_CASE("DynamicJsonBuffer::alloc()") {
-  DynamicJsonBuffer buffer;
+std::stringstream allocatorLog;
 
-  SECTION("InitialSizeIsZero") {
-    REQUIRE(0 == buffer.size());
+struct SpyingAllocator : DefaultAllocator {
+  void* allocate(size_t n) {
+    allocatorLog << "A" << (n - DynamicJsonBuffer::EmptyBlockSize);
+    return DefaultAllocator::allocate(n);
   }
-
-  SECTION("SizeIncreasesAfterAlloc") {
-    buffer.alloc(1);
-    REQUIRE(1U <= buffer.size());
-    buffer.alloc(1);
-    REQUIRE(2U <= buffer.size());
+  void deallocate(void* p) {
+    allocatorLog << "F";
+    return DefaultAllocator::deallocate(p);
   }
+};
 
-  SECTION("ReturnDifferentPointer") {
+TEST_CASE("DynamicJsonBuffer::alloc()") {
+  SECTION("Returns different pointers") {
+    DynamicJsonBuffer buffer;
     void* p1 = buffer.alloc(1);
     void* p2 = buffer.alloc(2);
     REQUIRE(p1 != p2);
   }
 
+  SECTION("Doubles allocation size when full") {
+    allocatorLog.str("");
+    {
+      DynamicJsonBufferBase<SpyingAllocator> buffer(1);
+      buffer.alloc(1);
+      buffer.alloc(1);
+    }
+    REQUIRE(allocatorLog.str() == "A1A2FF");
+  }
+
+  SECTION("Keeps increasing allocation size after clear") {
+    allocatorLog.str("");
+    {
+      DynamicJsonBufferBase<SpyingAllocator> buffer(1);
+      buffer.alloc(1);
+      buffer.alloc(1);
+      buffer.clear();
+      buffer.alloc(1);
+    }
+    REQUIRE(allocatorLog.str() == "A1A2FFA4F");
+  }
+
+  SECTION("Makes a big allocation when needed") {
+    allocatorLog.str("");
+    {
+      DynamicJsonBufferBase<SpyingAllocator> buffer(1);
+      buffer.alloc(42);
+    }
+    REQUIRE(allocatorLog.str() == "A42F");
+  }
+
   SECTION("Alignment") {
     // make room for two but not three
     DynamicJsonBuffer tinyBuf(2 * sizeof(void*) + 1);

+ 30 - 0
test/DynamicJsonBuffer/size.cpp

@@ -0,0 +1,30 @@
+// Copyright Benoit Blanchon 2014-2017
+// MIT License
+//
+// Arduino JSON library
+// https://bblanchon.github.io/ArduinoJson/
+// If you like this project, please add a star!
+
+#include <ArduinoJson.h>
+#include <catch.hpp>
+
+TEST_CASE("DynamicJsonBuffer::size()") {
+  DynamicJsonBuffer buffer;
+
+  SECTION("Initial size is 0") {
+    REQUIRE(0 == buffer.size());
+  }
+
+  SECTION("Increases after alloc()") {
+    buffer.alloc(1);
+    REQUIRE(1U <= buffer.size());
+    buffer.alloc(1);
+    REQUIRE(2U <= buffer.size());
+  }
+
+  SECTION("Goes back to 0 after clear()") {
+    buffer.alloc(1);
+    buffer.clear();
+    REQUIRE(0 == buffer.size());
+  }
+}