forked from bblanchon/ArduinoJson
Store offset between slots to reduce memory usage
This commit is contained in:
@ -6,6 +6,7 @@ HEAD
|
|||||||
|
|
||||||
* Removed the automatic expansion of `DynamicJsonDocument`, it now has a fixed capacity.
|
* Removed the automatic expansion of `DynamicJsonDocument`, it now has a fixed capacity.
|
||||||
* Restored the monotonic allocator because the code was getting too big
|
* Restored the monotonic allocator because the code was getting too big
|
||||||
|
* Reduced the memory usage
|
||||||
|
|
||||||
v6.6.0-beta (2018-11-13)
|
v6.6.0-beta (2018-11-13)
|
||||||
-----------
|
-----------
|
||||||
|
@ -2,6 +2,10 @@
|
|||||||
# Copyright Benoit Blanchon 2014-2018
|
# Copyright Benoit Blanchon 2014-2018
|
||||||
# MIT License
|
# MIT License
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
add_compile_options(-D_CRT_SECURE_NO_WARNINGS)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_executable(msgpack_fuzzer
|
add_executable(msgpack_fuzzer
|
||||||
msgpack_fuzzer.cpp
|
msgpack_fuzzer.cpp
|
||||||
fuzzer_main.cpp
|
fuzzer_main.cpp
|
||||||
|
@ -17,10 +17,10 @@ inline JsonVariantData* arrayAdd(JsonArrayData* arr, MemoryPool* pool) {
|
|||||||
|
|
||||||
slot->next = 0;
|
slot->next = 0;
|
||||||
slot->value.type = JSON_NULL;
|
slot->value.type = JSON_NULL;
|
||||||
|
slot->value.keyIsOwned = false;
|
||||||
|
|
||||||
if (arr->tail) {
|
if (arr->tail) {
|
||||||
slot->prev = arr->tail;
|
slot->attachTo(arr->tail);
|
||||||
arr->tail->next = slot;
|
|
||||||
arr->tail = slot;
|
arr->tail = slot;
|
||||||
} else {
|
} else {
|
||||||
slot->prev = 0;
|
slot->prev = 0;
|
||||||
@ -28,13 +28,12 @@ inline JsonVariantData* arrayAdd(JsonArrayData* arr, MemoryPool* pool) {
|
|||||||
arr->tail = slot;
|
arr->tail = slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
slot->value.keyIsOwned = false;
|
|
||||||
return &slot->value;
|
return &slot->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline VariantSlot* arrayGetSlot(const JsonArrayData* arr, size_t index) {
|
inline VariantSlot* arrayGetSlot(const JsonArrayData* arr, size_t index) {
|
||||||
if (!arr) return 0;
|
if (!arr) return 0;
|
||||||
return slotAdvance(arr->head, index);
|
return arr->head->getNext(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline JsonVariantData* arrayGet(const JsonArrayData* arr, size_t index) {
|
inline JsonVariantData* arrayGet(const JsonArrayData* arr, size_t index) {
|
||||||
@ -46,13 +45,13 @@ inline void arrayRemove(JsonArrayData* arr, VariantSlot* slot) {
|
|||||||
if (!arr || !slot) return;
|
if (!arr || !slot) return;
|
||||||
|
|
||||||
if (slot->prev)
|
if (slot->prev)
|
||||||
slot->prev->next = slot->next;
|
slot->getPrev()->setNext(slot->getNext());
|
||||||
else
|
else
|
||||||
arr->head = slot->next;
|
arr->head = slot->getNext();
|
||||||
if (slot->next)
|
if (slot->next)
|
||||||
slot->next->prev = slot->prev;
|
slot->getNext()->setPrev(slot->getPrev());
|
||||||
else
|
else
|
||||||
arr->tail = slot->prev;
|
arr->tail = slot->getPrev();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void arrayRemove(JsonArrayData* arr, size_t index) {
|
inline void arrayRemove(JsonArrayData* arr, size_t index) {
|
||||||
@ -71,7 +70,7 @@ inline bool arrayCopy(JsonArrayData* dst, const JsonArrayData* src,
|
|||||||
MemoryPool* pool) {
|
MemoryPool* pool) {
|
||||||
if (!dst || !src) return false;
|
if (!dst || !src) return false;
|
||||||
arrayClear(dst);
|
arrayClear(dst);
|
||||||
for (VariantSlot* s = src->head; s; s = s->next) {
|
for (VariantSlot* s = src->head; s; s = s->getNext()) {
|
||||||
if (!variantCopy(arrayAdd(dst, pool), &s->value, pool)) return false;
|
if (!variantCopy(arrayAdd(dst, pool), &s->value, pool)) return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -88,8 +87,8 @@ inline bool arrayEquals(const JsonArrayData* a1, const JsonArrayData* a2) {
|
|||||||
if (s1 == s2) return true;
|
if (s1 == s2) return true;
|
||||||
if (!s1 || !s2) return false;
|
if (!s1 || !s2) return false;
|
||||||
if (!variantEquals(&s1->value, &s2->value)) return false;
|
if (!variantEquals(&s1->value, &s2->value)) return false;
|
||||||
s1 = s1->next;
|
s1 = s1->getNext();
|
||||||
s2 = s2->next;
|
s2 = s2->getNext();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ inline VariantSlot* objectFindSlot(const JsonObjectData* obj, TKey key) {
|
|||||||
VariantSlot* slot = obj->head;
|
VariantSlot* slot = obj->head;
|
||||||
while (slot) {
|
while (slot) {
|
||||||
if (key.equals(slotGetKey(slot))) break;
|
if (key.equals(slotGetKey(slot))) break;
|
||||||
slot = slot->next;
|
slot = slot->getNext();
|
||||||
}
|
}
|
||||||
return slot;
|
return slot;
|
||||||
}
|
}
|
||||||
@ -36,8 +36,7 @@ inline JsonVariantData* objectAdd(JsonObjectData* obj, TKey key,
|
|||||||
slot->value.type = JSON_NULL;
|
slot->value.type = JSON_NULL;
|
||||||
|
|
||||||
if (obj->tail) {
|
if (obj->tail) {
|
||||||
slot->prev = obj->tail;
|
slot->attachTo(obj->tail);
|
||||||
obj->tail->next = slot;
|
|
||||||
obj->tail = slot;
|
obj->tail = slot;
|
||||||
} else {
|
} else {
|
||||||
slot->prev = 0;
|
slot->prev = 0;
|
||||||
@ -79,14 +78,16 @@ inline void objectClear(JsonObjectData* obj) {
|
|||||||
inline void objectRemove(JsonObjectData* obj, VariantSlot* slot) {
|
inline void objectRemove(JsonObjectData* obj, VariantSlot* slot) {
|
||||||
if (!obj) return;
|
if (!obj) return;
|
||||||
if (!slot) return;
|
if (!slot) return;
|
||||||
if (slot->prev)
|
VariantSlot* prev = slot->getPrev();
|
||||||
slot->prev->next = slot->next;
|
VariantSlot* next = slot->getNext();
|
||||||
|
if (prev)
|
||||||
|
prev->setNext(next);
|
||||||
else
|
else
|
||||||
obj->head = slot->next;
|
obj->head = next;
|
||||||
if (slot->next)
|
if (next)
|
||||||
slot->next->prev = slot->prev;
|
next->setPrev(prev);
|
||||||
else
|
else
|
||||||
obj->tail = slot->prev;
|
obj->tail = prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline size_t objectSize(const JsonObjectData* obj) {
|
inline size_t objectSize(const JsonObjectData* obj) {
|
||||||
@ -100,7 +101,7 @@ inline bool objectCopy(JsonObjectData* dst, const JsonObjectData* src,
|
|||||||
MemoryPool* pool) {
|
MemoryPool* pool) {
|
||||||
if (!dst || !src) return false;
|
if (!dst || !src) return false;
|
||||||
objectClear(dst);
|
objectClear(dst);
|
||||||
for (VariantSlot* s = src->head; s; s = s->next) {
|
for (VariantSlot* s = src->head; s; s = s->getNext()) {
|
||||||
JsonVariantData* var;
|
JsonVariantData* var;
|
||||||
if (s->value.keyIsOwned)
|
if (s->value.keyIsOwned)
|
||||||
var = objectAdd(dst, ZeroTerminatedRamString(s->key), pool);
|
var = objectAdd(dst, ZeroTerminatedRamString(s->key), pool);
|
||||||
@ -115,7 +116,7 @@ inline bool objectEquals(const JsonObjectData* o1, const JsonObjectData* o2) {
|
|||||||
if (o1 == o2) return true;
|
if (o1 == o2) return true;
|
||||||
if (!o1 || !o2) return false;
|
if (!o1 || !o2) return false;
|
||||||
|
|
||||||
for (VariantSlot* s = o1->head; s; s = s->next) {
|
for (VariantSlot* s = o1->head; s; s = s->getNext()) {
|
||||||
JsonVariantData* v1 = &s->value;
|
JsonVariantData* v1 = &s->value;
|
||||||
JsonVariantData* v2 = objectGet(o2, makeString(slotGetKey(s)));
|
JsonVariantData* v2 = objectGet(o2, makeString(slotGetKey(s)));
|
||||||
if (!variantEquals(v1, v2)) return false;
|
if (!variantEquals(v1, v2)) return false;
|
||||||
|
@ -37,27 +37,11 @@ inline const char* slotGetKey(const VariantSlot* var) {
|
|||||||
return var->key;
|
return var->key;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const VariantSlot* slotAdvance(const VariantSlot* var, size_t distance) {
|
|
||||||
while (distance && var) {
|
|
||||||
var = var->next;
|
|
||||||
distance--;
|
|
||||||
}
|
|
||||||
return var;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline VariantSlot* slotAdvance(VariantSlot* var, size_t distance) {
|
|
||||||
while (distance && var) {
|
|
||||||
var = var->next;
|
|
||||||
distance--;
|
|
||||||
}
|
|
||||||
return var;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline size_t slotSize(const VariantSlot* var) {
|
inline size_t slotSize(const VariantSlot* var) {
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
while (var) {
|
while (var) {
|
||||||
n++;
|
n++;
|
||||||
var = var->next;
|
var = var->getNext();
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
@ -48,12 +48,12 @@ class JsonArrayIterator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
JsonArrayIterator &operator++() {
|
JsonArrayIterator &operator++() {
|
||||||
_slot = _slot->next;
|
_slot = _slot->getNext();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonArrayIterator &operator+=(size_t distance) {
|
JsonArrayIterator &operator+=(size_t distance) {
|
||||||
_slot = slotAdvance(_slot, distance);
|
_slot = _slot->getNext(distance);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,12 +103,12 @@ class JsonArrayConstIterator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
JsonArrayConstIterator &operator++() {
|
JsonArrayConstIterator &operator++() {
|
||||||
_slot = _slot->next;
|
_slot = _slot->getNext();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonArrayConstIterator &operator+=(size_t distance) {
|
JsonArrayConstIterator &operator+=(size_t distance) {
|
||||||
_slot = slotAdvance(_slot, distance);
|
_slot = _slot->getNext(distance);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,12 +49,12 @@ class JsonObjectIterator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
JsonObjectIterator &operator++() {
|
JsonObjectIterator &operator++() {
|
||||||
if (_slot) _slot = _slot->next;
|
_slot = _slot->getNext();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonObjectIterator &operator+=(size_t distance) {
|
JsonObjectIterator &operator+=(size_t distance) {
|
||||||
_slot = slotAdvance(_slot, distance);
|
_slot = _slot->getNext(distance);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,12 +105,12 @@ class JsonObjectConstIterator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
JsonObjectConstIterator &operator++() {
|
JsonObjectConstIterator &operator++() {
|
||||||
if (_slot) _slot = _slot->next;
|
_slot = _slot->getNext();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonObjectConstIterator &operator+=(size_t distance) {
|
JsonObjectConstIterator &operator+=(size_t distance) {
|
||||||
_slot = slotAdvance(_slot, distance);
|
_slot = _slot->getNext(distance);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,14 +5,58 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../Data/JsonVariantData.hpp"
|
#include "../Data/JsonVariantData.hpp"
|
||||||
|
#include "../Polyfills/type_traits.hpp"
|
||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
|
typedef conditional<sizeof(void*) <= 2, int8_t, int16_t>::type VariantSlotDiff;
|
||||||
|
|
||||||
struct VariantSlot {
|
struct VariantSlot {
|
||||||
JsonVariantData value;
|
JsonVariantData value;
|
||||||
struct VariantSlot* next;
|
VariantSlotDiff next;
|
||||||
struct VariantSlot* prev;
|
VariantSlotDiff prev;
|
||||||
const char* key;
|
const char* key;
|
||||||
|
|
||||||
|
// Must be a POD! so no constructor, nor destructor, nor virtual
|
||||||
|
|
||||||
|
VariantSlot* getNext() {
|
||||||
|
return next ? this + next : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const VariantSlot* getNext() const {
|
||||||
|
return const_cast<VariantSlot*>(this)->getNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
VariantSlot* getNext(size_t distance) {
|
||||||
|
VariantSlot* slot = this;
|
||||||
|
while (distance--) {
|
||||||
|
if (!slot->next) return 0;
|
||||||
|
slot += slot->next;
|
||||||
|
}
|
||||||
|
return slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
const VariantSlot* getNext(size_t distance) const {
|
||||||
|
return const_cast<VariantSlot*>(this)->getNext(distance);
|
||||||
|
}
|
||||||
|
|
||||||
|
VariantSlot* getPrev() {
|
||||||
|
return prev ? this + prev : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setNext(VariantSlot* slot) {
|
||||||
|
this->next = VariantSlotDiff(slot ? slot - this : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPrev(VariantSlot* slot) {
|
||||||
|
this->prev = VariantSlotDiff(slot ? slot - this : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void attachTo(VariantSlot* tail) {
|
||||||
|
VariantSlotDiff offset = VariantSlotDiff(tail - this);
|
||||||
|
this->prev = offset;
|
||||||
|
tail->next = VariantSlotDiff(-offset);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "type_traits/conditional.hpp"
|
||||||
#include "type_traits/enable_if.hpp"
|
#include "type_traits/enable_if.hpp"
|
||||||
#include "type_traits/integral_constant.hpp"
|
#include "type_traits/integral_constant.hpp"
|
||||||
#include "type_traits/is_array.hpp"
|
#include "type_traits/is_array.hpp"
|
||||||
|
18
src/ArduinoJson/Polyfills/type_traits/conditional.hpp
Normal file
18
src/ArduinoJson/Polyfills/type_traits/conditional.hpp
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// ArduinoJson - arduinojson.org
|
||||||
|
// Copyright Benoit Blanchon 2014-2018
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
|
template <bool Condition, class TrueType, class FalseType>
|
||||||
|
struct conditional {
|
||||||
|
typedef TrueType type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class TrueType, class FalseType>
|
||||||
|
struct conditional<false, TrueType, FalseType> {
|
||||||
|
typedef FalseType type;
|
||||||
|
};
|
||||||
|
} // namespace ARDUINOJSON_NAMESPACE
|
@ -8,6 +8,7 @@ add_executable(JsonArrayTests
|
|||||||
copyTo.cpp
|
copyTo.cpp
|
||||||
createNested.cpp
|
createNested.cpp
|
||||||
equals.cpp
|
equals.cpp
|
||||||
|
get.cpp
|
||||||
isNull.cpp
|
isNull.cpp
|
||||||
iterator.cpp
|
iterator.cpp
|
||||||
remove.cpp
|
remove.cpp
|
||||||
|
16
test/JsonArray/get.cpp
Normal file
16
test/JsonArray/get.cpp
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// ArduinoJson - arduinojson.org
|
||||||
|
// Copyright Benoit Blanchon 2014-2018
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
#include <catch.hpp>
|
||||||
|
|
||||||
|
TEST_CASE("JsonArray::get()") {
|
||||||
|
DynamicJsonDocument doc;
|
||||||
|
deserializeJson(doc, "[1,2,3]");
|
||||||
|
JsonArray array = doc.as<JsonArray>();
|
||||||
|
|
||||||
|
SECTION("Overflow") {
|
||||||
|
REQUIRE(array.get(3).isNull());
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user