forked from bblanchon/ArduinoJson
Extracted VariantData and CollectionData classes
This commit is contained in:
@ -7,6 +7,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
|
* Reduced the memory usage
|
||||||
|
* Reduced the code size
|
||||||
* Removed spurious files in the Particle library
|
* Removed spurious files in the Particle library
|
||||||
|
|
||||||
v6.6.0-beta (2018-11-13)
|
v6.6.0-beta (2018-11-13)
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#include "ArduinoJson/Array/ArrayImpl.hpp"
|
#include "ArduinoJson/Array/ArrayImpl.hpp"
|
||||||
#include "ArduinoJson/Array/ArraySubscript.hpp"
|
#include "ArduinoJson/Array/ArraySubscript.hpp"
|
||||||
|
#include "ArduinoJson/Collection/CollectionImpl.hpp"
|
||||||
#include "ArduinoJson/Object/ObjectImpl.hpp"
|
#include "ArduinoJson/Object/ObjectImpl.hpp"
|
||||||
#include "ArduinoJson/Object/ObjectSubscript.hpp"
|
#include "ArduinoJson/Object/ObjectSubscript.hpp"
|
||||||
#include "ArduinoJson/Variant/VariantAsImpl.hpp"
|
#include "ArduinoJson/Variant/VariantAsImpl.hpp"
|
||||||
|
@ -4,92 +4,26 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../Variant/SlotFunctions.hpp"
|
#include "../Collection/CollectionData.hpp"
|
||||||
#include "../Variant/VariantData.hpp"
|
|
||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
inline VariantData* arrayAdd(ArrayData* arr, MemoryPool* pool) {
|
inline VariantData *arrayAdd(CollectionData *arr, MemoryPool *pool) {
|
||||||
if (!arr) return 0;
|
return arr ? arr->add(pool) : 0;
|
||||||
|
|
||||||
VariantSlot* slot = pool->allocVariant();
|
|
||||||
if (!slot) return 0;
|
|
||||||
|
|
||||||
slot->init();
|
|
||||||
|
|
||||||
if (arr->tail) {
|
|
||||||
slot->attachTo(arr->tail);
|
|
||||||
arr->tail = slot;
|
|
||||||
} else {
|
|
||||||
arr->head = slot;
|
|
||||||
arr->tail = slot;
|
|
||||||
}
|
|
||||||
|
|
||||||
return slot->getData();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline VariantSlot* arrayGetSlot(const ArrayData* arr, size_t index) {
|
template <typename Visitor>
|
||||||
if (!arr) return 0;
|
inline void arrayAccept(const CollectionData *arr, Visitor &visitor) {
|
||||||
return arr->head->getNext(index);
|
if (arr)
|
||||||
}
|
visitor.visitArray(*arr);
|
||||||
|
|
||||||
inline VariantData* arrayGet(const ArrayData* arr, size_t index) {
|
|
||||||
VariantSlot* slot = arrayGetSlot(arr, index);
|
|
||||||
return slot ? slot->getData() : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void arrayRemove(ArrayData* arr, VariantSlot* slot) {
|
|
||||||
if (!arr || !slot) return;
|
|
||||||
|
|
||||||
VariantSlot* prev = slot->getPrev(arr->head);
|
|
||||||
VariantSlot* next = slot->getNext();
|
|
||||||
|
|
||||||
if (prev)
|
|
||||||
prev->setNext(next);
|
|
||||||
else
|
else
|
||||||
arr->head = next;
|
visitor.visitNull();
|
||||||
if (!next) arr->tail = prev;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void arrayRemove(ArrayData* arr, size_t index) {
|
inline bool arrayEquals(const CollectionData *lhs, const CollectionData *rhs) {
|
||||||
arrayRemove(arr, arrayGetSlot(arr, index));
|
if (lhs == rhs) return true;
|
||||||
}
|
if (!lhs || !rhs) return false;
|
||||||
|
|
||||||
inline void arrayClear(ArrayData* arr) {
|
return lhs->equalsArray(*rhs);
|
||||||
if (!arr) return;
|
|
||||||
arr->head = 0;
|
|
||||||
arr->tail = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool variantCopy(VariantData*, const VariantData*, MemoryPool*);
|
|
||||||
|
|
||||||
inline bool arrayCopy(ArrayData* dst, const ArrayData* src, MemoryPool* pool) {
|
|
||||||
if (!dst || !src) return false;
|
|
||||||
arrayClear(dst);
|
|
||||||
for (VariantSlot* s = src->head; s; s = s->getNext()) {
|
|
||||||
if (!variantCopy(arrayAdd(dst, pool), s->getData(), pool)) return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool variantEquals(const VariantData*, const VariantData*);
|
|
||||||
|
|
||||||
inline bool arrayEquals(const ArrayData* a1, const ArrayData* a2) {
|
|
||||||
if (a1 == a2) return true;
|
|
||||||
if (!a1 || !a2) return false;
|
|
||||||
VariantSlot* s1 = a1->head;
|
|
||||||
VariantSlot* s2 = a2->head;
|
|
||||||
for (;;) {
|
|
||||||
if (s1 == s2) return true;
|
|
||||||
if (!s1 || !s2) return false;
|
|
||||||
if (!variantEquals(s1->getData(), s2->getData())) return false;
|
|
||||||
s1 = s1->getNext();
|
|
||||||
s2 = s2->getNext();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline size_t arraySize(const ArrayData* arr) {
|
|
||||||
if (!arr) return 0;
|
|
||||||
return slotSize(arr->head);
|
|
||||||
}
|
}
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
|
@ -11,8 +11,7 @@ namespace ARDUINOJSON_NAMESPACE {
|
|||||||
|
|
||||||
class VariantPtr {
|
class VariantPtr {
|
||||||
public:
|
public:
|
||||||
VariantPtr(MemoryPool *memoryPool, VariantData *data)
|
VariantPtr(MemoryPool *pool, VariantData *data) : _variant(pool, data) {}
|
||||||
: _variant(memoryPool, data) {}
|
|
||||||
|
|
||||||
VariantRef *operator->() {
|
VariantRef *operator->() {
|
||||||
return &_variant;
|
return &_variant;
|
||||||
@ -29,14 +28,14 @@ class VariantPtr {
|
|||||||
class ArrayIterator {
|
class ArrayIterator {
|
||||||
public:
|
public:
|
||||||
ArrayIterator() : _slot(0) {}
|
ArrayIterator() : _slot(0) {}
|
||||||
explicit ArrayIterator(MemoryPool *memoryPool, VariantSlot *slot)
|
explicit ArrayIterator(MemoryPool *pool, VariantSlot *slot)
|
||||||
: _memoryPool(memoryPool), _slot(slot) {}
|
: _pool(pool), _slot(slot) {}
|
||||||
|
|
||||||
VariantRef operator*() const {
|
VariantRef operator*() const {
|
||||||
return VariantRef(_memoryPool, _slot->getData());
|
return VariantRef(_pool, _slot->data());
|
||||||
}
|
}
|
||||||
VariantPtr operator->() {
|
VariantPtr operator->() {
|
||||||
return VariantPtr(_memoryPool, _slot->getData());
|
return VariantPtr(_pool, _slot->data());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const ArrayIterator &other) const {
|
bool operator==(const ArrayIterator &other) const {
|
||||||
@ -48,12 +47,12 @@ class ArrayIterator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ArrayIterator &operator++() {
|
ArrayIterator &operator++() {
|
||||||
_slot = _slot->getNext();
|
_slot = _slot->next();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayIterator &operator+=(size_t distance) {
|
ArrayIterator &operator+=(size_t distance) {
|
||||||
_slot = _slot->getNext(distance);
|
_slot = _slot->next(distance);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,7 +61,7 @@ class ArrayIterator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MemoryPool *_memoryPool;
|
MemoryPool *_pool;
|
||||||
VariantSlot *_slot;
|
VariantSlot *_slot;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -88,10 +87,10 @@ class ArrayConstRefIterator {
|
|||||||
explicit ArrayConstRefIterator(const VariantSlot *slot) : _slot(slot) {}
|
explicit ArrayConstRefIterator(const VariantSlot *slot) : _slot(slot) {}
|
||||||
|
|
||||||
VariantConstRef operator*() const {
|
VariantConstRef operator*() const {
|
||||||
return VariantConstRef(_slot->getData());
|
return VariantConstRef(_slot->data());
|
||||||
}
|
}
|
||||||
VariantConstPtr operator->() {
|
VariantConstPtr operator->() {
|
||||||
return VariantConstPtr(_slot->getData());
|
return VariantConstPtr(_slot->data());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const ArrayConstRefIterator &other) const {
|
bool operator==(const ArrayConstRefIterator &other) const {
|
||||||
@ -103,12 +102,12 @@ class ArrayConstRefIterator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ArrayConstRefIterator &operator++() {
|
ArrayConstRefIterator &operator++() {
|
||||||
_slot = _slot->getNext();
|
_slot = _slot->next();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayConstRefIterator &operator+=(size_t distance) {
|
ArrayConstRefIterator &operator+=(size_t distance) {
|
||||||
_slot = _slot->getNext(distance);
|
_slot = _slot->next(distance);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,16 +21,21 @@ class ArraySubscript;
|
|||||||
template <typename TData>
|
template <typename TData>
|
||||||
class ArrayRefBase {
|
class ArrayRefBase {
|
||||||
public:
|
public:
|
||||||
|
template <typename Visitor>
|
||||||
|
FORCE_INLINE void accept(Visitor& visitor) const {
|
||||||
|
arrayAccept(_data, visitor);
|
||||||
|
}
|
||||||
|
|
||||||
FORCE_INLINE bool isNull() const {
|
FORCE_INLINE bool isNull() const {
|
||||||
return _data == 0;
|
return _data == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE VariantConstRef operator[](size_t index) const {
|
FORCE_INLINE VariantConstRef operator[](size_t index) const {
|
||||||
return VariantConstRef(arrayGet(_data, index));
|
return VariantConstRef(_data ? _data->get(index) : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE size_t size() const {
|
FORCE_INLINE size_t size() const {
|
||||||
return arraySize(_data);
|
return _data ? _data->size() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -38,24 +43,17 @@ class ArrayRefBase {
|
|||||||
TData* _data;
|
TData* _data;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ArrayConstRef : public ArrayRefBase<const ArrayData>, public Visitable {
|
class ArrayConstRef : public ArrayRefBase<const CollectionData>,
|
||||||
|
public Visitable {
|
||||||
friend class ArrayRef;
|
friend class ArrayRef;
|
||||||
typedef ArrayRefBase<const ArrayData> base_type;
|
typedef ArrayRefBase<const CollectionData> base_type;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef ArrayConstRefIterator iterator;
|
typedef ArrayConstRefIterator iterator;
|
||||||
|
|
||||||
template <typename Visitor>
|
|
||||||
FORCE_INLINE void accept(Visitor& visitor) const {
|
|
||||||
if (_data)
|
|
||||||
visitor.visitArray(*this);
|
|
||||||
else
|
|
||||||
visitor.visitNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
FORCE_INLINE iterator begin() const {
|
FORCE_INLINE iterator begin() const {
|
||||||
if (!_data) return iterator();
|
if (!_data) return iterator();
|
||||||
return iterator(_data->head);
|
return iterator(_data->head());
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE iterator end() const {
|
FORCE_INLINE iterator end() const {
|
||||||
@ -63,25 +61,25 @@ class ArrayConstRef : public ArrayRefBase<const ArrayData>, public Visitable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE ArrayConstRef() : base_type(0) {}
|
FORCE_INLINE ArrayConstRef() : base_type(0) {}
|
||||||
FORCE_INLINE ArrayConstRef(const ArrayData* data) : base_type(data) {}
|
FORCE_INLINE ArrayConstRef(const CollectionData* data) : base_type(data) {}
|
||||||
|
|
||||||
FORCE_INLINE bool operator==(ArrayConstRef rhs) const {
|
FORCE_INLINE bool operator==(ArrayConstRef rhs) const {
|
||||||
return arrayEquals(_data, rhs._data);
|
return arrayEquals(_data, rhs._data);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ArrayRef : public ArrayRefBase<ArrayData>, public Visitable {
|
class ArrayRef : public ArrayRefBase<CollectionData>, public Visitable {
|
||||||
typedef ArrayRefBase<ArrayData> base_type;
|
typedef ArrayRefBase<CollectionData> base_type;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef ArrayIterator iterator;
|
typedef ArrayIterator iterator;
|
||||||
|
|
||||||
FORCE_INLINE ArrayRef() : base_type(0), _memoryPool(0) {}
|
FORCE_INLINE ArrayRef() : base_type(0), _pool(0) {}
|
||||||
FORCE_INLINE ArrayRef(MemoryPool* pool, ArrayData* data)
|
FORCE_INLINE ArrayRef(MemoryPool* pool, CollectionData* data)
|
||||||
: base_type(data), _memoryPool(pool) {}
|
: base_type(data), _pool(pool) {}
|
||||||
|
|
||||||
operator VariantRef() {
|
operator VariantRef() {
|
||||||
return VariantRef(_memoryPool, getVariantData(_data));
|
return VariantRef(_pool, reinterpret_cast<VariantData*>(_data));
|
||||||
}
|
}
|
||||||
|
|
||||||
operator ArrayConstRef() const {
|
operator ArrayConstRef() const {
|
||||||
@ -110,12 +108,12 @@ class ArrayRef : public ArrayRefBase<ArrayData>, public Visitable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
VariantRef add() const {
|
VariantRef add() const {
|
||||||
return VariantRef(_memoryPool, arrayAdd(_data, _memoryPool));
|
return VariantRef(_pool, arrayAdd(_data, _pool));
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE iterator begin() const {
|
FORCE_INLINE iterator begin() const {
|
||||||
if (!_data) return iterator();
|
if (!_data) return iterator();
|
||||||
return iterator(_memoryPool, _data->head);
|
return iterator(_pool, _data->head());
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE iterator end() const {
|
FORCE_INLINE iterator end() const {
|
||||||
@ -153,7 +151,8 @@ class ArrayRef : public ArrayRefBase<ArrayData>, public Visitable {
|
|||||||
|
|
||||||
// Copy a ArrayRef
|
// Copy a ArrayRef
|
||||||
FORCE_INLINE bool copyFrom(ArrayRef src) const {
|
FORCE_INLINE bool copyFrom(ArrayRef src) const {
|
||||||
return arrayCopy(_data, src._data, _memoryPool);
|
if (!_data || !src._data) return false;
|
||||||
|
return _data->copyFrom(*src._data, _pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exports a 1D array
|
// Exports a 1D array
|
||||||
@ -191,30 +190,22 @@ class ArrayRef : public ArrayRefBase<ArrayData>, public Visitable {
|
|||||||
|
|
||||||
// Gets the value at the specified index.
|
// Gets the value at the specified index.
|
||||||
FORCE_INLINE VariantRef get(size_t index) const {
|
FORCE_INLINE VariantRef get(size_t index) const {
|
||||||
return VariantRef(_memoryPool, arrayGet(_data, index));
|
return VariantRef(_pool, _data ? _data->get(index) : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes element at specified position.
|
// Removes element at specified position.
|
||||||
FORCE_INLINE void remove(iterator it) const {
|
FORCE_INLINE void remove(iterator it) const {
|
||||||
arrayRemove(_data, it.internal());
|
if (!_data) return;
|
||||||
|
_data->remove(it.internal());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes element at specified index.
|
// Removes element at specified index.
|
||||||
FORCE_INLINE void remove(size_t index) const {
|
FORCE_INLINE void remove(size_t index) const {
|
||||||
arrayRemove(_data, index);
|
if (!_data) return;
|
||||||
}
|
_data->remove(index);
|
||||||
|
|
||||||
template <typename Visitor>
|
|
||||||
FORCE_INLINE void accept(Visitor& visitor) const {
|
|
||||||
ArrayConstRef(_data).accept(visitor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename TValueRef>
|
MemoryPool* _pool;
|
||||||
FORCE_INLINE bool add_impl(TValueRef value) const {
|
|
||||||
return add().set(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
MemoryPool* _memoryPool;
|
|
||||||
};
|
};
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
|
68
src/ArduinoJson/Collection/CollectionData.hpp
Normal file
68
src/ArduinoJson/Collection/CollectionData.hpp
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
// ArduinoJson - arduinojson.org
|
||||||
|
// Copyright Benoit Blanchon 2014-2018
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
|
class MemoryPool;
|
||||||
|
class VariantData;
|
||||||
|
class VariantSlot;
|
||||||
|
|
||||||
|
class CollectionData {
|
||||||
|
VariantSlot *_head;
|
||||||
|
VariantSlot *_tail;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Must be a POD!
|
||||||
|
// - no constructor
|
||||||
|
// - no destructor
|
||||||
|
// - no virtual
|
||||||
|
// - no inheritance
|
||||||
|
VariantSlot *addSlot(MemoryPool *);
|
||||||
|
|
||||||
|
VariantData *add(MemoryPool *pool);
|
||||||
|
|
||||||
|
template <typename TKey>
|
||||||
|
VariantData *add(TKey key, MemoryPool *pool);
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
template <typename TKey>
|
||||||
|
bool containsKey(const TKey &key) const;
|
||||||
|
|
||||||
|
bool copyFrom(const CollectionData &src, MemoryPool *pool);
|
||||||
|
|
||||||
|
bool equalsArray(const CollectionData &other) const;
|
||||||
|
bool equalsObject(const CollectionData &other) const;
|
||||||
|
|
||||||
|
VariantData *get(size_t index) const;
|
||||||
|
|
||||||
|
template <typename TKey>
|
||||||
|
VariantData *get(TKey key) const;
|
||||||
|
|
||||||
|
VariantSlot *head() const {
|
||||||
|
return _head;
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove(size_t index);
|
||||||
|
|
||||||
|
template <typename TKey>
|
||||||
|
void remove(TKey key) {
|
||||||
|
remove(getSlot(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove(VariantSlot *slot);
|
||||||
|
|
||||||
|
size_t size() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
VariantSlot *getSlot(size_t index) const;
|
||||||
|
|
||||||
|
template <typename TKey>
|
||||||
|
VariantSlot *getSlot(TKey key) const;
|
||||||
|
|
||||||
|
VariantSlot *getPreviousSlot(VariantSlot *) const;
|
||||||
|
};
|
||||||
|
} // namespace ARDUINOJSON_NAMESPACE
|
145
src/ArduinoJson/Collection/CollectionImpl.hpp
Normal file
145
src/ArduinoJson/Collection/CollectionImpl.hpp
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
// ArduinoJson - arduinojson.org
|
||||||
|
// Copyright Benoit Blanchon 2014-2018
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../Variant/VariantData.hpp"
|
||||||
|
#include "CollectionData.hpp"
|
||||||
|
|
||||||
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
|
inline VariantSlot* CollectionData::addSlot(MemoryPool* pool) {
|
||||||
|
VariantSlot* slot = pool->allocVariant();
|
||||||
|
if (!slot) return 0;
|
||||||
|
|
||||||
|
if (_tail) {
|
||||||
|
_tail->setNextNotNull(slot);
|
||||||
|
_tail = slot;
|
||||||
|
} else {
|
||||||
|
_head = slot;
|
||||||
|
_tail = slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
slot->clear();
|
||||||
|
return slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VariantData* CollectionData::add(MemoryPool* pool) {
|
||||||
|
return addSlot(pool)->data();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TKey>
|
||||||
|
inline VariantData* CollectionData::add(TKey key, MemoryPool* pool) {
|
||||||
|
VariantSlot* slot = addSlot(pool);
|
||||||
|
if (!slotSetKey(slot, key, pool)) return 0;
|
||||||
|
return slot->data();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void CollectionData::clear() {
|
||||||
|
_head = 0;
|
||||||
|
_tail = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TKey>
|
||||||
|
inline bool CollectionData::containsKey(const TKey& key) const {
|
||||||
|
return getSlot(key) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool CollectionData::copyFrom(const CollectionData& src,
|
||||||
|
MemoryPool* pool) {
|
||||||
|
clear();
|
||||||
|
for (VariantSlot* s = src._head; s; s = s->next()) {
|
||||||
|
VariantData* var;
|
||||||
|
if (s->key() != 0) {
|
||||||
|
if (s->ownsKey())
|
||||||
|
var = add(ZeroTerminatedRamString(s->key()), pool);
|
||||||
|
else
|
||||||
|
var = add(ZeroTerminatedRamStringConst(s->key()), pool);
|
||||||
|
} else {
|
||||||
|
var = add(pool);
|
||||||
|
}
|
||||||
|
if (!var) return false;
|
||||||
|
if (!var->copyFrom(*s->data(), pool)) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool CollectionData::equalsObject(const CollectionData& other) const {
|
||||||
|
size_t count = 0;
|
||||||
|
for (VariantSlot* slot = _head; slot; slot = slot->next()) {
|
||||||
|
VariantData* v1 = slot->data();
|
||||||
|
VariantData* v2 = other.get(makeString(slot->key()));
|
||||||
|
if (!variantEquals(v1, v2)) return false;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count == other.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool CollectionData::equalsArray(const CollectionData& other) const {
|
||||||
|
VariantSlot* s1 = _head;
|
||||||
|
VariantSlot* s2 = other._head;
|
||||||
|
for (;;) {
|
||||||
|
if (s1 == s2) return true;
|
||||||
|
if (!s1 || !s2) return false;
|
||||||
|
if (!variantEquals(s1->data(), s2->data())) return false;
|
||||||
|
s1 = s1->next();
|
||||||
|
s2 = s2->next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TKey>
|
||||||
|
inline VariantSlot* CollectionData::getSlot(TKey key) const {
|
||||||
|
VariantSlot* slot = _head;
|
||||||
|
while (slot) {
|
||||||
|
if (key.equals(slot->key())) break;
|
||||||
|
slot = slot->next();
|
||||||
|
}
|
||||||
|
return slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VariantSlot* CollectionData::getSlot(size_t index) const {
|
||||||
|
return _head->next(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VariantSlot* CollectionData::getPreviousSlot(VariantSlot* target) const {
|
||||||
|
VariantSlot* current = _head;
|
||||||
|
while (current) {
|
||||||
|
VariantSlot* next = current->next();
|
||||||
|
if (next == target) return current;
|
||||||
|
current = next;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TKey>
|
||||||
|
inline VariantData* CollectionData::get(TKey key) const {
|
||||||
|
VariantSlot* slot = getSlot(key);
|
||||||
|
return slot ? slot->data() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline VariantData* CollectionData::get(size_t index) const {
|
||||||
|
VariantSlot* slot = getSlot(index);
|
||||||
|
return slot ? slot->data() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void CollectionData::remove(VariantSlot* slot) {
|
||||||
|
if (!slot) return;
|
||||||
|
VariantSlot* prev = getPreviousSlot(slot);
|
||||||
|
VariantSlot* next = slot->next();
|
||||||
|
if (prev)
|
||||||
|
prev->setNext(next);
|
||||||
|
else
|
||||||
|
_head = next;
|
||||||
|
if (!next) _tail = prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void CollectionData::remove(size_t index) {
|
||||||
|
remove(getSlot(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_t CollectionData::size() const {
|
||||||
|
return slotSize(_head);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ARDUINOJSON_NAMESPACE
|
@ -14,63 +14,58 @@
|
|||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
template <template <typename, typename> class TDeserializer,
|
template <template <typename, typename> class TDeserializer, typename TReader,
|
||||||
typename TMemoryPool, typename TReader, typename TWriter>
|
typename TWriter>
|
||||||
TDeserializer<TReader, TWriter> makeDeserializer(TMemoryPool &memoryPool,
|
TDeserializer<TReader, TWriter> makeDeserializer(MemoryPool &pool,
|
||||||
TReader reader, TWriter writer,
|
TReader reader, TWriter writer,
|
||||||
uint8_t nestingLimit) {
|
uint8_t nestingLimit) {
|
||||||
return TDeserializer<TReader, TWriter>(memoryPool, reader, writer,
|
return TDeserializer<TReader, TWriter>(pool, reader, writer, nestingLimit);
|
||||||
nestingLimit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeserializationError deserialize(TDocument& doc, TString input);
|
// DeserializationError deserialize(JsonDocument& doc, TString input);
|
||||||
// TDocument = DynamicJsonDocument, StaticJsonDocument
|
|
||||||
// TString = const std::string&, const String&
|
// TString = const std::string&, const String&
|
||||||
template <template <typename, typename> class TDeserializer, typename TDocument,
|
template <template <typename, typename> class TDeserializer, typename TString>
|
||||||
typename TString>
|
|
||||||
typename enable_if<!is_array<TString>::value, DeserializationError>::type
|
typename enable_if<!is_array<TString>::value, DeserializationError>::type
|
||||||
deserialize(TDocument &doc, const TString &input) {
|
deserialize(JsonDocument &doc, const TString &input) {
|
||||||
|
doc.clear();
|
||||||
return makeDeserializer<TDeserializer>(
|
return makeDeserializer<TDeserializer>(
|
||||||
doc.memoryPool(), makeReader(input),
|
doc.memoryPool(), makeReader(input),
|
||||||
makeStringStorage(doc.memoryPool(), input), doc.nestingLimit)
|
makeStringStorage(doc.memoryPool(), input), doc.nestingLimit)
|
||||||
.parse(doc.template to<VariantRef>());
|
.parse(doc.data());
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
// DeserializationError deserialize(TDocument& doc, TChar* input);
|
// DeserializationError deserialize(JsonDocument& doc, TChar* input);
|
||||||
// TDocument = DynamicJsonDocument, StaticJsonDocument
|
|
||||||
// TChar* = char*, const char*, const FlashStringHelper*
|
// TChar* = char*, const char*, const FlashStringHelper*
|
||||||
template <template <typename, typename> class TDeserializer, typename TDocument,
|
template <template <typename, typename> class TDeserializer, typename TChar>
|
||||||
typename TChar>
|
DeserializationError deserialize(JsonDocument &doc, TChar *input) {
|
||||||
DeserializationError deserialize(TDocument &doc, TChar *input) {
|
doc.clear();
|
||||||
return makeDeserializer<TDeserializer>(
|
return makeDeserializer<TDeserializer>(
|
||||||
doc.memoryPool(), makeReader(input),
|
doc.memoryPool(), makeReader(input),
|
||||||
makeStringStorage(doc.memoryPool(), input), doc.nestingLimit)
|
makeStringStorage(doc.memoryPool(), input), doc.nestingLimit)
|
||||||
.parse(doc.template to<VariantRef>());
|
.parse(doc.data());
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
// DeserializationError deserialize(TDocument& doc, TChar* input, size_t
|
// DeserializationError deserialize(JsonDocument& doc, TChar* input, size_t
|
||||||
// inputSize);
|
// inputSize);
|
||||||
// TDocument = DynamicJsonDocument, StaticJsonDocument
|
|
||||||
// TChar* = char*, const char*, const FlashStringHelper*
|
// TChar* = char*, const char*, const FlashStringHelper*
|
||||||
template <template <typename, typename> class TDeserializer, typename TDocument,
|
template <template <typename, typename> class TDeserializer, typename TChar>
|
||||||
typename TChar>
|
DeserializationError deserialize(JsonDocument &doc, TChar *input,
|
||||||
DeserializationError deserialize(TDocument &doc, TChar *input,
|
|
||||||
size_t inputSize) {
|
size_t inputSize) {
|
||||||
|
doc.clear();
|
||||||
return makeDeserializer<TDeserializer>(
|
return makeDeserializer<TDeserializer>(
|
||||||
doc.memoryPool(), makeReader(input, inputSize),
|
doc.memoryPool(), makeReader(input, inputSize),
|
||||||
makeStringStorage(doc.memoryPool(), input), doc.nestingLimit)
|
makeStringStorage(doc.memoryPool(), input), doc.nestingLimit)
|
||||||
.parse(doc.template to<VariantRef>());
|
.parse(doc.data());
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
// DeserializationError deserialize(TDocument& doc, TStream input);
|
// DeserializationError deserialize(JsonDocument& doc, TStream input);
|
||||||
// TDocument = DynamicJsonDocument, StaticJsonDocument
|
|
||||||
// TStream = std::istream&, Stream&
|
// TStream = std::istream&, Stream&
|
||||||
template <template <typename, typename> class TDeserializer, typename TDocument,
|
template <template <typename, typename> class TDeserializer, typename TStream>
|
||||||
typename TStream>
|
DeserializationError deserialize(JsonDocument &doc, TStream &input) {
|
||||||
DeserializationError deserialize(TDocument &doc, TStream &input) {
|
doc.clear();
|
||||||
return makeDeserializer<TDeserializer>(
|
return makeDeserializer<TDeserializer>(
|
||||||
doc.memoryPool(), makeReader(input),
|
doc.memoryPool(), makeReader(input),
|
||||||
makeStringStorage(doc.memoryPool(), input), doc.nestingLimit)
|
makeStringStorage(doc.memoryPool(), input), doc.nestingLimit)
|
||||||
.parse(doc.template to<VariantRef>());
|
.parse(doc.data());
|
||||||
}
|
}
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
|
@ -30,8 +30,8 @@ class JsonDocument : public Visitable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
_memoryPool.clear();
|
_pool.clear();
|
||||||
_rootData.type = JSON_NULL;
|
_data.setNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -40,16 +40,11 @@ class JsonDocument : public Visitable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t memoryUsage() const {
|
size_t memoryUsage() const {
|
||||||
return _memoryPool.size();
|
return _pool.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t capacity() const {
|
size_t capacity() const {
|
||||||
return _memoryPool.capacity();
|
return _pool.capacity();
|
||||||
}
|
|
||||||
|
|
||||||
// for internal use only
|
|
||||||
MemoryPool& memoryPool() {
|
|
||||||
return _memoryPool;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -58,10 +53,18 @@ class JsonDocument : public Visitable {
|
|||||||
return getVariant().template to<T>();
|
return getVariant().template to<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for internal use only
|
||||||
|
MemoryPool& memoryPool() {
|
||||||
|
return _pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
VariantData& data() {
|
||||||
|
return _data;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
JsonDocument(char* buf, size_t capa)
|
JsonDocument(char* buf, size_t capa)
|
||||||
: nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT),
|
: nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT), _pool(buf, capa) {}
|
||||||
_memoryPool(buf, capa) {}
|
|
||||||
|
|
||||||
void copy(const JsonDocument& src) {
|
void copy(const JsonDocument& src) {
|
||||||
nestingLimit = src.nestingLimit;
|
nestingLimit = src.nestingLimit;
|
||||||
@ -70,15 +73,15 @@ class JsonDocument : public Visitable {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
VariantRef getVariant() {
|
VariantRef getVariant() {
|
||||||
return VariantRef(&_memoryPool, &_rootData);
|
return VariantRef(&_pool, &_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
VariantConstRef getVariant() const {
|
VariantConstRef getVariant() const {
|
||||||
return VariantConstRef(&_rootData);
|
return VariantConstRef(&_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryPool _memoryPool;
|
MemoryPool _pool;
|
||||||
VariantData _rootData;
|
VariantData _data;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
#include "../Numbers/isFloat.hpp"
|
#include "../Numbers/isFloat.hpp"
|
||||||
#include "../Numbers/isInteger.hpp"
|
#include "../Numbers/isInteger.hpp"
|
||||||
#include "../Polyfills/type_traits.hpp"
|
#include "../Polyfills/type_traits.hpp"
|
||||||
#include "../Variant/VariantRef.hpp"
|
#include "../Variant/VariantData.hpp"
|
||||||
#include "EscapeSequence.hpp"
|
#include "EscapeSequence.hpp"
|
||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
@ -18,26 +18,26 @@ template <typename TReader, typename TStringStorage>
|
|||||||
class JsonDeserializer {
|
class JsonDeserializer {
|
||||||
typedef typename remove_reference<TStringStorage>::type::StringBuilder
|
typedef typename remove_reference<TStringStorage>::type::StringBuilder
|
||||||
StringBuilder;
|
StringBuilder;
|
||||||
typedef typename StringBuilder::StringType StringType;
|
typedef const char *StringType;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
JsonDeserializer(MemoryPool &memoryPool, TReader reader,
|
JsonDeserializer(MemoryPool &pool, TReader reader,
|
||||||
TStringStorage stringStorage, uint8_t nestingLimit)
|
TStringStorage stringStorage, uint8_t nestingLimit)
|
||||||
: _memoryPool(&memoryPool),
|
: _pool(&pool),
|
||||||
_reader(reader),
|
_reader(reader),
|
||||||
_stringStorage(stringStorage),
|
_stringStorage(stringStorage),
|
||||||
_nestingLimit(nestingLimit),
|
_nestingLimit(nestingLimit),
|
||||||
_loaded(false) {}
|
_loaded(false) {}
|
||||||
DeserializationError parse(VariantRef variant) {
|
DeserializationError parse(VariantData &variant) {
|
||||||
DeserializationError err = skipSpacesAndComments();
|
DeserializationError err = skipSpacesAndComments();
|
||||||
if (err) return err;
|
if (err) return err;
|
||||||
|
|
||||||
switch (current()) {
|
switch (current()) {
|
||||||
case '[':
|
case '[':
|
||||||
return parseArray(variant);
|
return parseArray(variant.toArray());
|
||||||
|
|
||||||
case '{':
|
case '{':
|
||||||
return parseObject(variant);
|
return parseObject(variant.toObject());
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return parseValue(variant);
|
return parseValue(variant);
|
||||||
@ -68,12 +68,9 @@ class JsonDeserializer {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError parseArray(VariantRef variant) {
|
DeserializationError parseArray(CollectionData &array) {
|
||||||
if (_nestingLimit == 0) return DeserializationError::TooDeep;
|
if (_nestingLimit == 0) return DeserializationError::TooDeep;
|
||||||
|
|
||||||
ArrayRef array = variant.to<ArrayRef>();
|
|
||||||
if (array.isNull()) return DeserializationError::NoMemory;
|
|
||||||
|
|
||||||
// Check opening braket
|
// Check opening braket
|
||||||
if (!eat('[')) return DeserializationError::InvalidInput;
|
if (!eat('[')) return DeserializationError::InvalidInput;
|
||||||
|
|
||||||
@ -87,12 +84,12 @@ class JsonDeserializer {
|
|||||||
// Read each value
|
// Read each value
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// Allocate slot in array
|
// Allocate slot in array
|
||||||
VariantRef value = array.add();
|
VariantData *value = array.add(_pool);
|
||||||
if (value.isInvalid()) return DeserializationError::NoMemory;
|
if (!value) return DeserializationError::NoMemory;
|
||||||
|
|
||||||
// 1 - Parse value
|
// 1 - Parse value
|
||||||
_nestingLimit--;
|
_nestingLimit--;
|
||||||
err = parse(value);
|
err = parse(*value);
|
||||||
_nestingLimit++;
|
_nestingLimit++;
|
||||||
if (err) return err;
|
if (err) return err;
|
||||||
|
|
||||||
@ -106,12 +103,9 @@ class JsonDeserializer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError parseObject(VariantRef variant) {
|
DeserializationError parseObject(CollectionData &object) {
|
||||||
if (_nestingLimit == 0) return DeserializationError::TooDeep;
|
if (_nestingLimit == 0) return DeserializationError::TooDeep;
|
||||||
|
|
||||||
ObjectRef object = variant.to<ObjectRef>();
|
|
||||||
if (object.isNull()) return DeserializationError::NoMemory;
|
|
||||||
|
|
||||||
// Check opening brace
|
// Check opening brace
|
||||||
if (!eat('{')) return DeserializationError::InvalidInput;
|
if (!eat('{')) return DeserializationError::InvalidInput;
|
||||||
|
|
||||||
@ -124,23 +118,24 @@ class JsonDeserializer {
|
|||||||
|
|
||||||
// Read each key value pair
|
// Read each key value pair
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
// Allocate slot in object
|
||||||
|
VariantSlot *slot = object.addSlot(_pool);
|
||||||
|
if (!slot) return DeserializationError::NoMemory;
|
||||||
|
|
||||||
// Parse key
|
// Parse key
|
||||||
StringType key;
|
StringType key;
|
||||||
err = parseKey(key);
|
err = parseKey(key);
|
||||||
if (err) return err;
|
if (err) return err;
|
||||||
|
slot->setOwnedKey(key);
|
||||||
|
|
||||||
// Skip spaces
|
// Skip spaces
|
||||||
err = skipSpacesAndComments();
|
err = skipSpacesAndComments();
|
||||||
if (err) return err; // Colon
|
if (err) return err; // Colon
|
||||||
if (!eat(':')) return DeserializationError::InvalidInput;
|
if (!eat(':')) return DeserializationError::InvalidInput;
|
||||||
|
|
||||||
// Allocate slot in object
|
|
||||||
VariantRef value = object.set(key);
|
|
||||||
if (value.isInvalid()) return DeserializationError::NoMemory;
|
|
||||||
|
|
||||||
// Parse value
|
// Parse value
|
||||||
_nestingLimit--;
|
_nestingLimit--;
|
||||||
err = parse(value);
|
err = parse(*slot->data());
|
||||||
_nestingLimit++;
|
_nestingLimit++;
|
||||||
if (err) return err;
|
if (err) return err;
|
||||||
|
|
||||||
@ -158,7 +153,7 @@ class JsonDeserializer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError parseValue(VariantRef variant) {
|
DeserializationError parseValue(VariantData &variant) {
|
||||||
if (isQuote(current())) {
|
if (isQuote(current())) {
|
||||||
return parseStringValue(variant);
|
return parseStringValue(variant);
|
||||||
} else {
|
} else {
|
||||||
@ -174,11 +169,11 @@ class JsonDeserializer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError parseStringValue(VariantRef variant) {
|
DeserializationError parseStringValue(VariantData &variant) {
|
||||||
StringType value;
|
StringType value;
|
||||||
DeserializationError err = parseQuotedString(value);
|
DeserializationError err = parseQuotedString(value);
|
||||||
if (err) return err;
|
if (err) return err;
|
||||||
variant.set(value);
|
variant.setOwnedString(value);
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,7 +203,7 @@ class JsonDeserializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
result = builder.complete();
|
result = builder.complete();
|
||||||
if (result.isNull()) return DeserializationError::NoMemory;
|
if (!result) return DeserializationError::NoMemory;
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,11 +224,11 @@ class JsonDeserializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
result = builder.complete();
|
result = builder.complete();
|
||||||
if (result.isNull()) return DeserializationError::NoMemory;
|
if (!result) return DeserializationError::NoMemory;
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError parseNumericValue(VariantRef result) {
|
DeserializationError parseNumericValue(VariantData &result) {
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
uint8_t n = 0;
|
uint8_t n = 0;
|
||||||
|
|
||||||
@ -246,13 +241,13 @@ class JsonDeserializer {
|
|||||||
buffer[n] = 0;
|
buffer[n] = 0;
|
||||||
|
|
||||||
if (isInteger(buffer)) {
|
if (isInteger(buffer)) {
|
||||||
result.set(parseInteger<Integer>(buffer));
|
result.setInteger(parseInteger<Integer>(buffer));
|
||||||
} else if (isFloat(buffer)) {
|
} else if (isFloat(buffer)) {
|
||||||
result.set(parseFloat<Float>(buffer));
|
result.setFloat(parseFloat<Float>(buffer));
|
||||||
} else if (!strcmp(buffer, "true")) {
|
} else if (!strcmp(buffer, "true")) {
|
||||||
result.set(true);
|
result.setBoolean(true);
|
||||||
} else if (!strcmp(buffer, "false")) {
|
} else if (!strcmp(buffer, "false")) {
|
||||||
result.set(false);
|
result.setBoolean(false);
|
||||||
} else if (!strcmp(buffer, "null")) {
|
} else if (!strcmp(buffer, "null")) {
|
||||||
// already null
|
// already null
|
||||||
} else {
|
} else {
|
||||||
@ -333,7 +328,7 @@ class JsonDeserializer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryPool *_memoryPool;
|
MemoryPool *_pool;
|
||||||
TReader _reader;
|
TReader _reader;
|
||||||
TStringStorage _stringStorage;
|
TStringStorage _stringStorage;
|
||||||
uint8_t _nestingLimit;
|
uint8_t _nestingLimit;
|
||||||
|
@ -20,15 +20,16 @@ class JsonSerializer {
|
|||||||
_writer.writeFloat(value);
|
_writer.writeFloat(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void visitArray(ArrayConstRef array) {
|
void visitArray(const CollectionData &array) {
|
||||||
_writer.beginArray();
|
_writer.beginArray();
|
||||||
|
|
||||||
ArrayConstRef::iterator it = array.begin();
|
VariantSlot *slot = array.head();
|
||||||
while (it != array.end()) {
|
|
||||||
it->accept(*this);
|
|
||||||
|
|
||||||
++it;
|
while (slot != 0) {
|
||||||
if (it == array.end()) break;
|
slot->data()->accept(*this);
|
||||||
|
|
||||||
|
slot = slot->next();
|
||||||
|
if (slot == 0) break;
|
||||||
|
|
||||||
_writer.writeComma();
|
_writer.writeComma();
|
||||||
}
|
}
|
||||||
@ -36,17 +37,18 @@ class JsonSerializer {
|
|||||||
_writer.endArray();
|
_writer.endArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
void visitObject(ObjectConstRef object) {
|
void visitObject(const CollectionData &object) {
|
||||||
_writer.beginObject();
|
_writer.beginObject();
|
||||||
|
|
||||||
ObjectConstRef::iterator it = object.begin();
|
VariantSlot *slot = object.head();
|
||||||
while (it != object.end()) {
|
|
||||||
_writer.writeString(it->key());
|
|
||||||
_writer.writeColon();
|
|
||||||
it->value().accept(*this);
|
|
||||||
|
|
||||||
++it;
|
while (slot != 0) {
|
||||||
if (it == object.end()) break;
|
_writer.writeString(slot->key());
|
||||||
|
_writer.writeColon();
|
||||||
|
slot->data()->accept(*this);
|
||||||
|
|
||||||
|
slot = slot->next();
|
||||||
|
if (slot == 0) break;
|
||||||
|
|
||||||
_writer.writeComma();
|
_writer.writeComma();
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
#include "../Polyfills/assert.hpp"
|
#include "../Polyfills/assert.hpp"
|
||||||
#include "../Polyfills/mpl/max.hpp"
|
#include "../Polyfills/mpl/max.hpp"
|
||||||
#include "../Strings/StringInMemoryPool.hpp"
|
|
||||||
#include "../Variant/VariantSlot.hpp"
|
#include "../Variant/VariantSlot.hpp"
|
||||||
#include "Alignment.hpp"
|
#include "Alignment.hpp"
|
||||||
#include "MemoryPool.hpp"
|
#include "MemoryPool.hpp"
|
||||||
|
@ -4,15 +4,12 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../Strings/StringInMemoryPool.hpp"
|
|
||||||
#include "MemoryPool.hpp"
|
#include "MemoryPool.hpp"
|
||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
class StringBuilder {
|
class StringBuilder {
|
||||||
public:
|
public:
|
||||||
typedef StringInMemoryPool StringType;
|
|
||||||
|
|
||||||
explicit StringBuilder(MemoryPool* parent) : _parent(parent), _size(0) {
|
explicit StringBuilder(MemoryPool* parent) : _parent(parent), _size(0) {
|
||||||
_slot = _parent->allocExpandableString();
|
_slot = _parent->allocExpandableString();
|
||||||
}
|
}
|
||||||
@ -36,7 +33,7 @@ class StringBuilder {
|
|||||||
_slot.value[_size++] = c;
|
_slot.value[_size++] = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringType complete() {
|
char* complete() {
|
||||||
append('\0');
|
append('\0');
|
||||||
if (_slot.value) {
|
if (_slot.value) {
|
||||||
_parent->freezeString(_slot, _size);
|
_parent->freezeString(_slot, _size);
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
#include "../Deserialization/deserialize.hpp"
|
#include "../Deserialization/deserialize.hpp"
|
||||||
#include "../Memory/MemoryPool.hpp"
|
#include "../Memory/MemoryPool.hpp"
|
||||||
#include "../Polyfills/type_traits.hpp"
|
#include "../Polyfills/type_traits.hpp"
|
||||||
#include "../Variant/VariantRef.hpp"
|
#include "../Variant/VariantData.hpp"
|
||||||
#include "endianess.hpp"
|
#include "endianess.hpp"
|
||||||
#include "ieee754.hpp"
|
#include "ieee754.hpp"
|
||||||
|
|
||||||
@ -17,27 +17,28 @@ template <typename TReader, typename TStringStorage>
|
|||||||
class MsgPackDeserializer {
|
class MsgPackDeserializer {
|
||||||
typedef typename remove_reference<TStringStorage>::type::StringBuilder
|
typedef typename remove_reference<TStringStorage>::type::StringBuilder
|
||||||
StringBuilder;
|
StringBuilder;
|
||||||
typedef typename StringBuilder::StringType StringType;
|
typedef const char *StringType;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MsgPackDeserializer(MemoryPool &memoryPool, TReader reader,
|
MsgPackDeserializer(MemoryPool &pool, TReader reader,
|
||||||
TStringStorage stringStorage, uint8_t nestingLimit)
|
TStringStorage stringStorage, uint8_t nestingLimit)
|
||||||
: _memoryPool(&memoryPool),
|
: _pool(&pool),
|
||||||
_reader(reader),
|
_reader(reader),
|
||||||
_stringStorage(stringStorage),
|
_stringStorage(stringStorage),
|
||||||
_nestingLimit(nestingLimit) {}
|
_nestingLimit(nestingLimit) {}
|
||||||
|
|
||||||
DeserializationError parse(VariantRef variant) {
|
DeserializationError parse(VariantData &variant) {
|
||||||
uint8_t code;
|
uint8_t code;
|
||||||
if (!readByte(code)) return DeserializationError::IncompleteInput;
|
if (!readByte(code)) return DeserializationError::IncompleteInput;
|
||||||
|
|
||||||
if ((code & 0x80) == 0) {
|
if ((code & 0x80) == 0) {
|
||||||
variant.set(code);
|
variant.setUnsignedInteger(code);
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((code & 0xe0) == 0xe0) {
|
if ((code & 0xe0) == 0xe0) {
|
||||||
variant.set(static_cast<int8_t>(code));
|
// TODO: add setNegativeInteger()
|
||||||
|
variant.setSignedInteger(static_cast<int8_t>(code));
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,9 +46,13 @@ class MsgPackDeserializer {
|
|||||||
return readString(variant, code & 0x1f);
|
return readString(variant, code & 0x1f);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((code & 0xf0) == 0x90) return readArray(variant, code & 0x0F);
|
if ((code & 0xf0) == 0x90) {
|
||||||
|
return readArray(variant.toArray(), code & 0x0F);
|
||||||
|
}
|
||||||
|
|
||||||
if ((code & 0xf0) == 0x80) return readObject(variant, code & 0x0F);
|
if ((code & 0xf0) == 0x80) {
|
||||||
|
return readObject(variant.toObject(), code & 0x0F);
|
||||||
|
}
|
||||||
|
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case 0xc0:
|
case 0xc0:
|
||||||
@ -55,11 +60,11 @@ class MsgPackDeserializer {
|
|||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
|
|
||||||
case 0xc2:
|
case 0xc2:
|
||||||
variant.set(false);
|
variant.setBoolean(false);
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
|
|
||||||
case 0xc3:
|
case 0xc3:
|
||||||
variant.set(true);
|
variant.setBoolean(true);
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
|
|
||||||
case 0xcc:
|
case 0xcc:
|
||||||
@ -112,16 +117,16 @@ class MsgPackDeserializer {
|
|||||||
return readString<uint32_t>(variant);
|
return readString<uint32_t>(variant);
|
||||||
|
|
||||||
case 0xdc:
|
case 0xdc:
|
||||||
return readArray<uint16_t>(variant);
|
return readArray<uint16_t>(variant.toArray());
|
||||||
|
|
||||||
case 0xdd:
|
case 0xdd:
|
||||||
return readArray<uint32_t>(variant);
|
return readArray<uint32_t>(variant.toArray());
|
||||||
|
|
||||||
case 0xde:
|
case 0xde:
|
||||||
return readObject<uint16_t>(variant);
|
return readObject<uint16_t>(variant.toObject());
|
||||||
|
|
||||||
case 0xdf:
|
case 0xdf:
|
||||||
return readObject<uint32_t>(variant);
|
return readObject<uint32_t>(variant.toObject());
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return DeserializationError::NotSupported;
|
return DeserializationError::NotSupported;
|
||||||
@ -174,48 +179,48 @@ class MsgPackDeserializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
DeserializationError readInteger(VariantRef variant) {
|
DeserializationError readInteger(VariantData &variant) {
|
||||||
T value;
|
T value;
|
||||||
if (!readInteger(value)) return DeserializationError::IncompleteInput;
|
if (!readInteger(value)) return DeserializationError::IncompleteInput;
|
||||||
variant.set(value);
|
variant.setInteger(value);
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename enable_if<sizeof(T) == 4, DeserializationError>::type readFloat(
|
typename enable_if<sizeof(T) == 4, DeserializationError>::type readFloat(
|
||||||
VariantRef variant) {
|
VariantData &variant) {
|
||||||
T value;
|
T value;
|
||||||
if (!readBytes(value)) return DeserializationError::IncompleteInput;
|
if (!readBytes(value)) return DeserializationError::IncompleteInput;
|
||||||
fixEndianess(value);
|
fixEndianess(value);
|
||||||
variant.set(value);
|
variant.setFloat(value);
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename enable_if<sizeof(T) == 8, DeserializationError>::type readDouble(
|
typename enable_if<sizeof(T) == 8, DeserializationError>::type readDouble(
|
||||||
VariantRef variant) {
|
VariantData &variant) {
|
||||||
T value;
|
T value;
|
||||||
if (!readBytes(value)) return DeserializationError::IncompleteInput;
|
if (!readBytes(value)) return DeserializationError::IncompleteInput;
|
||||||
fixEndianess(value);
|
fixEndianess(value);
|
||||||
variant.set(value);
|
variant.setFloat(value);
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename enable_if<sizeof(T) == 4, DeserializationError>::type readDouble(
|
typename enable_if<sizeof(T) == 4, DeserializationError>::type readDouble(
|
||||||
VariantRef variant) {
|
VariantData &variant) {
|
||||||
uint8_t i[8]; // input is 8 bytes
|
uint8_t i[8]; // input is 8 bytes
|
||||||
T value; // output is 4 bytes
|
T value; // output is 4 bytes
|
||||||
uint8_t *o = reinterpret_cast<uint8_t *>(&value);
|
uint8_t *o = reinterpret_cast<uint8_t *>(&value);
|
||||||
if (!readBytes(i, 8)) return DeserializationError::IncompleteInput;
|
if (!readBytes(i, 8)) return DeserializationError::IncompleteInput;
|
||||||
doubleToFloat(i, o);
|
doubleToFloat(i, o);
|
||||||
fixEndianess(value);
|
fixEndianess(value);
|
||||||
variant.set(value);
|
variant.setFloat(value);
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
DeserializationError readString(VariantRef variant) {
|
DeserializationError readString(VariantData &variant) {
|
||||||
T size;
|
T size;
|
||||||
if (!readInteger(size)) return DeserializationError::IncompleteInput;
|
if (!readInteger(size)) return DeserializationError::IncompleteInput;
|
||||||
return readString(variant, size);
|
return readString(variant, size);
|
||||||
@ -228,46 +233,40 @@ class MsgPackDeserializer {
|
|||||||
return readString(str, size);
|
return readString(str, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError readString(VariantRef variant, size_t n) {
|
DeserializationError readString(VariantData &variant, size_t n) {
|
||||||
StringType s;
|
StringType s;
|
||||||
DeserializationError err = readString(s, n);
|
DeserializationError err = readString(s, n);
|
||||||
if (!err) variant.set(s);
|
if (!err) variant.setOwnedString(s);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError readString(StringType &s, size_t n) {
|
DeserializationError readString(StringType &result, size_t n) {
|
||||||
StringBuilder builder = _stringStorage.startString();
|
StringBuilder builder = _stringStorage.startString();
|
||||||
for (; n; --n) {
|
for (; n; --n) {
|
||||||
uint8_t c;
|
uint8_t c;
|
||||||
if (!readBytes(c)) return DeserializationError::IncompleteInput;
|
if (!readBytes(c)) return DeserializationError::IncompleteInput;
|
||||||
builder.append(static_cast<char>(c));
|
builder.append(static_cast<char>(c));
|
||||||
}
|
}
|
||||||
s = builder.complete();
|
result = builder.complete();
|
||||||
if (s.isNull()) return DeserializationError::NoMemory;
|
if (!result) return DeserializationError::NoMemory;
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TSize>
|
template <typename TSize>
|
||||||
DeserializationError readArray(VariantRef variant) {
|
DeserializationError readArray(CollectionData &array) {
|
||||||
TSize size;
|
TSize size;
|
||||||
if (!readInteger(size)) return DeserializationError::IncompleteInput;
|
if (!readInteger(size)) return DeserializationError::IncompleteInput;
|
||||||
return readArray(variant, size);
|
return readArray(array, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError readArray(VariantRef variant, size_t n) {
|
DeserializationError readArray(CollectionData &array, size_t n) {
|
||||||
ArrayRef array = variant.to<ArrayRef>();
|
|
||||||
if (array.isNull()) return DeserializationError::NoMemory;
|
|
||||||
return readArray(array, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
DeserializationError readArray(ArrayRef array, size_t n) {
|
|
||||||
if (_nestingLimit == 0) return DeserializationError::TooDeep;
|
if (_nestingLimit == 0) return DeserializationError::TooDeep;
|
||||||
--_nestingLimit;
|
--_nestingLimit;
|
||||||
for (; n; --n) {
|
for (; n; --n) {
|
||||||
VariantRef value = array.add();
|
VariantData *value = array.add(_pool);
|
||||||
if (value.isInvalid()) return DeserializationError::NoMemory;
|
if (!value) return DeserializationError::NoMemory;
|
||||||
|
|
||||||
DeserializationError err = parse(value);
|
DeserializationError err = parse(*value);
|
||||||
if (err) return err;
|
if (err) return err;
|
||||||
}
|
}
|
||||||
++_nestingLimit;
|
++_nestingLimit;
|
||||||
@ -275,31 +274,25 @@ class MsgPackDeserializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename TSize>
|
template <typename TSize>
|
||||||
DeserializationError readObject(VariantRef variant) {
|
DeserializationError readObject(CollectionData &object) {
|
||||||
TSize size;
|
TSize size;
|
||||||
if (!readInteger(size)) return DeserializationError::IncompleteInput;
|
if (!readInteger(size)) return DeserializationError::IncompleteInput;
|
||||||
return readObject(variant, size);
|
return readObject(object, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError readObject(VariantRef variant, size_t n) {
|
DeserializationError readObject(CollectionData &object, size_t n) {
|
||||||
ObjectRef object = variant.to<ObjectRef>();
|
|
||||||
if (object.isNull()) return DeserializationError::NoMemory;
|
|
||||||
|
|
||||||
return readObject(object, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
DeserializationError readObject(ObjectRef object, size_t n) {
|
|
||||||
if (_nestingLimit == 0) return DeserializationError::TooDeep;
|
if (_nestingLimit == 0) return DeserializationError::TooDeep;
|
||||||
--_nestingLimit;
|
--_nestingLimit;
|
||||||
for (; n; --n) {
|
for (; n; --n) {
|
||||||
|
VariantSlot *slot = object.addSlot(_pool);
|
||||||
|
if (!slot) return DeserializationError::NoMemory;
|
||||||
|
|
||||||
StringType key;
|
StringType key;
|
||||||
DeserializationError err = parseKey(key);
|
DeserializationError err = parseKey(key);
|
||||||
if (err) return err;
|
if (err) return err;
|
||||||
|
slot->setOwnedKey(key);
|
||||||
|
|
||||||
VariantRef value = object.set(key);
|
err = parse(*slot->data());
|
||||||
if (value.isInvalid()) return DeserializationError::NoMemory;
|
|
||||||
|
|
||||||
err = parse(value);
|
|
||||||
if (err) return err;
|
if (err) return err;
|
||||||
}
|
}
|
||||||
++_nestingLimit;
|
++_nestingLimit;
|
||||||
@ -327,7 +320,7 @@ class MsgPackDeserializer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryPool *_memoryPool;
|
MemoryPool *_pool;
|
||||||
TReader _reader;
|
TReader _reader;
|
||||||
TStringStorage _stringStorage;
|
TStringStorage _stringStorage;
|
||||||
uint8_t _nestingLimit;
|
uint8_t _nestingLimit;
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
#include "../Polyfills/type_traits.hpp"
|
#include "../Polyfills/type_traits.hpp"
|
||||||
#include "../Serialization/measure.hpp"
|
#include "../Serialization/measure.hpp"
|
||||||
#include "../Serialization/serialize.hpp"
|
#include "../Serialization/serialize.hpp"
|
||||||
#include "../Variant/VariantRef.hpp"
|
#include "../Variant/VariantData.hpp"
|
||||||
#include "endianess.hpp"
|
#include "endianess.hpp"
|
||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
@ -35,7 +35,7 @@ class MsgPackSerializer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void visitArray(ArrayConstRef array) {
|
void visitArray(const CollectionData& array) {
|
||||||
size_t n = array.size();
|
size_t n = array.size();
|
||||||
if (n < 0x10) {
|
if (n < 0x10) {
|
||||||
writeByte(uint8_t(0x90 + array.size()));
|
writeByte(uint8_t(0x90 + array.size()));
|
||||||
@ -46,12 +46,12 @@ class MsgPackSerializer {
|
|||||||
writeByte(0xDD);
|
writeByte(0xDD);
|
||||||
writeInteger(uint32_t(n));
|
writeInteger(uint32_t(n));
|
||||||
}
|
}
|
||||||
for (ArrayConstRef::iterator it = array.begin(); it != array.end(); ++it) {
|
for (VariantSlot* slot = array.head(); slot; slot = slot->next()) {
|
||||||
it->accept(*this);
|
slot->data()->accept(*this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void visitObject(ObjectConstRef object) {
|
void visitObject(const CollectionData& object) {
|
||||||
size_t n = object.size();
|
size_t n = object.size();
|
||||||
if (n < 0x10) {
|
if (n < 0x10) {
|
||||||
writeByte(uint8_t(0x80 + n));
|
writeByte(uint8_t(0x80 + n));
|
||||||
@ -62,10 +62,9 @@ class MsgPackSerializer {
|
|||||||
writeByte(0xDF);
|
writeByte(0xDF);
|
||||||
writeInteger(uint32_t(n));
|
writeInteger(uint32_t(n));
|
||||||
}
|
}
|
||||||
for (ObjectConstRef::iterator it = object.begin(); it != object.end();
|
for (VariantSlot* slot = object.head(); slot; slot = slot->next()) {
|
||||||
++it) {
|
visitString(slot->key());
|
||||||
visitString(it->key());
|
slot->data()->accept(*this);
|
||||||
it->value().accept(*this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ class Key {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const char* c_str() const {
|
const char* c_str() const {
|
||||||
return _slot ? slotGetKey(_slot) : 0;
|
return _slot ? _slot->key() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isNull() const {
|
bool isNull() const {
|
||||||
|
@ -4,116 +4,52 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../Memory/MemoryPool.hpp"
|
#include "../Collection/CollectionData.hpp"
|
||||||
#include "../Variant/SlotFunctions.hpp"
|
|
||||||
#include "../Variant/VariantData.hpp"
|
|
||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
|
template <typename Visitor>
|
||||||
|
void objectAccept(const CollectionData *obj, Visitor &visitor) {
|
||||||
|
if (obj)
|
||||||
|
visitor.visitObject(*obj);
|
||||||
|
else
|
||||||
|
visitor.visitNull();
|
||||||
|
}
|
||||||
|
|
||||||
template <typename TKey>
|
template <typename TKey>
|
||||||
inline VariantSlot* objectFindSlot(const ObjectData* obj, TKey key) {
|
inline bool objectContainsKey(const CollectionData *obj, TKey key) {
|
||||||
|
return obj && obj->containsKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool objectEquals(const CollectionData *lhs, const CollectionData *rhs) {
|
||||||
|
if (lhs == rhs) return true;
|
||||||
|
if (!lhs || !rhs) return false;
|
||||||
|
return lhs->equalsObject(*rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TKey>
|
||||||
|
inline VariantData *objectGet(const CollectionData *obj, TKey key) {
|
||||||
if (!obj) return 0;
|
if (!obj) return 0;
|
||||||
VariantSlot* slot = obj->head;
|
return obj->get(key);
|
||||||
while (slot) {
|
|
||||||
if (key.equals(slotGetKey(slot))) break;
|
|
||||||
slot = slot->getNext();
|
|
||||||
}
|
|
||||||
return slot;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TKey>
|
template <typename TKey>
|
||||||
inline bool objectContainsKey(const ObjectData* obj, const TKey& key) {
|
void objectRemove(CollectionData *obj, TKey key) {
|
||||||
return objectFindSlot(obj, key) != 0;
|
if (!obj) return;
|
||||||
|
obj->remove(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TKey>
|
template <typename TKey>
|
||||||
inline VariantData* objectAdd(ObjectData* obj, TKey key, MemoryPool* pool) {
|
inline VariantData *objectSet(CollectionData *obj, TKey key, MemoryPool *pool) {
|
||||||
VariantSlot* slot = pool->allocVariant();
|
|
||||||
if (!slot) return 0;
|
|
||||||
|
|
||||||
slot->init();
|
|
||||||
|
|
||||||
if (obj->tail) {
|
|
||||||
slot->attachTo(obj->tail);
|
|
||||||
obj->tail = slot;
|
|
||||||
} else {
|
|
||||||
obj->head = slot;
|
|
||||||
obj->tail = slot;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!slotSetKey(slot, key, pool)) return 0;
|
|
||||||
return slot->getData();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename TKey>
|
|
||||||
inline VariantData* objectSet(ObjectData* obj, TKey key, MemoryPool* pool) {
|
|
||||||
if (!obj) return 0;
|
if (!obj) return 0;
|
||||||
|
|
||||||
// ignore null key
|
// ignore null key
|
||||||
if (key.isNull()) return 0;
|
if (key.isNull()) return 0;
|
||||||
|
|
||||||
// search a matching key
|
// search a matching key
|
||||||
VariantSlot* slot = objectFindSlot(obj, key);
|
VariantData *var = obj->get(key);
|
||||||
if (slot) return slot->getData();
|
if (var) return var;
|
||||||
|
|
||||||
return objectAdd(obj, key, pool);
|
return obj->add(key, pool);
|
||||||
}
|
|
||||||
|
|
||||||
template <typename TKey>
|
|
||||||
inline VariantData* objectGet(const ObjectData* obj, TKey key) {
|
|
||||||
VariantSlot* slot = objectFindSlot(obj, key);
|
|
||||||
return slot ? slot->getData() : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void objectClear(ObjectData* obj) {
|
|
||||||
if (!obj) return;
|
|
||||||
obj->head = 0;
|
|
||||||
obj->tail = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void objectRemove(ObjectData* obj, VariantSlot* slot) {
|
|
||||||
if (!obj) return;
|
|
||||||
if (!slot) return;
|
|
||||||
VariantSlot* prev = slot->getPrev(obj->head);
|
|
||||||
VariantSlot* next = slot->getNext();
|
|
||||||
if (prev)
|
|
||||||
prev->setNext(next);
|
|
||||||
else
|
|
||||||
obj->head = next;
|
|
||||||
if (!next) obj->tail = prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline size_t objectSize(const ObjectData* obj) {
|
|
||||||
if (!obj) return 0;
|
|
||||||
return slotSize(obj->head);
|
|
||||||
}
|
|
||||||
|
|
||||||
// bool variantCopy(VariantData*, const VariantData*, MemoryPool*);
|
|
||||||
|
|
||||||
inline bool objectCopy(ObjectData* dst, const ObjectData* src,
|
|
||||||
MemoryPool* pool) {
|
|
||||||
if (!dst || !src) return false;
|
|
||||||
objectClear(dst);
|
|
||||||
for (VariantSlot* s = src->head; s; s = s->getNext()) {
|
|
||||||
VariantData* var;
|
|
||||||
if (s->ownsKey())
|
|
||||||
var = objectAdd(dst, ZeroTerminatedRamString(s->key()), pool);
|
|
||||||
else
|
|
||||||
var = objectAdd(dst, ZeroTerminatedRamStringConst(s->key()), pool);
|
|
||||||
if (!variantCopy(var, s->getData(), pool)) return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool objectEquals(const ObjectData* o1, const ObjectData* o2) {
|
|
||||||
if (o1 == o2) return true;
|
|
||||||
if (!o1 || !o2) return false;
|
|
||||||
|
|
||||||
for (VariantSlot* s = o1->head; s; s = s->getNext()) {
|
|
||||||
VariantData* v1 = s->getData();
|
|
||||||
VariantData* v2 = objectGet(o2, makeString(slotGetKey(s)));
|
|
||||||
if (!variantEquals(v1, v2)) return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
|
@ -11,8 +11,7 @@ namespace ARDUINOJSON_NAMESPACE {
|
|||||||
|
|
||||||
class PairPtr {
|
class PairPtr {
|
||||||
public:
|
public:
|
||||||
PairPtr(MemoryPool *memoryPool, VariantSlot *slot)
|
PairPtr(MemoryPool *pool, VariantSlot *slot) : _pair(pool, slot) {}
|
||||||
: _pair(memoryPool, slot) {}
|
|
||||||
|
|
||||||
const Pair *operator->() const {
|
const Pair *operator->() const {
|
||||||
return &_pair;
|
return &_pair;
|
||||||
@ -30,14 +29,14 @@ class ObjectIterator {
|
|||||||
public:
|
public:
|
||||||
ObjectIterator() : _slot(0) {}
|
ObjectIterator() : _slot(0) {}
|
||||||
|
|
||||||
explicit ObjectIterator(MemoryPool *memoryPool, VariantSlot *slot)
|
explicit ObjectIterator(MemoryPool *pool, VariantSlot *slot)
|
||||||
: _memoryPool(memoryPool), _slot(slot) {}
|
: _pool(pool), _slot(slot) {}
|
||||||
|
|
||||||
Pair operator*() const {
|
Pair operator*() const {
|
||||||
return Pair(_memoryPool, _slot);
|
return Pair(_pool, _slot);
|
||||||
}
|
}
|
||||||
PairPtr operator->() {
|
PairPtr operator->() {
|
||||||
return PairPtr(_memoryPool, _slot);
|
return PairPtr(_pool, _slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const ObjectIterator &other) const {
|
bool operator==(const ObjectIterator &other) const {
|
||||||
@ -49,12 +48,12 @@ class ObjectIterator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ObjectIterator &operator++() {
|
ObjectIterator &operator++() {
|
||||||
_slot = _slot->getNext();
|
_slot = _slot->next();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectIterator &operator+=(size_t distance) {
|
ObjectIterator &operator+=(size_t distance) {
|
||||||
_slot = _slot->getNext(distance);
|
_slot = _slot->next(distance);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +62,7 @@ class ObjectIterator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MemoryPool *_memoryPool;
|
MemoryPool *_pool;
|
||||||
VariantSlot *_slot;
|
VariantSlot *_slot;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -105,12 +104,12 @@ class ObjectConstIterator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ObjectConstIterator &operator++() {
|
ObjectConstIterator &operator++() {
|
||||||
_slot = _slot->getNext();
|
_slot = _slot->next();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectConstIterator &operator+=(size_t distance) {
|
ObjectConstIterator &operator+=(size_t distance) {
|
||||||
_slot = _slot->getNext(distance);
|
_slot = _slot->next(distance);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,11 @@ namespace ARDUINOJSON_NAMESPACE {
|
|||||||
template <typename TData>
|
template <typename TData>
|
||||||
class ObjectRefBase {
|
class ObjectRefBase {
|
||||||
public:
|
public:
|
||||||
|
template <typename Visitor>
|
||||||
|
FORCE_INLINE void accept(Visitor& visitor) const {
|
||||||
|
objectAccept(_data, visitor);
|
||||||
|
}
|
||||||
|
|
||||||
// Tells weither the specified key is present and associated with a value.
|
// Tells weither the specified key is present and associated with a value.
|
||||||
//
|
//
|
||||||
// bool containsKey(TKey);
|
// bool containsKey(TKey);
|
||||||
@ -38,7 +43,7 @@ class ObjectRefBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE size_t size() const {
|
FORCE_INLINE size_t size() const {
|
||||||
return objectSize(_data);
|
return _data ? _data->size() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -46,28 +51,20 @@ class ObjectRefBase {
|
|||||||
TData* _data;
|
TData* _data;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ObjectConstRef : public ObjectRefBase<const ObjectData>,
|
class ObjectConstRef : public ObjectRefBase<const CollectionData>,
|
||||||
public Visitable {
|
public Visitable {
|
||||||
friend class ObjectRef;
|
friend class ObjectRef;
|
||||||
typedef ObjectRefBase<const ObjectData> base_type;
|
typedef ObjectRefBase<const CollectionData> base_type;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef ObjectConstIterator iterator;
|
typedef ObjectConstIterator iterator;
|
||||||
|
|
||||||
ObjectConstRef() : base_type(0) {}
|
ObjectConstRef() : base_type(0) {}
|
||||||
ObjectConstRef(const ObjectData* data) : base_type(data) {}
|
ObjectConstRef(const CollectionData* data) : base_type(data) {}
|
||||||
|
|
||||||
template <typename Visitor>
|
|
||||||
FORCE_INLINE void accept(Visitor& visitor) const {
|
|
||||||
if (_data)
|
|
||||||
visitor.visitObject(*this);
|
|
||||||
else
|
|
||||||
visitor.visitNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
FORCE_INLINE iterator begin() const {
|
FORCE_INLINE iterator begin() const {
|
||||||
if (!_data) return iterator();
|
if (!_data) return iterator();
|
||||||
return iterator(_data->head);
|
return iterator(_data->head());
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE iterator end() const {
|
FORCE_INLINE iterator end() const {
|
||||||
@ -122,18 +119,18 @@ class ObjectConstRef : public ObjectRefBase<const ObjectData>,
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ObjectRef : public ObjectRefBase<ObjectData>, public Visitable {
|
class ObjectRef : public ObjectRefBase<CollectionData>, public Visitable {
|
||||||
typedef ObjectRefBase<ObjectData> base_type;
|
typedef ObjectRefBase<CollectionData> base_type;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef ObjectIterator iterator;
|
typedef ObjectIterator iterator;
|
||||||
|
|
||||||
FORCE_INLINE ObjectRef() : base_type(0), _memoryPool(0) {}
|
FORCE_INLINE ObjectRef() : base_type(0), _pool(0) {}
|
||||||
FORCE_INLINE ObjectRef(MemoryPool* buf, ObjectData* data)
|
FORCE_INLINE ObjectRef(MemoryPool* buf, CollectionData* data)
|
||||||
: base_type(data), _memoryPool(buf) {}
|
: base_type(data), _pool(buf) {}
|
||||||
|
|
||||||
operator VariantRef() const {
|
operator VariantRef() const {
|
||||||
return VariantRef(_memoryPool, getVariantData(_data));
|
return VariantRef(_pool, reinterpret_cast<VariantData*>(_data));
|
||||||
}
|
}
|
||||||
|
|
||||||
operator ObjectConstRef() const {
|
operator ObjectConstRef() const {
|
||||||
@ -142,7 +139,7 @@ class ObjectRef : public ObjectRefBase<ObjectData>, public Visitable {
|
|||||||
|
|
||||||
FORCE_INLINE iterator begin() const {
|
FORCE_INLINE iterator begin() const {
|
||||||
if (!_data) return iterator();
|
if (!_data) return iterator();
|
||||||
return iterator(_memoryPool, _data->head);
|
return iterator(_pool, _data->head());
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE iterator end() const {
|
FORCE_INLINE iterator end() const {
|
||||||
@ -150,11 +147,13 @@ class ObjectRef : public ObjectRefBase<ObjectData>, public Visitable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void clear() const {
|
void clear() const {
|
||||||
objectClear(_data);
|
if (!_data) return;
|
||||||
|
_data->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE bool copyFrom(ObjectConstRef src) {
|
FORCE_INLINE bool copyFrom(ObjectConstRef src) {
|
||||||
return objectCopy(_data, src._data, _memoryPool);
|
if (!_data || !src._data) return false;
|
||||||
|
return _data->copyFrom(*src._data, _pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates and adds a ArrayRef.
|
// Creates and adds a ArrayRef.
|
||||||
@ -225,7 +224,8 @@ class ObjectRef : public ObjectRefBase<ObjectData>, public Visitable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE void remove(iterator it) const {
|
FORCE_INLINE void remove(iterator it) const {
|
||||||
objectRemove(_data, it.internal());
|
if (!_data) return;
|
||||||
|
_data->remove(it.internal());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes the specified key and the associated value.
|
// Removes the specified key and the associated value.
|
||||||
@ -234,14 +234,14 @@ class ObjectRef : public ObjectRefBase<ObjectData>, public Visitable {
|
|||||||
// TKey = const std::string&, const String&
|
// TKey = const std::string&, const String&
|
||||||
template <typename TKey>
|
template <typename TKey>
|
||||||
FORCE_INLINE void remove(const TKey& key) const {
|
FORCE_INLINE void remove(const TKey& key) const {
|
||||||
remove_impl(makeString(key));
|
objectRemove(_data, makeString(key));
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
// void remove(TKey);
|
// void remove(TKey);
|
||||||
// TKey = char*, const char*, char[], const char[], const FlashStringHelper*
|
// TKey = char*, const char*, char[], const char[], const FlashStringHelper*
|
||||||
template <typename TKey>
|
template <typename TKey>
|
||||||
FORCE_INLINE void remove(TKey* key) const {
|
FORCE_INLINE void remove(TKey* key) const {
|
||||||
remove_impl(makeString(key));
|
objectRemove(_data, makeString(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TKey>
|
template <typename TKey>
|
||||||
@ -254,35 +254,17 @@ class ObjectRef : public ObjectRefBase<ObjectData>, public Visitable {
|
|||||||
return set_impl(makeString(key));
|
return set_impl(makeString(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE VariantRef set(StringInMemoryPool key) const {
|
|
||||||
return set_impl(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
FORCE_INLINE VariantRef set(ZeroTerminatedRamStringConst key) const {
|
|
||||||
return set_impl(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Visitor>
|
|
||||||
FORCE_INLINE void accept(Visitor& visitor) const {
|
|
||||||
ObjectConstRef(_data).accept(visitor);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename TStringRef>
|
template <typename TKey>
|
||||||
FORCE_INLINE VariantRef get_impl(TStringRef key) const {
|
FORCE_INLINE VariantRef get_impl(TKey key) const {
|
||||||
return VariantRef(_memoryPool, objectGet(_data, key));
|
return VariantRef(_pool, objectGet(_data, key));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TKey>
|
template <typename TKey>
|
||||||
FORCE_INLINE VariantRef set_impl(TKey key) const {
|
FORCE_INLINE VariantRef set_impl(TKey key) const {
|
||||||
return VariantRef(_memoryPool, objectSet(_data, key, _memoryPool));
|
return VariantRef(_pool, objectSet(_data, key, _pool));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TStringRef>
|
MemoryPool* _pool;
|
||||||
FORCE_INLINE void remove_impl(TStringRef key) const {
|
|
||||||
objectRemove(_data, objectFindSlot(_data, key));
|
|
||||||
}
|
|
||||||
|
|
||||||
MemoryPool* _memoryPool;
|
|
||||||
};
|
};
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
|
@ -8,12 +8,12 @@
|
|||||||
#include "Key.hpp"
|
#include "Key.hpp"
|
||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
// A key value pair for ObjectData.
|
// A key value pair for CollectionData.
|
||||||
class Pair {
|
class Pair {
|
||||||
public:
|
public:
|
||||||
Pair(MemoryPool* memoryPool, VariantSlot* slot) : _key(slot) {
|
Pair(MemoryPool* pool, VariantSlot* slot) : _key(slot) {
|
||||||
if (slot) {
|
if (slot) {
|
||||||
_value = VariantRef(memoryPool, slot->getData());
|
_value = VariantRef(pool, slot->data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,7 +34,7 @@ class PairConst {
|
|||||||
public:
|
public:
|
||||||
PairConst(const VariantSlot* slot) : _key(slot) {
|
PairConst(const VariantSlot* slot) : _key(slot) {
|
||||||
if (slot) {
|
if (slot) {
|
||||||
_value = VariantConstRef(slot->getData());
|
_value = VariantConstRef(slot->data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h> // size_t
|
||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -13,13 +13,13 @@ class StringCopier {
|
|||||||
public:
|
public:
|
||||||
typedef ARDUINOJSON_NAMESPACE::StringBuilder StringBuilder;
|
typedef ARDUINOJSON_NAMESPACE::StringBuilder StringBuilder;
|
||||||
|
|
||||||
StringCopier(MemoryPool* memoryPool) : _memoryPool(memoryPool) {}
|
StringCopier(MemoryPool* pool) : _pool(pool) {}
|
||||||
|
|
||||||
StringBuilder startString() {
|
StringBuilder startString() {
|
||||||
return StringBuilder(_memoryPool);
|
return StringBuilder(_pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MemoryPool* _memoryPool;
|
MemoryPool* _pool;
|
||||||
};
|
};
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
|
@ -10,17 +10,15 @@ class StringMover {
|
|||||||
public:
|
public:
|
||||||
class StringBuilder {
|
class StringBuilder {
|
||||||
public:
|
public:
|
||||||
typedef ZeroTerminatedRamStringConst StringType;
|
|
||||||
|
|
||||||
StringBuilder(char** ptr) : _writePtr(ptr), _startPtr(*ptr) {}
|
StringBuilder(char** ptr) : _writePtr(ptr), _startPtr(*ptr) {}
|
||||||
|
|
||||||
void append(char c) {
|
void append(char c) {
|
||||||
*(*_writePtr)++ = char(c);
|
*(*_writePtr)++ = char(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
StringType complete() const {
|
char* complete() const {
|
||||||
*(*_writePtr)++ = 0;
|
*(*_writePtr)++ = 0;
|
||||||
return reinterpret_cast<const char*>(_startPtr);
|
return _startPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -12,10 +12,10 @@ class ArduinoString {
|
|||||||
public:
|
public:
|
||||||
ArduinoString(const ::String& str) : _str(&str) {}
|
ArduinoString(const ::String& str) : _str(&str) {}
|
||||||
|
|
||||||
char* save(MemoryPool* memoryPool) const {
|
char* save(MemoryPool* pool) const {
|
||||||
if (isNull()) return NULL;
|
if (isNull()) return NULL;
|
||||||
size_t n = _str->length() + 1;
|
size_t n = _str->length() + 1;
|
||||||
char* dup = memoryPool->allocFrozenString(n);
|
char* dup = pool->allocFrozenString(n);
|
||||||
if (dup) memcpy(dup, _str->c_str(), n);
|
if (dup) memcpy(dup, _str->c_str(), n);
|
||||||
return dup;
|
return dup;
|
||||||
}
|
}
|
||||||
|
@ -21,9 +21,9 @@ class FixedSizeFlashString {
|
|||||||
return !_str;
|
return !_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* save(MemoryPool* memoryPool) const {
|
char* save(MemoryPool* pool) const {
|
||||||
if (!_str) return NULL;
|
if (!_str) return NULL;
|
||||||
char* dup = memoryPool->allocFrozenString(_size);
|
char* dup = pool->allocFrozenString(_size);
|
||||||
if (!dup) memcpy_P(dup, (const char*)_str, _size);
|
if (!dup) memcpy_P(dup, (const char*)_str, _size);
|
||||||
return dup;
|
return dup;
|
||||||
}
|
}
|
||||||
|
@ -22,10 +22,9 @@ class FixedSizeRamString {
|
|||||||
return !_str;
|
return !_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TMemoryPool>
|
char* save(MemoryPool* pool) const {
|
||||||
char* save(TMemoryPool* memoryPool) const {
|
|
||||||
if (!_str) return NULL;
|
if (!_str) return NULL;
|
||||||
char* dup = memoryPool->allocFrozenString(_size);
|
char* dup = pool->allocFrozenString(_size);
|
||||||
if (dup) memcpy(dup, _str, _size);
|
if (dup) memcpy(dup, _str, _size);
|
||||||
return dup;
|
return dup;
|
||||||
}
|
}
|
||||||
|
@ -12,9 +12,9 @@ class StlString {
|
|||||||
public:
|
public:
|
||||||
StlString(const std::string& str) : _str(&str) {}
|
StlString(const std::string& str) : _str(&str) {}
|
||||||
|
|
||||||
char* save(MemoryPool* memoryPool) const {
|
char* save(MemoryPool* pool) const {
|
||||||
size_t n = _str->length() + 1;
|
size_t n = _str->length() + 1;
|
||||||
char* dup = memoryPool->allocFrozenString(n);
|
char* dup = pool->allocFrozenString(n);
|
||||||
if (dup) memcpy(dup, _str->c_str(), n);
|
if (dup) memcpy(dup, _str->c_str(), n);
|
||||||
return dup;
|
return dup;
|
||||||
}
|
}
|
||||||
|
@ -1,39 +0,0 @@
|
|||||||
// ArduinoJson - arduinojson.org
|
|
||||||
// Copyright Benoit Blanchon 2014-2018
|
|
||||||
// MIT License
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include "../Memory/MemoryPool.hpp"
|
|
||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
|
||||||
|
|
||||||
class StringInMemoryPool {
|
|
||||||
public:
|
|
||||||
StringInMemoryPool(char* s = 0) : _value(s) {}
|
|
||||||
|
|
||||||
bool equals(const char* expected) const {
|
|
||||||
if (!_value) return expected == 0;
|
|
||||||
const char* actual = _value;
|
|
||||||
if (actual == expected) return true;
|
|
||||||
return strcmp(actual, expected) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* save(void*) {
|
|
||||||
return _value;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isNull() const {
|
|
||||||
return !_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* c_str() const {
|
|
||||||
return _value;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
char* _value;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "../Memory/MemoryPool.hpp"
|
||||||
#include "../Polyfills/type_traits.hpp"
|
#include "../Polyfills/type_traits.hpp"
|
||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
@ -18,7 +19,6 @@ struct IsString<T&> : IsString<T> {};
|
|||||||
} // namespace ARDUINOJSON_NAMESPACE
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
|
|
||||||
#include "FixedSizeRamString.hpp"
|
#include "FixedSizeRamString.hpp"
|
||||||
#include "StringInMemoryPool.hpp"
|
|
||||||
#include "ZeroTerminatedRamString.hpp"
|
#include "ZeroTerminatedRamString.hpp"
|
||||||
#include "ZeroTerminatedRamStringConst.hpp"
|
#include "ZeroTerminatedRamStringConst.hpp"
|
||||||
|
|
||||||
|
@ -20,10 +20,10 @@ class ZeroTerminatedFlashString {
|
|||||||
return !_str;
|
return !_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* save(MemoryPool* memoryPool) const {
|
char* save(MemoryPool* pool) const {
|
||||||
if (!_str) return NULL;
|
if (!_str) return NULL;
|
||||||
size_t n = size() + 1; // copy the terminator
|
size_t n = size() + 1; // copy the terminator
|
||||||
char* dup = memoryPool->allocFrozenString(n);
|
char* dup = pool->allocFrozenString(n);
|
||||||
if (dup) memcpy_P(dup, reinterpret_cast<const char*>(_str), n);
|
if (dup) memcpy_P(dup, reinterpret_cast<const char*>(_str), n);
|
||||||
return dup;
|
return dup;
|
||||||
}
|
}
|
||||||
|
@ -13,11 +13,10 @@ class ZeroTerminatedRamString : public ZeroTerminatedRamStringConst {
|
|||||||
ZeroTerminatedRamString(const char* str)
|
ZeroTerminatedRamString(const char* str)
|
||||||
: ZeroTerminatedRamStringConst(str) {}
|
: ZeroTerminatedRamStringConst(str) {}
|
||||||
|
|
||||||
template <typename TMemoryPool>
|
char* save(MemoryPool* pool) const {
|
||||||
char* save(TMemoryPool* memoryPool) const {
|
|
||||||
if (!_str) return NULL;
|
if (!_str) return NULL;
|
||||||
size_t n = size() + 1;
|
size_t n = size() + 1;
|
||||||
char* dup = memoryPool->allocFrozenString(n);
|
char* dup = pool->allocFrozenString(n);
|
||||||
if (dup) memcpy(dup, _str, n);
|
if (dup) memcpy(dup, _str, n);
|
||||||
return dup;
|
return dup;
|
||||||
}
|
}
|
||||||
|
@ -13,32 +13,25 @@ namespace ARDUINOJSON_NAMESPACE {
|
|||||||
|
|
||||||
template <typename TKey>
|
template <typename TKey>
|
||||||
inline bool slotSetKey(VariantSlot* var, TKey key, MemoryPool* pool) {
|
inline bool slotSetKey(VariantSlot* var, TKey key, MemoryPool* pool) {
|
||||||
|
if (!var) return false;
|
||||||
char* dup = key.save(pool);
|
char* dup = key.save(pool);
|
||||||
if (!dup) return false;
|
if (!dup) return false;
|
||||||
var->setKey(dup, true);
|
var->setOwnedKey(dup);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool slotSetKey(VariantSlot* var, ZeroTerminatedRamStringConst key,
|
inline bool slotSetKey(VariantSlot* var, ZeroTerminatedRamStringConst key,
|
||||||
MemoryPool*) {
|
MemoryPool*) {
|
||||||
var->setKey(key.c_str(), false);
|
if (!var) return false;
|
||||||
|
var->setLinkedKey(key.c_str());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool slotSetKey(VariantSlot* var, StringInMemoryPool key, MemoryPool*) {
|
|
||||||
var->setKey(key.c_str(), true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const char* slotGetKey(const VariantSlot* var) {
|
|
||||||
return var->key();
|
|
||||||
}
|
|
||||||
|
|
||||||
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->getNext();
|
var = var->next();
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../Serialization/DynamicStringWriter.hpp"
|
#include "../Serialization/DynamicStringWriter.hpp"
|
||||||
#include "VariantFunctions.hpp"
|
|
||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
@ -55,19 +54,19 @@ struct VariantConstAs<ArrayRef> {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
inline typename enable_if<is_integral<T>::value, T>::type variantAs(
|
inline typename enable_if<is_integral<T>::value, T>::type variantAs(
|
||||||
const VariantData* _data) {
|
const VariantData* _data) {
|
||||||
return variantAsIntegral<T>(_data);
|
return _data != 0 ? _data->asIntegral<T>() : T(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline typename enable_if<is_same<T, bool>::value, T>::type variantAs(
|
inline typename enable_if<is_same<T, bool>::value, T>::type variantAs(
|
||||||
const VariantData* _data) {
|
const VariantData* _data) {
|
||||||
return variantAsBoolean(_data);
|
return _data != 0 ? _data->asBoolean() : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline typename enable_if<is_floating_point<T>::value, T>::type variantAs(
|
inline typename enable_if<is_floating_point<T>::value, T>::type variantAs(
|
||||||
const VariantData* _data) {
|
const VariantData* _data) {
|
||||||
return variantAsFloat<T>(_data);
|
return _data != 0 ? _data->asFloat<T>() : T(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -75,7 +74,7 @@ inline typename enable_if<is_same<T, const char*>::value ||
|
|||||||
is_same<T, char*>::value,
|
is_same<T, char*>::value,
|
||||||
const char*>::type
|
const char*>::type
|
||||||
variantAs(const VariantData* _data) {
|
variantAs(const VariantData* _data) {
|
||||||
return variantAsString(_data);
|
return _data != 0 ? _data->asString() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../Serialization/DynamicStringWriter.hpp"
|
#include "../Serialization/DynamicStringWriter.hpp"
|
||||||
#include "VariantFunctions.hpp"
|
|
||||||
#include "VariantRef.hpp"
|
#include "VariantRef.hpp"
|
||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
@ -19,7 +18,7 @@ variantAs(const VariantData* _data) {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
inline typename enable_if<IsWriteableString<T>::value, T>::type variantAs(
|
inline typename enable_if<IsWriteableString<T>::value, T>::type variantAs(
|
||||||
const VariantData* _data) {
|
const VariantData* _data) {
|
||||||
const char* cstr = variantAsString(_data);
|
const char* cstr = _data != 0 ? _data->asString() : 0;
|
||||||
if (cstr) return T(cstr);
|
if (cstr) return T(cstr);
|
||||||
T s;
|
T s;
|
||||||
serializeJson(VariantConstRef(_data), s);
|
serializeJson(VariantConstRef(_data), s);
|
||||||
|
46
src/ArduinoJson/Variant/VariantContent.hpp
Normal file
46
src/ArduinoJson/Variant/VariantContent.hpp
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// ArduinoJson - arduinojson.org
|
||||||
|
// Copyright Benoit Blanchon 2014-2018
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h> // size_t
|
||||||
|
|
||||||
|
#include "../Collection/CollectionData.hpp"
|
||||||
|
#include "../Numbers/Float.hpp"
|
||||||
|
#include "../Numbers/Integer.hpp"
|
||||||
|
|
||||||
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
|
enum {
|
||||||
|
VALUE_IS_NULL = 0,
|
||||||
|
VALUE_IS_LINKED_RAW,
|
||||||
|
VALUE_IS_OWNED_RAW,
|
||||||
|
VALUE_IS_LINKED_STRING,
|
||||||
|
VALUE_IS_OWNED_STRING,
|
||||||
|
VALUE_IS_BOOLEAN,
|
||||||
|
VALUE_IS_POSITIVE_INTEGER,
|
||||||
|
VALUE_IS_NEGATIVE_INTEGER,
|
||||||
|
VALUE_IS_ARRAY,
|
||||||
|
VALUE_IS_OBJECT,
|
||||||
|
VALUE_IS_FLOAT,
|
||||||
|
VALUE_MASK = 0x7F,
|
||||||
|
KEY_IS_OWNED = 0x80
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RawData {
|
||||||
|
const char *data;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
union VariantContent {
|
||||||
|
Float asFloat;
|
||||||
|
UInt asInteger;
|
||||||
|
CollectionData asCollection;
|
||||||
|
const char *asString;
|
||||||
|
struct {
|
||||||
|
const char *data;
|
||||||
|
size_t size;
|
||||||
|
} asRaw;
|
||||||
|
};
|
||||||
|
} // namespace ARDUINOJSON_NAMESPACE
|
@ -4,78 +4,285 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stddef.h> // ptrdiff_t, size_t
|
#include "../Misc/SerializedValue.hpp"
|
||||||
|
#include "VariantContent.hpp"
|
||||||
#include "../Numbers/Float.hpp"
|
|
||||||
#include "../Numbers/Integer.hpp"
|
|
||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
class VariantSlot;
|
class VariantData {
|
||||||
|
VariantContent _content; // must be first to allow cast from array to variant
|
||||||
|
uint8_t _flags;
|
||||||
|
|
||||||
enum VariantType {
|
public:
|
||||||
JSON_NULL,
|
// Must be a POD!
|
||||||
JSON_LINKED_RAW,
|
// - no constructor
|
||||||
JSON_OWNED_RAW,
|
// - no destructor
|
||||||
JSON_LINKED_STRING,
|
// - no virtual
|
||||||
JSON_OWNED_STRING,
|
// - no inheritance
|
||||||
JSON_BOOLEAN,
|
|
||||||
JSON_POSITIVE_INTEGER,
|
template <typename Visitor>
|
||||||
JSON_NEGATIVE_INTEGER,
|
void accept(Visitor &visitor) const {
|
||||||
JSON_ARRAY,
|
switch (type()) {
|
||||||
JSON_OBJECT,
|
case VALUE_IS_FLOAT:
|
||||||
JSON_FLOAT
|
return visitor.visitFloat(_content.asFloat);
|
||||||
|
|
||||||
|
case VALUE_IS_ARRAY:
|
||||||
|
return visitor.visitArray(_content.asCollection);
|
||||||
|
|
||||||
|
case VALUE_IS_OBJECT:
|
||||||
|
return visitor.visitObject(_content.asCollection);
|
||||||
|
|
||||||
|
case VALUE_IS_LINKED_STRING:
|
||||||
|
case VALUE_IS_OWNED_STRING:
|
||||||
|
return visitor.visitString(_content.asString);
|
||||||
|
|
||||||
|
case VALUE_IS_OWNED_RAW:
|
||||||
|
case VALUE_IS_LINKED_RAW:
|
||||||
|
return visitor.visitRawJson(_content.asRaw.data, _content.asRaw.size);
|
||||||
|
|
||||||
|
case VALUE_IS_NEGATIVE_INTEGER:
|
||||||
|
return visitor.visitNegativeInteger(_content.asInteger);
|
||||||
|
|
||||||
|
case VALUE_IS_POSITIVE_INTEGER:
|
||||||
|
return visitor.visitPositiveInteger(_content.asInteger);
|
||||||
|
|
||||||
|
case VALUE_IS_BOOLEAN:
|
||||||
|
return visitor.visitBoolean(_content.asInteger != 0);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return visitor.visitNull();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T asIntegral() const;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T asFloat() const;
|
||||||
|
|
||||||
|
const char *asString() const;
|
||||||
|
|
||||||
|
bool asBoolean() const {
|
||||||
|
return asIntegral<int>() != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
CollectionData *asArray() {
|
||||||
|
if (type() == VALUE_IS_ARRAY)
|
||||||
|
return &_content.asCollection;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CollectionData *asArray() const {
|
||||||
|
return const_cast<VariantData *>(this)->asArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
CollectionData *asObject() {
|
||||||
|
if (type() == VALUE_IS_OBJECT)
|
||||||
|
return &_content.asCollection;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CollectionData *asObject() const {
|
||||||
|
return const_cast<VariantData *>(this)->asObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool copyFrom(const VariantData &src, MemoryPool *pool) {
|
||||||
|
switch (src.type()) {
|
||||||
|
case VALUE_IS_ARRAY:
|
||||||
|
return toArray().copyFrom(src._content.asCollection, pool);
|
||||||
|
case VALUE_IS_OBJECT:
|
||||||
|
return toObject().copyFrom(src._content.asCollection, pool);
|
||||||
|
case VALUE_IS_OWNED_STRING:
|
||||||
|
return setOwnedString(ZeroTerminatedRamString(src._content.asString),
|
||||||
|
pool);
|
||||||
|
case VALUE_IS_OWNED_RAW:
|
||||||
|
return setOwnedRaw(
|
||||||
|
serialized(src._content.asRaw.data, src._content.asRaw.size), pool);
|
||||||
|
default:
|
||||||
|
setType(src.type());
|
||||||
|
_content = src._content;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool equals(const VariantData &other) const {
|
||||||
|
if (type() != other.type()) return false;
|
||||||
|
|
||||||
|
switch (type()) {
|
||||||
|
case VALUE_IS_LINKED_STRING:
|
||||||
|
case VALUE_IS_OWNED_STRING:
|
||||||
|
return !strcmp(_content.asString, other._content.asString);
|
||||||
|
|
||||||
|
case VALUE_IS_LINKED_RAW:
|
||||||
|
case VALUE_IS_OWNED_RAW:
|
||||||
|
return _content.asRaw.size == other._content.asRaw.size &&
|
||||||
|
!memcmp(_content.asRaw.data, other._content.asRaw.data,
|
||||||
|
_content.asRaw.size);
|
||||||
|
|
||||||
|
case VALUE_IS_BOOLEAN:
|
||||||
|
case VALUE_IS_POSITIVE_INTEGER:
|
||||||
|
case VALUE_IS_NEGATIVE_INTEGER:
|
||||||
|
return _content.asInteger == other._content.asInteger;
|
||||||
|
|
||||||
|
case VALUE_IS_ARRAY:
|
||||||
|
return _content.asCollection.equalsArray(other._content.asCollection);
|
||||||
|
|
||||||
|
case VALUE_IS_OBJECT:
|
||||||
|
return _content.asCollection.equalsObject(other._content.asCollection);
|
||||||
|
|
||||||
|
case VALUE_IS_FLOAT:
|
||||||
|
return _content.asFloat == other._content.asFloat;
|
||||||
|
|
||||||
|
case VALUE_IS_NULL:
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isArray() const {
|
||||||
|
return type() == VALUE_IS_ARRAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isBoolean() const {
|
||||||
|
return type() == VALUE_IS_BOOLEAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isInteger() const {
|
||||||
|
return type() == VALUE_IS_POSITIVE_INTEGER ||
|
||||||
|
type() == VALUE_IS_NEGATIVE_INTEGER;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isFloat() const {
|
||||||
|
return type() == VALUE_IS_FLOAT || type() == VALUE_IS_POSITIVE_INTEGER ||
|
||||||
|
type() == VALUE_IS_NEGATIVE_INTEGER;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isString() const {
|
||||||
|
return (type() == VALUE_IS_LINKED_STRING ||
|
||||||
|
type() == VALUE_IS_OWNED_STRING);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isObject() const {
|
||||||
|
return type() == VALUE_IS_OBJECT;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isNull() const {
|
||||||
|
return type() == VALUE_IS_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBoolean(bool value) {
|
||||||
|
setType(VALUE_IS_BOOLEAN);
|
||||||
|
_content.asInteger = static_cast<UInt>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setFloat(Float value) {
|
||||||
|
setType(VALUE_IS_FLOAT);
|
||||||
|
_content.asFloat = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLinkedRaw(SerializedValue<const char *> value) {
|
||||||
|
setType(VALUE_IS_LINKED_RAW);
|
||||||
|
_content.asRaw.data = value.data();
|
||||||
|
_content.asRaw.size = value.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool setOwnedRaw(SerializedValue<T> value, MemoryPool *pool) {
|
||||||
|
char *dup = makeString(value.data(), value.size()).save(pool);
|
||||||
|
if (dup) {
|
||||||
|
setType(VALUE_IS_OWNED_RAW);
|
||||||
|
_content.asRaw.data = dup;
|
||||||
|
_content.asRaw.size = value.size();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
setType(VALUE_IS_NULL);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
typename enable_if<is_unsigned<T>::value>::type setInteger(T value) {
|
||||||
|
setUnsignedInteger(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
typename enable_if<is_signed<T>::value>::type setInteger(T value) {
|
||||||
|
setSignedInteger(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void setSignedInteger(T value) {
|
||||||
|
if (value >= 0) {
|
||||||
|
setType(VALUE_IS_POSITIVE_INTEGER);
|
||||||
|
_content.asInteger = static_cast<UInt>(value);
|
||||||
|
} else {
|
||||||
|
setType(VALUE_IS_NEGATIVE_INTEGER);
|
||||||
|
_content.asInteger = ~static_cast<UInt>(value) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLinkedString(const char *value) {
|
||||||
|
setType(VALUE_IS_LINKED_STRING);
|
||||||
|
_content.asString = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setNull() {
|
||||||
|
setType(VALUE_IS_NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setOwnedString(const char *s) {
|
||||||
|
setType(VALUE_IS_OWNED_STRING);
|
||||||
|
_content.asString = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool setOwnedString(T value, MemoryPool *pool) {
|
||||||
|
char *dup = value.save(pool);
|
||||||
|
if (dup) {
|
||||||
|
setType(VALUE_IS_OWNED_STRING);
|
||||||
|
_content.asString = dup;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
setType(VALUE_IS_NULL);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setUnsignedInteger(UInt value) {
|
||||||
|
setType(VALUE_IS_POSITIVE_INTEGER);
|
||||||
|
_content.asInteger = static_cast<UInt>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
CollectionData &toArray() {
|
||||||
|
setType(VALUE_IS_ARRAY);
|
||||||
|
_content.asCollection.clear();
|
||||||
|
return _content.asCollection;
|
||||||
|
}
|
||||||
|
|
||||||
|
CollectionData &toObject() {
|
||||||
|
setType(VALUE_IS_OBJECT);
|
||||||
|
_content.asCollection.clear();
|
||||||
|
return _content.asCollection;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size() const {
|
||||||
|
if (type() == VALUE_IS_OBJECT || type() == VALUE_IS_ARRAY)
|
||||||
|
return _content.asCollection.size();
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t type() const {
|
||||||
|
return _flags & VALUE_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setType(uint8_t t) {
|
||||||
|
_flags &= KEY_IS_OWNED;
|
||||||
|
_flags |= t;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ObjectData {
|
|
||||||
VariantSlot *head;
|
|
||||||
VariantSlot *tail;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ArrayData {
|
|
||||||
VariantSlot *head;
|
|
||||||
VariantSlot *tail;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct RawData {
|
|
||||||
const char *data;
|
|
||||||
size_t size;
|
|
||||||
};
|
|
||||||
|
|
||||||
// A union that defines the actual content of a VariantData.
|
|
||||||
// The enum VariantType determines which member is in use.
|
|
||||||
union VariantContent {
|
|
||||||
Float asFloat;
|
|
||||||
UInt asInteger;
|
|
||||||
ArrayData asArray;
|
|
||||||
ObjectData asObject;
|
|
||||||
const char *asString;
|
|
||||||
struct {
|
|
||||||
const char *data;
|
|
||||||
size_t size;
|
|
||||||
} asRaw;
|
|
||||||
};
|
|
||||||
|
|
||||||
// this struct must be a POD type to prevent error calling offsetof on clang
|
|
||||||
struct VariantData {
|
|
||||||
VariantContent content;
|
|
||||||
bool keyIsOwned : 1;
|
|
||||||
VariantType type : 7;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline VariantData *getVariantData(ArrayData *arr) {
|
|
||||||
const ptrdiff_t offset =
|
|
||||||
offsetof(VariantData, content) - offsetof(VariantContent, asArray);
|
|
||||||
if (!arr) return 0;
|
|
||||||
return reinterpret_cast<VariantData *>(reinterpret_cast<char *>(arr) -
|
|
||||||
offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline VariantData *getVariantData(ObjectData *obj) {
|
|
||||||
const ptrdiff_t offset =
|
|
||||||
offsetof(VariantData, content) - offsetof(VariantContent, asObject);
|
|
||||||
if (!obj) return 0;
|
|
||||||
return reinterpret_cast<VariantData *>(reinterpret_cast<char *>(obj) -
|
|
||||||
offset);
|
|
||||||
}
|
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
|
@ -4,292 +4,142 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../Array/ArrayFunctions.hpp"
|
|
||||||
#include "../Misc/SerializedValue.hpp"
|
|
||||||
#include "../Numbers/parseFloat.hpp"
|
|
||||||
#include "../Numbers/parseInteger.hpp"
|
|
||||||
#include "../Object/ObjectFunctions.hpp"
|
|
||||||
#include "VariantData.hpp"
|
#include "VariantData.hpp"
|
||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
template <typename T>
|
|
||||||
inline T variantAsIntegral(const VariantData* var) {
|
|
||||||
if (!var) return 0;
|
|
||||||
switch (var->type) {
|
|
||||||
case JSON_POSITIVE_INTEGER:
|
|
||||||
case JSON_BOOLEAN:
|
|
||||||
return T(var->content.asInteger);
|
|
||||||
case JSON_NEGATIVE_INTEGER:
|
|
||||||
return T(~var->content.asInteger + 1);
|
|
||||||
case JSON_LINKED_STRING:
|
|
||||||
case JSON_OWNED_STRING:
|
|
||||||
return parseInteger<T>(var->content.asString);
|
|
||||||
case JSON_FLOAT:
|
|
||||||
return T(var->content.asFloat);
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool variantAsBoolean(const VariantData* var) {
|
template <typename Visitor>
|
||||||
return variantAsIntegral<int>(var) != 0;
|
inline void variantAccept(const VariantData *var, Visitor &visitor) {
|
||||||
}
|
if (var != 0)
|
||||||
|
var->accept(visitor);
|
||||||
// T = float/double
|
|
||||||
template <typename T>
|
|
||||||
inline T variantAsFloat(const VariantData* var) {
|
|
||||||
if (!var) return 0;
|
|
||||||
switch (var->type) {
|
|
||||||
case JSON_POSITIVE_INTEGER:
|
|
||||||
case JSON_BOOLEAN:
|
|
||||||
return static_cast<T>(var->content.asInteger);
|
|
||||||
case JSON_NEGATIVE_INTEGER:
|
|
||||||
return -static_cast<T>(var->content.asInteger);
|
|
||||||
case JSON_LINKED_STRING:
|
|
||||||
case JSON_OWNED_STRING:
|
|
||||||
return parseFloat<T>(var->content.asString);
|
|
||||||
case JSON_FLOAT:
|
|
||||||
return static_cast<T>(var->content.asFloat);
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const char* variantAsString(const VariantData* var) {
|
|
||||||
if (!var) return 0;
|
|
||||||
switch (var->type) {
|
|
||||||
case JSON_LINKED_STRING:
|
|
||||||
case JSON_OWNED_STRING:
|
|
||||||
return var->content.asString;
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline ArrayData* variantAsArray(VariantData* var) {
|
|
||||||
if (var && var->type == JSON_ARRAY)
|
|
||||||
return &var->content.asArray;
|
|
||||||
else
|
else
|
||||||
return 0;
|
visitor.visitNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const ArrayData* variantAsArray(const VariantData* var) {
|
inline const CollectionData *variantAsObject(const VariantData *var) {
|
||||||
if (var && var->type == JSON_ARRAY)
|
return var != 0 ? var->asObject() : 0;
|
||||||
return &var->content.asArray;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline ObjectData* variantAsObject(VariantData* var) {
|
inline CollectionData *variantAsObject(VariantData *var) {
|
||||||
if (var && var->type == JSON_OBJECT)
|
return var != 0 ? var->asObject() : 0;
|
||||||
return &var->content.asObject;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const ObjectData* variantAsObject(const VariantData* var) {
|
inline bool variantCopyFrom(VariantData *dst, const VariantData *src,
|
||||||
if (var && var->type == JSON_OBJECT)
|
MemoryPool *pool) {
|
||||||
return &var->content.asObject;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool variantSetBoolean(VariantData* var, bool value) {
|
|
||||||
if (!var) return false;
|
|
||||||
var->type = JSON_BOOLEAN;
|
|
||||||
var->content.asInteger = static_cast<UInt>(value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool variantSetFloat(VariantData* var, Float value) {
|
|
||||||
if (!var) return false;
|
|
||||||
var->type = JSON_FLOAT;
|
|
||||||
var->content.asFloat = value;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
inline bool variantSetSignedInteger(VariantData* var, T value) {
|
|
||||||
if (!var) return false;
|
|
||||||
if (value >= 0) {
|
|
||||||
var->type = JSON_POSITIVE_INTEGER;
|
|
||||||
var->content.asInteger = static_cast<UInt>(value);
|
|
||||||
} else {
|
|
||||||
var->type = JSON_NEGATIVE_INTEGER;
|
|
||||||
var->content.asInteger = ~static_cast<UInt>(value) + 1;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool variantSetUnsignedInteger(VariantData* var, UInt value) {
|
|
||||||
if (!var) return false;
|
|
||||||
var->type = JSON_POSITIVE_INTEGER;
|
|
||||||
var->content.asInteger = static_cast<UInt>(value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool variantSetLinkedRaw(VariantData* var,
|
|
||||||
SerializedValue<const char*> value) {
|
|
||||||
if (!var) return false;
|
|
||||||
var->type = JSON_LINKED_RAW;
|
|
||||||
var->content.asRaw.data = value.data();
|
|
||||||
var->content.asRaw.size = value.size();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
inline bool variantSetOwnedRaw(VariantData* var, SerializedValue<T> value,
|
|
||||||
MemoryPool* pool) {
|
|
||||||
if (!var) return false;
|
|
||||||
char* dup = makeString(value.data(), value.size()).save(pool);
|
|
||||||
if (dup) {
|
|
||||||
var->type = JSON_OWNED_RAW;
|
|
||||||
var->content.asRaw.data = dup;
|
|
||||||
var->content.asRaw.size = value.size();
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
var->type = JSON_NULL;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
inline bool variantSetString(VariantData* var, T value, MemoryPool* pool) {
|
|
||||||
if (!var) return false;
|
|
||||||
char* dup = value.save(pool);
|
|
||||||
if (dup) {
|
|
||||||
var->type = JSON_OWNED_STRING;
|
|
||||||
var->content.asString = dup;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
var->type = JSON_NULL;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool variantSetOwnedString(VariantData* var, char* s) {
|
|
||||||
if (!var) return false;
|
|
||||||
var->type = JSON_OWNED_STRING;
|
|
||||||
var->content.asString = s;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool variantSetString(VariantData* var, const char* value) {
|
|
||||||
if (!var) return false;
|
|
||||||
var->type = JSON_LINKED_STRING;
|
|
||||||
var->content.asString = value;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void variantSetNull(VariantData* var) {
|
|
||||||
if (!var) return;
|
|
||||||
var->type = JSON_NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline ArrayData* variantToArray(VariantData* var) {
|
|
||||||
if (!var) return 0;
|
|
||||||
var->type = JSON_ARRAY;
|
|
||||||
var->content.asArray.head = 0;
|
|
||||||
var->content.asArray.tail = 0;
|
|
||||||
return &var->content.asArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline ObjectData* variantToObject(VariantData* var) {
|
|
||||||
if (!var) return 0;
|
|
||||||
var->type = JSON_OBJECT;
|
|
||||||
var->content.asObject.head = 0;
|
|
||||||
var->content.asObject.tail = 0;
|
|
||||||
return &var->content.asObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool variantCopy(VariantData* dst, const VariantData* src,
|
|
||||||
MemoryPool* pool) {
|
|
||||||
if (!dst) return false;
|
if (!dst) return false;
|
||||||
if (!src) {
|
if (!src) {
|
||||||
dst->type = JSON_NULL;
|
dst->setNull();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
switch (src->type) {
|
return dst->copyFrom(*src, pool);
|
||||||
case JSON_ARRAY:
|
|
||||||
return arrayCopy(variantToArray(dst), &src->content.asArray, pool);
|
|
||||||
case JSON_OBJECT:
|
|
||||||
return objectCopy(variantToObject(dst), &src->content.asObject, pool);
|
|
||||||
case JSON_OWNED_STRING:
|
|
||||||
return variantSetString(
|
|
||||||
dst, ZeroTerminatedRamString(src->content.asString), pool);
|
|
||||||
case JSON_OWNED_RAW:
|
|
||||||
return variantSetOwnedRaw(
|
|
||||||
dst, serialized(src->content.asRaw.data, src->content.asRaw.size),
|
|
||||||
pool);
|
|
||||||
default:
|
|
||||||
// caution: don't override keyIsOwned
|
|
||||||
dst->type = src->type;
|
|
||||||
dst->content = src->content;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool variantIsInteger(const VariantData* var) {
|
inline bool variantEquals(const VariantData *a, const VariantData *b) {
|
||||||
return var && (var->type == JSON_POSITIVE_INTEGER ||
|
|
||||||
var->type == JSON_NEGATIVE_INTEGER);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool variantIsFloat(const VariantData* var) {
|
|
||||||
return var &&
|
|
||||||
(var->type == JSON_FLOAT || var->type == JSON_POSITIVE_INTEGER ||
|
|
||||||
var->type == JSON_NEGATIVE_INTEGER);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool variantIsString(const VariantData* var) {
|
|
||||||
return var &&
|
|
||||||
(var->type == JSON_LINKED_STRING || var->type == JSON_OWNED_STRING);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool variantIsArray(const VariantData* var) {
|
|
||||||
return var && var->type == JSON_ARRAY;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool variantIsObject(const VariantData* var) {
|
|
||||||
return var && var->type == JSON_OBJECT;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool variantIsNull(const VariantData* var) {
|
|
||||||
return var == 0 || var->type == JSON_NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool variantEquals(const VariantData* a, const VariantData* b) {
|
|
||||||
if (a == b) return true;
|
if (a == b) return true;
|
||||||
if (!a || !b) return false;
|
if (!a || !b) return false;
|
||||||
if (a->type != b->type) return false;
|
return a->equals(*b);
|
||||||
|
|
||||||
switch (a->type) {
|
|
||||||
case JSON_LINKED_STRING:
|
|
||||||
case JSON_OWNED_STRING:
|
|
||||||
return !strcmp(a->content.asString, b->content.asString);
|
|
||||||
|
|
||||||
case JSON_LINKED_RAW:
|
|
||||||
case JSON_OWNED_RAW:
|
|
||||||
return a->content.asRaw.size == b->content.asRaw.size &&
|
|
||||||
!memcmp(a->content.asRaw.data, b->content.asRaw.data,
|
|
||||||
a->content.asRaw.size);
|
|
||||||
|
|
||||||
case JSON_BOOLEAN:
|
|
||||||
case JSON_POSITIVE_INTEGER:
|
|
||||||
case JSON_NEGATIVE_INTEGER:
|
|
||||||
return a->content.asInteger == b->content.asInteger;
|
|
||||||
|
|
||||||
case JSON_ARRAY:
|
|
||||||
return arrayEquals(&a->content.asArray, &b->content.asArray);
|
|
||||||
|
|
||||||
case JSON_OBJECT:
|
|
||||||
return objectEquals(&a->content.asObject, &b->content.asObject);
|
|
||||||
|
|
||||||
case JSON_FLOAT:
|
|
||||||
return a->content.asFloat == b->content.asFloat;
|
|
||||||
|
|
||||||
case JSON_NULL:
|
|
||||||
default:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool variantIsArray(const VariantData *var) {
|
||||||
|
return var && var->isArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool variantIsBoolean(const VariantData *var) {
|
||||||
|
return var && var->isBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool variantIsInteger(const VariantData *var) {
|
||||||
|
return var && var->isInteger();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool variantIsFloat(const VariantData *var) {
|
||||||
|
return var && var->isFloat();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool variantIsString(const VariantData *var) {
|
||||||
|
return var && var->isString();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool variantIsObject(const VariantData *var) {
|
||||||
|
return var && var->isObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool variantIsNull(const VariantData *var) {
|
||||||
|
return var == 0 || var->isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool variantSetBoolean(VariantData *var, bool value) {
|
||||||
|
if (!var) return false;
|
||||||
|
var->setBoolean(value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool variantSetFloat(VariantData *var, Float value) {
|
||||||
|
if (!var) return false;
|
||||||
|
var->setFloat(value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool variantSetLinkedRaw(VariantData *var,
|
||||||
|
SerializedValue<const char *> value) {
|
||||||
|
if (!var) return false;
|
||||||
|
var->setLinkedRaw(value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline bool variantSetOwnedRaw(VariantData *var, SerializedValue<T> value,
|
||||||
|
MemoryPool *pool) {
|
||||||
|
return var != 0 && var->setOwnedRaw(value, pool);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline bool variantSetSignedInteger(VariantData *var, T value) {
|
||||||
|
if (!var) return false;
|
||||||
|
var->setSignedInteger(value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool variantSetLinkedString(VariantData *var, const char *value) {
|
||||||
|
if (!var) return false;
|
||||||
|
var->setLinkedString(value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void variantSetNull(VariantData *var) {
|
||||||
|
if (!var) return;
|
||||||
|
var->setNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool variantSetOwnedString(VariantData *var, char *value) {
|
||||||
|
if (!var) return false;
|
||||||
|
var->setOwnedString(value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline bool variantSetOwnedString(VariantData *var, T value, MemoryPool *pool) {
|
||||||
|
return var != 0 && var->setOwnedString(value, pool);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool variantSetUnsignedInteger(VariantData *var, UInt value) {
|
||||||
|
if (!var) return false;
|
||||||
|
var->setUnsignedInteger(value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_t variantSize(const VariantData *var) {
|
||||||
|
return var != 0 ? var->size() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline CollectionData *variantToArray(VariantData *var) {
|
||||||
|
if (!var) return 0;
|
||||||
|
return &var->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline CollectionData *variantToObject(VariantData *var) {
|
||||||
|
if (!var) return 0;
|
||||||
|
return &var->toObject();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
|
@ -13,6 +13,53 @@
|
|||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline T VariantData::asIntegral() const {
|
||||||
|
switch (type()) {
|
||||||
|
case VALUE_IS_POSITIVE_INTEGER:
|
||||||
|
case VALUE_IS_BOOLEAN:
|
||||||
|
return T(_content.asInteger);
|
||||||
|
case VALUE_IS_NEGATIVE_INTEGER:
|
||||||
|
return T(~_content.asInteger + 1);
|
||||||
|
case VALUE_IS_LINKED_STRING:
|
||||||
|
case VALUE_IS_OWNED_STRING:
|
||||||
|
return parseInteger<T>(_content.asString);
|
||||||
|
case VALUE_IS_FLOAT:
|
||||||
|
return T(_content.asFloat);
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// T = float/double
|
||||||
|
template <typename T>
|
||||||
|
inline T VariantData::asFloat() const {
|
||||||
|
switch (type()) {
|
||||||
|
case VALUE_IS_POSITIVE_INTEGER:
|
||||||
|
case VALUE_IS_BOOLEAN:
|
||||||
|
return static_cast<T>(_content.asInteger);
|
||||||
|
case VALUE_IS_NEGATIVE_INTEGER:
|
||||||
|
return -static_cast<T>(_content.asInteger);
|
||||||
|
case VALUE_IS_LINKED_STRING:
|
||||||
|
case VALUE_IS_OWNED_STRING:
|
||||||
|
return parseFloat<T>(_content.asString);
|
||||||
|
case VALUE_IS_FLOAT:
|
||||||
|
return static_cast<T>(_content.asFloat);
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const char* VariantData::asString() const {
|
||||||
|
switch (type()) {
|
||||||
|
case VALUE_IS_LINKED_STRING:
|
||||||
|
case VALUE_IS_OWNED_STRING:
|
||||||
|
return _content.asString;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline bool VariantRef::set(ArrayRef array) const {
|
inline bool VariantRef::set(ArrayRef array) const {
|
||||||
return to<ArrayRef>().copyFrom(array);
|
return to<ArrayRef>().copyFrom(array);
|
||||||
}
|
}
|
||||||
@ -31,35 +78,35 @@ inline bool VariantRef::set(const ObjectSubscript<TString>& value) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline bool VariantRef::set(VariantConstRef value) const {
|
inline bool VariantRef::set(VariantConstRef value) const {
|
||||||
return variantCopy(_data, value._data, _memoryPool);
|
return variantCopyFrom(_data, value._data, _pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool VariantRef::set(VariantRef value) const {
|
inline bool VariantRef::set(VariantRef value) const {
|
||||||
return variantCopy(_data, value._data, _memoryPool);
|
return variantCopyFrom(_data, value._data, _pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline typename enable_if<is_same<T, ArrayRef>::value, T>::type VariantRef::as()
|
inline typename enable_if<is_same<T, ArrayRef>::value, T>::type VariantRef::as()
|
||||||
const {
|
const {
|
||||||
return ArrayRef(_memoryPool, variantAsArray(_data));
|
return ArrayRef(_pool, _data != 0 ? _data->asArray() : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline typename enable_if<is_same<T, ObjectRef>::value, T>::type
|
inline typename enable_if<is_same<T, ObjectRef>::value, T>::type
|
||||||
VariantRef::as() const {
|
VariantRef::as() const {
|
||||||
return ObjectRef(_memoryPool, variantAsObject(_data));
|
return ObjectRef(_pool, variantAsObject(_data));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline typename enable_if<is_same<T, ArrayRef>::value, ArrayRef>::type
|
inline typename enable_if<is_same<T, ArrayRef>::value, ArrayRef>::type
|
||||||
VariantRef::to() const {
|
VariantRef::to() const {
|
||||||
return ArrayRef(_memoryPool, variantToArray(_data));
|
return ArrayRef(_pool, variantToArray(_data));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename enable_if<is_same<T, ObjectRef>::value, ObjectRef>::type
|
typename enable_if<is_same<T, ObjectRef>::value, ObjectRef>::type
|
||||||
VariantRef::to() const {
|
VariantRef::to() const {
|
||||||
return ObjectRef(_memoryPool, variantToObject(_data));
|
return ObjectRef(_pool, variantToObject(_data));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -69,50 +116,8 @@ VariantRef::to() const {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Visitor>
|
|
||||||
inline void VariantRef::accept(Visitor& visitor) const {
|
|
||||||
return VariantConstRef(_data).accept(visitor);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Visitor>
|
|
||||||
inline void VariantConstRef::accept(Visitor& visitor) const {
|
|
||||||
if (!_data) return visitor.visitNull();
|
|
||||||
|
|
||||||
switch (_data->type) {
|
|
||||||
case JSON_FLOAT:
|
|
||||||
return visitor.visitFloat(_data->content.asFloat);
|
|
||||||
|
|
||||||
case JSON_ARRAY:
|
|
||||||
return visitor.visitArray(ArrayConstRef(&_data->content.asArray));
|
|
||||||
|
|
||||||
case JSON_OBJECT:
|
|
||||||
return visitor.visitObject(ObjectConstRef(&_data->content.asObject));
|
|
||||||
|
|
||||||
case JSON_LINKED_STRING:
|
|
||||||
case JSON_OWNED_STRING:
|
|
||||||
return visitor.visitString(_data->content.asString);
|
|
||||||
|
|
||||||
case JSON_OWNED_RAW:
|
|
||||||
case JSON_LINKED_RAW:
|
|
||||||
return visitor.visitRawJson(_data->content.asRaw.data,
|
|
||||||
_data->content.asRaw.size);
|
|
||||||
|
|
||||||
case JSON_NEGATIVE_INTEGER:
|
|
||||||
return visitor.visitNegativeInteger(_data->content.asInteger);
|
|
||||||
|
|
||||||
case JSON_POSITIVE_INTEGER:
|
|
||||||
return visitor.visitPositiveInteger(_data->content.asInteger);
|
|
||||||
|
|
||||||
case JSON_BOOLEAN:
|
|
||||||
return visitor.visitBoolean(_data->content.asInteger != 0);
|
|
||||||
|
|
||||||
default:
|
|
||||||
return visitor.visitNull();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline VariantConstRef VariantConstRef::operator[](size_t index) const {
|
inline VariantConstRef VariantConstRef::operator[](size_t index) const {
|
||||||
return ArrayConstRef(variantAsArray(_data))[index];
|
return ArrayConstRef(_data != 0 ? _data->asArray() : 0)[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
#include "../Operators/VariantOperators.hpp"
|
#include "../Operators/VariantOperators.hpp"
|
||||||
#include "../Polyfills/type_traits.hpp"
|
#include "../Polyfills/type_traits.hpp"
|
||||||
#include "VariantAs.hpp"
|
#include "VariantAs.hpp"
|
||||||
#include "VariantData.hpp"
|
|
||||||
#include "VariantFunctions.hpp"
|
#include "VariantFunctions.hpp"
|
||||||
#include "VariantRef.hpp"
|
#include "VariantRef.hpp"
|
||||||
|
|
||||||
@ -58,7 +57,7 @@ class VariantRefBase {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
FORCE_INLINE typename enable_if<is_same<T, bool>::value, bool>::type is()
|
FORCE_INLINE typename enable_if<is_same<T, bool>::value, bool>::type is()
|
||||||
const {
|
const {
|
||||||
return _data && _data->type == JSON_BOOLEAN;
|
return variantIsBoolean(_data);
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
// bool is<const char*>() const;
|
// bool is<const char*>() const;
|
||||||
@ -96,13 +95,8 @@ class VariantRefBase {
|
|||||||
return variantIsNull(_data);
|
return variantIsNull(_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE bool isInvalid() const {
|
|
||||||
return _data == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t size() const {
|
size_t size() const {
|
||||||
return objectSize(variantAsObject(_data)) +
|
return variantSize(_data);
|
||||||
arraySize(variantAsArray(_data));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -125,11 +119,11 @@ class VariantRef : public VariantRefBase<VariantData>,
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// Intenal use only
|
// Intenal use only
|
||||||
FORCE_INLINE VariantRef(MemoryPool *memoryPool, VariantData *data)
|
FORCE_INLINE VariantRef(MemoryPool *pool, VariantData *data)
|
||||||
: base_type(data), _memoryPool(memoryPool) {}
|
: base_type(data), _pool(pool) {}
|
||||||
|
|
||||||
// Creates an uninitialized VariantRef
|
// Creates an uninitialized VariantRef
|
||||||
FORCE_INLINE VariantRef() : base_type(0), _memoryPool(0) {}
|
FORCE_INLINE VariantRef() : base_type(0), _pool(0) {}
|
||||||
|
|
||||||
// set(bool value)
|
// set(bool value)
|
||||||
FORCE_INLINE bool set(bool value) const {
|
FORCE_INLINE bool set(bool value) const {
|
||||||
@ -180,7 +174,7 @@ class VariantRef : public VariantRefBase<VariantData>,
|
|||||||
FORCE_INLINE bool set(
|
FORCE_INLINE bool set(
|
||||||
SerializedValue<T> value,
|
SerializedValue<T> value,
|
||||||
typename enable_if<!is_same<const char *, T>::value>::type * = 0) const {
|
typename enable_if<!is_same<const char *, T>::value>::type * = 0) const {
|
||||||
return variantSetOwnedRaw(_data, value, _memoryPool);
|
return variantSetOwnedRaw(_data, value, _pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set(const std::string&)
|
// set(const std::string&)
|
||||||
@ -189,28 +183,20 @@ class VariantRef : public VariantRefBase<VariantData>,
|
|||||||
FORCE_INLINE bool set(
|
FORCE_INLINE bool set(
|
||||||
const T &value,
|
const T &value,
|
||||||
typename enable_if<IsString<T>::value>::type * = 0) const {
|
typename enable_if<IsString<T>::value>::type * = 0) const {
|
||||||
return variantSetString(_data, makeString(value), _memoryPool);
|
return variantSetOwnedString(_data, makeString(value), _pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set(char*)
|
// set(char*)
|
||||||
|
// set(const __FlashStringHelper*)
|
||||||
template <typename T>
|
template <typename T>
|
||||||
FORCE_INLINE bool set(
|
FORCE_INLINE bool set(
|
||||||
T *value, typename enable_if<IsString<T *>::value>::type * = 0) const {
|
T *value, typename enable_if<IsString<T *>::value>::type * = 0) const {
|
||||||
return variantSetString(_data, makeString(value), _memoryPool);
|
return variantSetOwnedString(_data, makeString(value), _pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set(const char*);
|
// set(const char*);
|
||||||
FORCE_INLINE bool set(const char *value) const {
|
FORCE_INLINE bool set(const char *value) const {
|
||||||
return variantSetString(_data, value);
|
return variantSetLinkedString(_data, value);
|
||||||
}
|
|
||||||
|
|
||||||
// for internal use only
|
|
||||||
FORCE_INLINE bool set(StringInMemoryPool value) const {
|
|
||||||
return variantSetOwnedString(_data,
|
|
||||||
value.save(_memoryPool)); // TODO: remove?
|
|
||||||
}
|
|
||||||
FORCE_INLINE bool set(ZeroTerminatedRamStringConst value) const {
|
|
||||||
return variantSetString(_data, value.c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool set(VariantConstRef value) const;
|
bool set(VariantConstRef value) const;
|
||||||
@ -255,7 +241,9 @@ class VariantRef : public VariantRefBase<VariantData>,
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Visitor>
|
template <typename Visitor>
|
||||||
void accept(Visitor &visitor) const;
|
void accept(Visitor &visitor) const {
|
||||||
|
variantAccept(_data, visitor);
|
||||||
|
}
|
||||||
|
|
||||||
FORCE_INLINE bool operator==(VariantRef lhs) const {
|
FORCE_INLINE bool operator==(VariantRef lhs) const {
|
||||||
return variantEquals(_data, lhs._data);
|
return variantEquals(_data, lhs._data);
|
||||||
@ -281,7 +269,7 @@ class VariantRef : public VariantRefBase<VariantData>,
|
|||||||
const;
|
const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MemoryPool *_memoryPool;
|
MemoryPool *_pool;
|
||||||
};
|
};
|
||||||
|
|
||||||
class VariantConstRef : public VariantRefBase<const VariantData>,
|
class VariantConstRef : public VariantRefBase<const VariantData>,
|
||||||
@ -296,7 +284,9 @@ class VariantConstRef : public VariantRefBase<const VariantData>,
|
|||||||
VariantConstRef(VariantRef var) : base_type(var._data) {}
|
VariantConstRef(VariantRef var) : base_type(var._data) {}
|
||||||
|
|
||||||
template <typename Visitor>
|
template <typename Visitor>
|
||||||
void accept(Visitor &visitor) const;
|
void accept(Visitor &visitor) const {
|
||||||
|
variantAccept(_data, visitor);
|
||||||
|
}
|
||||||
|
|
||||||
// Get the variant as the specified type.
|
// Get the variant as the specified type.
|
||||||
//
|
//
|
||||||
@ -323,7 +313,8 @@ class VariantConstRef : public VariantRefBase<const VariantData>,
|
|||||||
FORCE_INLINE
|
FORCE_INLINE
|
||||||
typename enable_if<IsString<TString *>::value, VariantConstRef>::type
|
typename enable_if<IsString<TString *>::value, VariantConstRef>::type
|
||||||
operator[](TString *key) const {
|
operator[](TString *key) const {
|
||||||
return VariantConstRef(objectGet(variantAsObject(_data), makeString(key)));
|
const CollectionData *obj = variantAsObject(_data);
|
||||||
|
return VariantConstRef(obj ? obj->get(makeString(key)) : 0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
|
@ -5,7 +5,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../Polyfills/type_traits.hpp"
|
#include "../Polyfills/type_traits.hpp"
|
||||||
#include "../Variant/VariantData.hpp"
|
#include "../Variant/VariantContent.hpp"
|
||||||
|
|
||||||
|
#include <stdint.h> // int8_t, int16_t
|
||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
@ -16,8 +18,7 @@ class VariantSlot {
|
|||||||
// we cannot use composition because it adds padding
|
// we cannot use composition because it adds padding
|
||||||
// (+20% on ESP8266 for example)
|
// (+20% on ESP8266 for example)
|
||||||
VariantContent _content;
|
VariantContent _content;
|
||||||
bool _keyIsOwned : 1;
|
uint8_t _flags;
|
||||||
VariantType _type : 7;
|
|
||||||
VariantSlotDiff _next;
|
VariantSlotDiff _next;
|
||||||
const char* _key;
|
const char* _key;
|
||||||
|
|
||||||
@ -28,23 +29,23 @@ class VariantSlot {
|
|||||||
// - no virtual
|
// - no virtual
|
||||||
// - no inheritance
|
// - no inheritance
|
||||||
|
|
||||||
VariantData* getData() {
|
VariantData* data() {
|
||||||
return reinterpret_cast<VariantData*>(&_content);
|
return reinterpret_cast<VariantData*>(&_content);
|
||||||
}
|
}
|
||||||
|
|
||||||
const VariantData* getData() const {
|
const VariantData* data() const {
|
||||||
return reinterpret_cast<const VariantData*>(&_content);
|
return reinterpret_cast<const VariantData*>(&_content);
|
||||||
}
|
}
|
||||||
|
|
||||||
VariantSlot* getNext() {
|
VariantSlot* next() {
|
||||||
return _next ? this + _next : 0;
|
return _next ? this + _next : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const VariantSlot* getNext() const {
|
const VariantSlot* next() const {
|
||||||
return const_cast<VariantSlot*>(this)->getNext();
|
return const_cast<VariantSlot*>(this)->next();
|
||||||
}
|
}
|
||||||
|
|
||||||
VariantSlot* getNext(size_t distance) {
|
VariantSlot* next(size_t distance) {
|
||||||
VariantSlot* slot = this;
|
VariantSlot* slot = this;
|
||||||
while (distance--) {
|
while (distance--) {
|
||||||
if (!slot->_next) return 0;
|
if (!slot->_next) return 0;
|
||||||
@ -53,29 +54,26 @@ class VariantSlot {
|
|||||||
return slot;
|
return slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
VariantSlot* getPrev(VariantSlot* head) {
|
const VariantSlot* next(size_t distance) const {
|
||||||
while (head) {
|
return const_cast<VariantSlot*>(this)->next(distance);
|
||||||
VariantSlot* nxt = head->getNext();
|
|
||||||
if (nxt == this) return head;
|
|
||||||
head = nxt;
|
|
||||||
}
|
|
||||||
return head;
|
|
||||||
}
|
|
||||||
|
|
||||||
const VariantSlot* getNext(size_t distance) const {
|
|
||||||
return const_cast<VariantSlot*>(this)->getNext(distance);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setNext(VariantSlot* slot) {
|
void setNext(VariantSlot* slot) {
|
||||||
_next = VariantSlotDiff(slot ? slot - this : 0);
|
_next = VariantSlotDiff(slot ? slot - this : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void attachTo(VariantSlot* tail) {
|
void setNextNotNull(VariantSlot* slot) {
|
||||||
tail->_next = VariantSlotDiff(this - tail);
|
ARDUINOJSON_ASSERT(slot != 0);
|
||||||
|
_next = VariantSlotDiff(slot - this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setKey(const char* k, bool owned) {
|
void setOwnedKey(const char* k) {
|
||||||
_keyIsOwned = owned;
|
_flags |= KEY_IS_OWNED;
|
||||||
|
_key = k;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLinkedKey(const char* k) {
|
||||||
|
_flags &= VALUE_MASK;
|
||||||
_key = k;
|
_key = k;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,13 +82,13 @@ class VariantSlot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ownsKey() const {
|
bool ownsKey() const {
|
||||||
return _keyIsOwned;
|
return (_flags & KEY_IS_OWNED) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void init() {
|
void clear() {
|
||||||
_next = 0;
|
_next = 0;
|
||||||
_type = JSON_NULL;
|
_flags = 0;
|
||||||
_keyIsOwned = false;
|
_key = 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -22,7 +22,25 @@ TEST_CASE("JsonArray::operator==()") {
|
|||||||
REQUIRE_FALSE(array1c == array2c);
|
REQUIRE_FALSE(array1c == array2c);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("should return false when arrays differ") {
|
SECTION("should return false when LHS has more elements") {
|
||||||
|
array1.add(1);
|
||||||
|
array1.add(2);
|
||||||
|
array2.add(1);
|
||||||
|
|
||||||
|
REQUIRE_FALSE(array1 == array2);
|
||||||
|
REQUIRE_FALSE(array1c == array2c);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("should return false when RKS has more elements") {
|
||||||
|
array1.add(1);
|
||||||
|
array2.add(1);
|
||||||
|
array2.add(2);
|
||||||
|
|
||||||
|
REQUIRE_FALSE(array1 == array2);
|
||||||
|
REQUIRE_FALSE(array1c == array2c);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("should return true when arrays equal") {
|
||||||
array1.add("coucou");
|
array1.add("coucou");
|
||||||
array2.add("coucou");
|
array2.add("coucou");
|
||||||
|
|
||||||
|
@ -22,7 +22,25 @@ TEST_CASE("JsonObject::operator==()") {
|
|||||||
REQUIRE_FALSE(obj1c == obj2c);
|
REQUIRE_FALSE(obj1c == obj2c);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("should return false when objs differ") {
|
SECTION("should return false when LHS has more elements") {
|
||||||
|
obj1["hello"] = "coucou";
|
||||||
|
obj1["world"] = 666;
|
||||||
|
obj2["hello"] = "coucou";
|
||||||
|
|
||||||
|
REQUIRE_FALSE(obj1 == obj2);
|
||||||
|
REQUIRE_FALSE(obj1c == obj2c);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("should return false when RKS has more elements") {
|
||||||
|
obj1["hello"] = "coucou";
|
||||||
|
obj2["hello"] = "coucou";
|
||||||
|
obj2["world"] = 666;
|
||||||
|
|
||||||
|
REQUIRE_FALSE(obj1 == obj2);
|
||||||
|
REQUIRE_FALSE(obj1c == obj2c);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("should return true when objs equal") {
|
||||||
obj1["hello"] = "world";
|
obj1["hello"] = "world";
|
||||||
obj1["anwser"] = 42;
|
obj1["anwser"] = 42;
|
||||||
// insert in different order
|
// insert in different order
|
||||||
|
@ -12,30 +12,30 @@ static char buffer[4096];
|
|||||||
|
|
||||||
TEST_CASE("StringBuilder") {
|
TEST_CASE("StringBuilder") {
|
||||||
SECTION("Works when buffer is big enough") {
|
SECTION("Works when buffer is big enough") {
|
||||||
MemoryPool memoryPool(buffer, addPadding(JSON_STRING_SIZE(6)));
|
MemoryPool pool(buffer, addPadding(JSON_STRING_SIZE(6)));
|
||||||
|
|
||||||
StringBuilder str(&memoryPool);
|
StringBuilder str(&pool);
|
||||||
str.append("hello");
|
str.append("hello");
|
||||||
|
|
||||||
REQUIRE(str.complete().equals("hello"));
|
REQUIRE(str.complete() == std::string("hello"));
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Returns null when too small") {
|
SECTION("Returns null when too small") {
|
||||||
MemoryPool memoryPool(buffer, sizeof(void*));
|
MemoryPool pool(buffer, sizeof(void*));
|
||||||
|
|
||||||
StringBuilder str(&memoryPool);
|
StringBuilder str(&pool);
|
||||||
str.append("hello world!");
|
str.append("hello world!");
|
||||||
|
|
||||||
REQUIRE(str.complete().isNull());
|
REQUIRE(str.complete() == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Increases size of memory pool") {
|
SECTION("Increases size of memory pool") {
|
||||||
MemoryPool memoryPool(buffer, addPadding(JSON_STRING_SIZE(6)));
|
MemoryPool pool(buffer, addPadding(JSON_STRING_SIZE(6)));
|
||||||
|
|
||||||
StringBuilder str(&memoryPool);
|
StringBuilder str(&pool);
|
||||||
str.append('h');
|
str.append('h');
|
||||||
str.complete();
|
str.complete();
|
||||||
|
|
||||||
REQUIRE(JSON_STRING_SIZE(2) == memoryPool.size());
|
REQUIRE(JSON_STRING_SIZE(2) == pool.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,21 +11,21 @@ static const size_t poolCapacity = 512;
|
|||||||
|
|
||||||
TEST_CASE("MemoryPool::clear()") {
|
TEST_CASE("MemoryPool::clear()") {
|
||||||
char buffer[poolCapacity];
|
char buffer[poolCapacity];
|
||||||
MemoryPool memoryPool(buffer, sizeof(buffer));
|
MemoryPool pool(buffer, sizeof(buffer));
|
||||||
|
|
||||||
SECTION("Discards allocated variants") {
|
SECTION("Discards allocated variants") {
|
||||||
memoryPool.allocVariant();
|
pool.allocVariant();
|
||||||
|
|
||||||
memoryPool.clear();
|
pool.clear();
|
||||||
REQUIRE(memoryPool.size() == 0);
|
REQUIRE(pool.size() == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Discards allocated strings") {
|
SECTION("Discards allocated strings") {
|
||||||
memoryPool.allocFrozenString(10);
|
pool.allocFrozenString(10);
|
||||||
REQUIRE(memoryPool.size() > 0);
|
REQUIRE(pool.size() > 0);
|
||||||
|
|
||||||
memoryPool.clear();
|
pool.clear();
|
||||||
|
|
||||||
REQUIRE(memoryPool.size() == 0);
|
REQUIRE(pool.size() == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,48 +11,48 @@ char buffer[4096];
|
|||||||
|
|
||||||
TEST_CASE("MemoryPool::capacity()") {
|
TEST_CASE("MemoryPool::capacity()") {
|
||||||
const size_t capacity = 64;
|
const size_t capacity = 64;
|
||||||
MemoryPool memoryPool(buffer, capacity);
|
MemoryPool pool(buffer, capacity);
|
||||||
REQUIRE(capacity == memoryPool.capacity());
|
REQUIRE(capacity == pool.capacity());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("MemoryPool::size()") {
|
TEST_CASE("MemoryPool::size()") {
|
||||||
MemoryPool memoryPool(buffer, sizeof(buffer));
|
MemoryPool pool(buffer, sizeof(buffer));
|
||||||
|
|
||||||
SECTION("Initial size is 0") {
|
SECTION("Initial size is 0") {
|
||||||
REQUIRE(0 == memoryPool.size());
|
REQUIRE(0 == pool.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("size() == capacity() after allocExpandableString()") {
|
SECTION("size() == capacity() after allocExpandableString()") {
|
||||||
memoryPool.allocExpandableString();
|
pool.allocExpandableString();
|
||||||
REQUIRE(memoryPool.size() == memoryPool.capacity());
|
REQUIRE(pool.size() == pool.capacity());
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Decreases after freezeString()") {
|
SECTION("Decreases after freezeString()") {
|
||||||
StringSlot a = memoryPool.allocExpandableString();
|
StringSlot a = pool.allocExpandableString();
|
||||||
memoryPool.freezeString(a, 1);
|
pool.freezeString(a, 1);
|
||||||
REQUIRE(memoryPool.size() == JSON_STRING_SIZE(1));
|
REQUIRE(pool.size() == JSON_STRING_SIZE(1));
|
||||||
|
|
||||||
StringSlot b = memoryPool.allocExpandableString();
|
StringSlot b = pool.allocExpandableString();
|
||||||
memoryPool.freezeString(b, 1);
|
pool.freezeString(b, 1);
|
||||||
REQUIRE(memoryPool.size() == 2 * JSON_STRING_SIZE(1));
|
REQUIRE(pool.size() == 2 * JSON_STRING_SIZE(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Increases after allocFrozenString()") {
|
SECTION("Increases after allocFrozenString()") {
|
||||||
memoryPool.allocFrozenString(0);
|
pool.allocFrozenString(0);
|
||||||
REQUIRE(memoryPool.size() == JSON_STRING_SIZE(0));
|
REQUIRE(pool.size() == JSON_STRING_SIZE(0));
|
||||||
|
|
||||||
memoryPool.allocFrozenString(0);
|
pool.allocFrozenString(0);
|
||||||
REQUIRE(memoryPool.size() == 2 * JSON_STRING_SIZE(0));
|
REQUIRE(pool.size() == 2 * JSON_STRING_SIZE(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Doesn't grow when memory pool is full") {
|
SECTION("Doesn't grow when memory pool is full") {
|
||||||
const size_t variantCount = sizeof(buffer) / sizeof(VariantSlot);
|
const size_t variantCount = sizeof(buffer) / sizeof(VariantSlot);
|
||||||
|
|
||||||
for (size_t i = 0; i < variantCount; i++) memoryPool.allocVariant();
|
for (size_t i = 0; i < variantCount; i++) pool.allocVariant();
|
||||||
size_t size = memoryPool.size();
|
size_t size = pool.size();
|
||||||
|
|
||||||
memoryPool.allocVariant();
|
pool.allocVariant();
|
||||||
|
|
||||||
REQUIRE(size == memoryPool.size());
|
REQUIRE(size == pool.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user