mirror of
https://github.com/bblanchon/ArduinoJson.git
synced 2025-07-25 00:07:34 +02:00
Add abstract Allocator
class
This commit is contained in:
@ -8,37 +8,50 @@
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
class SpyingAllocator {
|
||||
class SpyingAllocator : public Allocator {
|
||||
public:
|
||||
SpyingAllocator(const SpyingAllocator& src) : _log(src._log) {}
|
||||
SpyingAllocator(std::ostream& log) : _log(log) {}
|
||||
SpyingAllocator& operator=(const SpyingAllocator& src) = delete;
|
||||
virtual ~SpyingAllocator() {}
|
||||
|
||||
void* allocate(size_t n) {
|
||||
void* allocate(size_t n) override {
|
||||
_log << "A" << n;
|
||||
return malloc(n);
|
||||
}
|
||||
void deallocate(void* p) {
|
||||
|
||||
void deallocate(void* p) override {
|
||||
_log << "F";
|
||||
free(p);
|
||||
}
|
||||
|
||||
void* reallocate(void* ptr, size_t n) override {
|
||||
_log << "R" << n;
|
||||
return realloc(ptr, n);
|
||||
}
|
||||
|
||||
std::string log() const {
|
||||
return _log.str();
|
||||
}
|
||||
|
||||
private:
|
||||
std::ostream& _log;
|
||||
std::ostringstream _log;
|
||||
};
|
||||
|
||||
class ControllableAllocator {
|
||||
class ControllableAllocator : public Allocator {
|
||||
public:
|
||||
ControllableAllocator() : _enabled(true) {}
|
||||
virtual ~ControllableAllocator() {}
|
||||
|
||||
void* allocate(size_t n) {
|
||||
void* allocate(size_t n) override {
|
||||
return _enabled ? malloc(n) : 0;
|
||||
}
|
||||
|
||||
void deallocate(void* p) {
|
||||
void deallocate(void* p) override {
|
||||
free(p);
|
||||
}
|
||||
|
||||
void* reallocate(void* ptr, size_t n) override {
|
||||
return realloc(ptr, n);
|
||||
}
|
||||
|
||||
void disable() {
|
||||
_enabled = false;
|
||||
}
|
||||
@ -48,47 +61,48 @@ class ControllableAllocator {
|
||||
};
|
||||
|
||||
TEST_CASE("BasicJsonDocument") {
|
||||
std::stringstream log;
|
||||
SpyingAllocator spyingAllocator;
|
||||
ControllableAllocator controllableAllocator;
|
||||
|
||||
SECTION("Construct/Destruct") {
|
||||
{ BasicJsonDocument<SpyingAllocator> doc(4096, log); }
|
||||
REQUIRE(log.str() == "A4096F");
|
||||
{ BasicJsonDocument doc(4096, &spyingAllocator); }
|
||||
REQUIRE(spyingAllocator.log() == "A4096F");
|
||||
}
|
||||
|
||||
SECTION("Copy construct") {
|
||||
{
|
||||
BasicJsonDocument<SpyingAllocator> doc1(4096, log);
|
||||
BasicJsonDocument doc1(4096, &spyingAllocator);
|
||||
doc1.set(std::string("The size of this string is 32!!"));
|
||||
|
||||
BasicJsonDocument<SpyingAllocator> doc2(doc1);
|
||||
BasicJsonDocument doc2(doc1);
|
||||
|
||||
REQUIRE(doc1.as<std::string>() == "The size of this string is 32!!");
|
||||
REQUIRE(doc2.as<std::string>() == "The size of this string is 32!!");
|
||||
REQUIRE(doc2.capacity() == 4096);
|
||||
}
|
||||
REQUIRE(log.str() == "A4096A4096FF");
|
||||
REQUIRE(spyingAllocator.log() == "A4096A4096FF");
|
||||
}
|
||||
|
||||
SECTION("Move construct") {
|
||||
{
|
||||
BasicJsonDocument<SpyingAllocator> doc1(4096, log);
|
||||
BasicJsonDocument doc1(4096, &spyingAllocator);
|
||||
doc1.set(std::string("The size of this string is 32!!"));
|
||||
|
||||
BasicJsonDocument<SpyingAllocator> doc2(std::move(doc1));
|
||||
BasicJsonDocument doc2(std::move(doc1));
|
||||
|
||||
REQUIRE(doc2.as<std::string>() == "The size of this string is 32!!");
|
||||
REQUIRE(doc1.as<std::string>() == "null");
|
||||
REQUIRE(doc1.capacity() == 0);
|
||||
REQUIRE(doc2.capacity() == 4096);
|
||||
}
|
||||
REQUIRE(log.str() == "A4096F");
|
||||
REQUIRE(spyingAllocator.log() == "A4096F");
|
||||
}
|
||||
|
||||
SECTION("Copy assign larger") {
|
||||
{
|
||||
BasicJsonDocument<SpyingAllocator> doc1(4096, log);
|
||||
BasicJsonDocument doc1(4096, &spyingAllocator);
|
||||
doc1.set(std::string("The size of this string is 32!!"));
|
||||
BasicJsonDocument<SpyingAllocator> doc2(8, log);
|
||||
BasicJsonDocument doc2(8, &spyingAllocator);
|
||||
|
||||
doc2 = doc1;
|
||||
|
||||
@ -96,14 +110,14 @@ TEST_CASE("BasicJsonDocument") {
|
||||
REQUIRE(doc2.as<std::string>() == "The size of this string is 32!!");
|
||||
REQUIRE(doc2.capacity() == 4096);
|
||||
}
|
||||
REQUIRE(log.str() == "A4096A8FA4096FF");
|
||||
REQUIRE(spyingAllocator.log() == "A4096A8FA4096FF");
|
||||
}
|
||||
|
||||
SECTION("Copy assign smaller") {
|
||||
{
|
||||
BasicJsonDocument<SpyingAllocator> doc1(1024, log);
|
||||
BasicJsonDocument doc1(1024, &spyingAllocator);
|
||||
doc1.set(std::string("The size of this string is 32!!"));
|
||||
BasicJsonDocument<SpyingAllocator> doc2(4096, log);
|
||||
BasicJsonDocument doc2(4096, &spyingAllocator);
|
||||
|
||||
doc2 = doc1;
|
||||
|
||||
@ -111,14 +125,14 @@ TEST_CASE("BasicJsonDocument") {
|
||||
REQUIRE(doc2.as<std::string>() == "The size of this string is 32!!");
|
||||
REQUIRE(doc2.capacity() == 1024);
|
||||
}
|
||||
REQUIRE(log.str() == "A1024A4096FA1024FF");
|
||||
REQUIRE(spyingAllocator.log() == "A1024A4096FA1024FF");
|
||||
}
|
||||
|
||||
SECTION("Copy assign same size") {
|
||||
{
|
||||
BasicJsonDocument<SpyingAllocator> doc1(1024, log);
|
||||
BasicJsonDocument doc1(1024, &spyingAllocator);
|
||||
doc1.set(std::string("The size of this string is 32!!"));
|
||||
BasicJsonDocument<SpyingAllocator> doc2(1024, log);
|
||||
BasicJsonDocument doc2(1024, &spyingAllocator);
|
||||
|
||||
doc2 = doc1;
|
||||
|
||||
@ -126,14 +140,14 @@ TEST_CASE("BasicJsonDocument") {
|
||||
REQUIRE(doc2.as<std::string>() == "The size of this string is 32!!");
|
||||
REQUIRE(doc2.capacity() == 1024);
|
||||
}
|
||||
REQUIRE(log.str() == "A1024A1024FF");
|
||||
REQUIRE(spyingAllocator.log() == "A1024A1024FF");
|
||||
}
|
||||
|
||||
SECTION("Move assign") {
|
||||
{
|
||||
BasicJsonDocument<SpyingAllocator> doc1(4096, log);
|
||||
BasicJsonDocument doc1(4096, &spyingAllocator);
|
||||
doc1.set(std::string("The size of this string is 32!!"));
|
||||
BasicJsonDocument<SpyingAllocator> doc2(8, log);
|
||||
BasicJsonDocument doc2(8, &spyingAllocator);
|
||||
|
||||
doc2 = std::move(doc1);
|
||||
|
||||
@ -142,11 +156,11 @@ TEST_CASE("BasicJsonDocument") {
|
||||
REQUIRE(doc1.capacity() == 0);
|
||||
REQUIRE(doc2.capacity() == 4096);
|
||||
}
|
||||
REQUIRE(log.str() == "A4096A8FF");
|
||||
REQUIRE(spyingAllocator.log() == "A4096A8FF");
|
||||
}
|
||||
|
||||
SECTION("garbageCollect()") {
|
||||
BasicJsonDocument<ControllableAllocator> doc(4096);
|
||||
BasicJsonDocument doc(4096, &controllableAllocator);
|
||||
|
||||
SECTION("when allocation succeeds") {
|
||||
deserializeJson(doc, "{\"blanket\":1,\"dancing\":2}");
|
||||
@ -167,7 +181,7 @@ TEST_CASE("BasicJsonDocument") {
|
||||
REQUIRE(doc.capacity() == 4096);
|
||||
REQUIRE(doc.memoryUsage() == JSON_OBJECT_SIZE(2) + 16);
|
||||
doc.remove("blanket");
|
||||
doc.allocator().disable();
|
||||
controllableAllocator.disable();
|
||||
|
||||
bool result = doc.garbageCollect();
|
||||
|
||||
|
@ -8,24 +8,25 @@
|
||||
#include <stdlib.h> // malloc, free
|
||||
#include <string>
|
||||
|
||||
class ArmoredAllocator {
|
||||
class ArmoredAllocator : public Allocator {
|
||||
public:
|
||||
ArmoredAllocator() : _ptr(0), _size(0) {}
|
||||
virtual ~ArmoredAllocator() {}
|
||||
|
||||
void* allocate(size_t size) {
|
||||
void* allocate(size_t size) override {
|
||||
_ptr = malloc(size);
|
||||
_size = size;
|
||||
return _ptr;
|
||||
}
|
||||
|
||||
void deallocate(void* ptr) {
|
||||
void deallocate(void* ptr) override {
|
||||
REQUIRE(ptr == _ptr);
|
||||
free(ptr);
|
||||
_ptr = 0;
|
||||
_size = 0;
|
||||
}
|
||||
|
||||
void* reallocate(void* ptr, size_t new_size) {
|
||||
void* reallocate(void* ptr, size_t new_size) override {
|
||||
REQUIRE(ptr == _ptr);
|
||||
// don't call realloc, instead alloc a new buffer and erase the old one
|
||||
// this way we make sure we support relocation
|
||||
@ -42,9 +43,7 @@ class ArmoredAllocator {
|
||||
size_t _size;
|
||||
};
|
||||
|
||||
typedef BasicJsonDocument<ArmoredAllocator> ShrinkToFitTestDocument;
|
||||
|
||||
void testShrinkToFit(ShrinkToFitTestDocument& doc, std::string expected_json,
|
||||
void testShrinkToFit(DynamicJsonDocument& doc, std::string expected_json,
|
||||
size_t expected_size) {
|
||||
// test twice: shrinkToFit() should be idempotent
|
||||
for (int i = 0; i < 2; i++) {
|
||||
@ -60,7 +59,8 @@ void testShrinkToFit(ShrinkToFitTestDocument& doc, std::string expected_json,
|
||||
}
|
||||
|
||||
TEST_CASE("BasicJsonDocument::shrinkToFit()") {
|
||||
ShrinkToFitTestDocument doc(4096);
|
||||
ArmoredAllocator armoredAllocator;
|
||||
DynamicJsonDocument doc(4096, &armoredAllocator);
|
||||
|
||||
SECTION("null") {
|
||||
testShrinkToFit(doc, "null", 0);
|
||||
|
Reference in New Issue
Block a user