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