Extracted VariantData and CollectionData classes

This commit is contained in:
Benoit Blanchon
2018-12-07 09:16:58 +01:00
parent 1ad97ebf85
commit b77b203935
45 changed files with 1129 additions and 1007 deletions

View File

@ -7,6 +7,7 @@ HEAD
* Removed the automatic expansion of `DynamicJsonDocument`, it now has a fixed capacity. * Removed the automatic expansion of `DynamicJsonDocument`, it now has a fixed capacity.
* Restored the monotonic allocator because the code was getting too big * Restored the monotonic allocator because the code was getting too big
* Reduced the memory usage * Reduced the memory usage
* Reduced the code size
* Removed spurious files in the Particle library * Removed spurious files in the Particle library
v6.6.0-beta (2018-11-13) v6.6.0-beta (2018-11-13)

View File

@ -15,6 +15,7 @@
#include "ArduinoJson/Array/ArrayImpl.hpp" #include "ArduinoJson/Array/ArrayImpl.hpp"
#include "ArduinoJson/Array/ArraySubscript.hpp" #include "ArduinoJson/Array/ArraySubscript.hpp"
#include "ArduinoJson/Collection/CollectionImpl.hpp"
#include "ArduinoJson/Object/ObjectImpl.hpp" #include "ArduinoJson/Object/ObjectImpl.hpp"
#include "ArduinoJson/Object/ObjectSubscript.hpp" #include "ArduinoJson/Object/ObjectSubscript.hpp"
#include "ArduinoJson/Variant/VariantAsImpl.hpp" #include "ArduinoJson/Variant/VariantAsImpl.hpp"

View File

@ -4,92 +4,26 @@
#pragma once #pragma once
#include "../Variant/SlotFunctions.hpp" #include "../Collection/CollectionData.hpp"
#include "../Variant/VariantData.hpp"
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
inline VariantData* arrayAdd(ArrayData* arr, MemoryPool* pool) { inline VariantData *arrayAdd(CollectionData *arr, MemoryPool *pool) {
if (!arr) return 0; return arr ? arr->add(pool) : 0;
VariantSlot* slot = pool->allocVariant();
if (!slot) return 0;
slot->init();
if (arr->tail) {
slot->attachTo(arr->tail);
arr->tail = slot;
} else {
arr->head = slot;
arr->tail = slot;
}
return slot->getData();
} }
inline VariantSlot* arrayGetSlot(const ArrayData* arr, size_t index) { template <typename Visitor>
if (!arr) return 0; inline void arrayAccept(const CollectionData *arr, Visitor &visitor) {
return arr->head->getNext(index); if (arr)
} visitor.visitArray(*arr);
inline VariantData* arrayGet(const ArrayData* arr, size_t index) {
VariantSlot* slot = arrayGetSlot(arr, index);
return slot ? slot->getData() : 0;
}
inline void arrayRemove(ArrayData* arr, VariantSlot* slot) {
if (!arr || !slot) return;
VariantSlot* prev = slot->getPrev(arr->head);
VariantSlot* next = slot->getNext();
if (prev)
prev->setNext(next);
else else
arr->head = next; visitor.visitNull();
if (!next) arr->tail = prev;
} }
inline void arrayRemove(ArrayData* arr, size_t index) { inline bool arrayEquals(const CollectionData *lhs, const CollectionData *rhs) {
arrayRemove(arr, arrayGetSlot(arr, index)); if (lhs == rhs) return true;
} if (!lhs || !rhs) return false;
inline void arrayClear(ArrayData* arr) { return lhs->equalsArray(*rhs);
if (!arr) return;
arr->head = 0;
arr->tail = 0;
}
bool variantCopy(VariantData*, const VariantData*, MemoryPool*);
inline bool arrayCopy(ArrayData* dst, const ArrayData* src, MemoryPool* pool) {
if (!dst || !src) return false;
arrayClear(dst);
for (VariantSlot* s = src->head; s; s = s->getNext()) {
if (!variantCopy(arrayAdd(dst, pool), s->getData(), pool)) return false;
}
return true;
}
bool variantEquals(const VariantData*, const VariantData*);
inline bool arrayEquals(const ArrayData* a1, const ArrayData* a2) {
if (a1 == a2) return true;
if (!a1 || !a2) return false;
VariantSlot* s1 = a1->head;
VariantSlot* s2 = a2->head;
for (;;) {
if (s1 == s2) return true;
if (!s1 || !s2) return false;
if (!variantEquals(s1->getData(), s2->getData())) return false;
s1 = s1->getNext();
s2 = s2->getNext();
}
}
inline size_t arraySize(const ArrayData* arr) {
if (!arr) return 0;
return slotSize(arr->head);
} }
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@ -11,8 +11,7 @@ namespace ARDUINOJSON_NAMESPACE {
class VariantPtr { class VariantPtr {
public: public:
VariantPtr(MemoryPool *memoryPool, VariantData *data) VariantPtr(MemoryPool *pool, VariantData *data) : _variant(pool, data) {}
: _variant(memoryPool, data) {}
VariantRef *operator->() { VariantRef *operator->() {
return &_variant; return &_variant;
@ -29,14 +28,14 @@ class VariantPtr {
class ArrayIterator { class ArrayIterator {
public: public:
ArrayIterator() : _slot(0) {} ArrayIterator() : _slot(0) {}
explicit ArrayIterator(MemoryPool *memoryPool, VariantSlot *slot) explicit ArrayIterator(MemoryPool *pool, VariantSlot *slot)
: _memoryPool(memoryPool), _slot(slot) {} : _pool(pool), _slot(slot) {}
VariantRef operator*() const { VariantRef operator*() const {
return VariantRef(_memoryPool, _slot->getData()); return VariantRef(_pool, _slot->data());
} }
VariantPtr operator->() { VariantPtr operator->() {
return VariantPtr(_memoryPool, _slot->getData()); return VariantPtr(_pool, _slot->data());
} }
bool operator==(const ArrayIterator &other) const { bool operator==(const ArrayIterator &other) const {
@ -48,12 +47,12 @@ class ArrayIterator {
} }
ArrayIterator &operator++() { ArrayIterator &operator++() {
_slot = _slot->getNext(); _slot = _slot->next();
return *this; return *this;
} }
ArrayIterator &operator+=(size_t distance) { ArrayIterator &operator+=(size_t distance) {
_slot = _slot->getNext(distance); _slot = _slot->next(distance);
return *this; return *this;
} }
@ -62,7 +61,7 @@ class ArrayIterator {
} }
private: private:
MemoryPool *_memoryPool; MemoryPool *_pool;
VariantSlot *_slot; VariantSlot *_slot;
}; };
@ -88,10 +87,10 @@ class ArrayConstRefIterator {
explicit ArrayConstRefIterator(const VariantSlot *slot) : _slot(slot) {} explicit ArrayConstRefIterator(const VariantSlot *slot) : _slot(slot) {}
VariantConstRef operator*() const { VariantConstRef operator*() const {
return VariantConstRef(_slot->getData()); return VariantConstRef(_slot->data());
} }
VariantConstPtr operator->() { VariantConstPtr operator->() {
return VariantConstPtr(_slot->getData()); return VariantConstPtr(_slot->data());
} }
bool operator==(const ArrayConstRefIterator &other) const { bool operator==(const ArrayConstRefIterator &other) const {
@ -103,12 +102,12 @@ class ArrayConstRefIterator {
} }
ArrayConstRefIterator &operator++() { ArrayConstRefIterator &operator++() {
_slot = _slot->getNext(); _slot = _slot->next();
return *this; return *this;
} }
ArrayConstRefIterator &operator+=(size_t distance) { ArrayConstRefIterator &operator+=(size_t distance) {
_slot = _slot->getNext(distance); _slot = _slot->next(distance);
return *this; return *this;
} }

View File

@ -21,16 +21,21 @@ class ArraySubscript;
template <typename TData> template <typename TData>
class ArrayRefBase { class ArrayRefBase {
public: public:
template <typename Visitor>
FORCE_INLINE void accept(Visitor& visitor) const {
arrayAccept(_data, visitor);
}
FORCE_INLINE bool isNull() const { FORCE_INLINE bool isNull() const {
return _data == 0; return _data == 0;
} }
FORCE_INLINE VariantConstRef operator[](size_t index) const { FORCE_INLINE VariantConstRef operator[](size_t index) const {
return VariantConstRef(arrayGet(_data, index)); return VariantConstRef(_data ? _data->get(index) : 0);
} }
FORCE_INLINE size_t size() const { FORCE_INLINE size_t size() const {
return arraySize(_data); return _data ? _data->size() : 0;
} }
protected: protected:
@ -38,24 +43,17 @@ class ArrayRefBase {
TData* _data; TData* _data;
}; };
class ArrayConstRef : public ArrayRefBase<const ArrayData>, public Visitable { class ArrayConstRef : public ArrayRefBase<const CollectionData>,
public Visitable {
friend class ArrayRef; friend class ArrayRef;
typedef ArrayRefBase<const ArrayData> base_type; typedef ArrayRefBase<const CollectionData> base_type;
public: public:
typedef ArrayConstRefIterator iterator; typedef ArrayConstRefIterator iterator;
template <typename Visitor>
FORCE_INLINE void accept(Visitor& visitor) const {
if (_data)
visitor.visitArray(*this);
else
visitor.visitNull();
}
FORCE_INLINE iterator begin() const { FORCE_INLINE iterator begin() const {
if (!_data) return iterator(); if (!_data) return iterator();
return iterator(_data->head); return iterator(_data->head());
} }
FORCE_INLINE iterator end() const { FORCE_INLINE iterator end() const {
@ -63,25 +61,25 @@ class ArrayConstRef : public ArrayRefBase<const ArrayData>, public Visitable {
} }
FORCE_INLINE ArrayConstRef() : base_type(0) {} FORCE_INLINE ArrayConstRef() : base_type(0) {}
FORCE_INLINE ArrayConstRef(const ArrayData* data) : base_type(data) {} FORCE_INLINE ArrayConstRef(const CollectionData* data) : base_type(data) {}
FORCE_INLINE bool operator==(ArrayConstRef rhs) const { FORCE_INLINE bool operator==(ArrayConstRef rhs) const {
return arrayEquals(_data, rhs._data); return arrayEquals(_data, rhs._data);
} }
}; };
class ArrayRef : public ArrayRefBase<ArrayData>, public Visitable { class ArrayRef : public ArrayRefBase<CollectionData>, public Visitable {
typedef ArrayRefBase<ArrayData> base_type; typedef ArrayRefBase<CollectionData> base_type;
public: public:
typedef ArrayIterator iterator; typedef ArrayIterator iterator;
FORCE_INLINE ArrayRef() : base_type(0), _memoryPool(0) {} FORCE_INLINE ArrayRef() : base_type(0), _pool(0) {}
FORCE_INLINE ArrayRef(MemoryPool* pool, ArrayData* data) FORCE_INLINE ArrayRef(MemoryPool* pool, CollectionData* data)
: base_type(data), _memoryPool(pool) {} : base_type(data), _pool(pool) {}
operator VariantRef() { operator VariantRef() {
return VariantRef(_memoryPool, getVariantData(_data)); return VariantRef(_pool, reinterpret_cast<VariantData*>(_data));
} }
operator ArrayConstRef() const { operator ArrayConstRef() const {
@ -110,12 +108,12 @@ class ArrayRef : public ArrayRefBase<ArrayData>, public Visitable {
} }
VariantRef add() const { VariantRef add() const {
return VariantRef(_memoryPool, arrayAdd(_data, _memoryPool)); return VariantRef(_pool, arrayAdd(_data, _pool));
} }
FORCE_INLINE iterator begin() const { FORCE_INLINE iterator begin() const {
if (!_data) return iterator(); if (!_data) return iterator();
return iterator(_memoryPool, _data->head); return iterator(_pool, _data->head());
} }
FORCE_INLINE iterator end() const { FORCE_INLINE iterator end() const {
@ -153,7 +151,8 @@ class ArrayRef : public ArrayRefBase<ArrayData>, public Visitable {
// Copy a ArrayRef // Copy a ArrayRef
FORCE_INLINE bool copyFrom(ArrayRef src) const { FORCE_INLINE bool copyFrom(ArrayRef src) const {
return arrayCopy(_data, src._data, _memoryPool); if (!_data || !src._data) return false;
return _data->copyFrom(*src._data, _pool);
} }
// Exports a 1D array // Exports a 1D array
@ -191,30 +190,22 @@ class ArrayRef : public ArrayRefBase<ArrayData>, public Visitable {
// Gets the value at the specified index. // Gets the value at the specified index.
FORCE_INLINE VariantRef get(size_t index) const { FORCE_INLINE VariantRef get(size_t index) const {
return VariantRef(_memoryPool, arrayGet(_data, index)); return VariantRef(_pool, _data ? _data->get(index) : 0);
} }
// Removes element at specified position. // Removes element at specified position.
FORCE_INLINE void remove(iterator it) const { FORCE_INLINE void remove(iterator it) const {
arrayRemove(_data, it.internal()); if (!_data) return;
_data->remove(it.internal());
} }
// Removes element at specified index. // Removes element at specified index.
FORCE_INLINE void remove(size_t index) const { FORCE_INLINE void remove(size_t index) const {
arrayRemove(_data, index); if (!_data) return;
} _data->remove(index);
template <typename Visitor>
FORCE_INLINE void accept(Visitor& visitor) const {
ArrayConstRef(_data).accept(visitor);
} }
private: private:
template <typename TValueRef> MemoryPool* _pool;
FORCE_INLINE bool add_impl(TValueRef value) const {
return add().set(value);
}
MemoryPool* _memoryPool;
}; };
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View 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

View 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

View File

@ -14,63 +14,58 @@
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
template <template <typename, typename> class TDeserializer, template <template <typename, typename> class TDeserializer, typename TReader,
typename TMemoryPool, typename TReader, typename TWriter> typename TWriter>
TDeserializer<TReader, TWriter> makeDeserializer(TMemoryPool &memoryPool, TDeserializer<TReader, TWriter> makeDeserializer(MemoryPool &pool,
TReader reader, TWriter writer, TReader reader, TWriter writer,
uint8_t nestingLimit) { uint8_t nestingLimit) {
return TDeserializer<TReader, TWriter>(memoryPool, reader, writer, return TDeserializer<TReader, TWriter>(pool, reader, writer, nestingLimit);
nestingLimit);
} }
// DeserializationError deserialize(TDocument& doc, TString input); // DeserializationError deserialize(JsonDocument& doc, TString input);
// TDocument = DynamicJsonDocument, StaticJsonDocument
// TString = const std::string&, const String& // TString = const std::string&, const String&
template <template <typename, typename> class TDeserializer, typename TDocument, template <template <typename, typename> class TDeserializer, typename TString>
typename TString>
typename enable_if<!is_array<TString>::value, DeserializationError>::type typename enable_if<!is_array<TString>::value, DeserializationError>::type
deserialize(TDocument &doc, const TString &input) { deserialize(JsonDocument &doc, const TString &input) {
doc.clear();
return makeDeserializer<TDeserializer>( return makeDeserializer<TDeserializer>(
doc.memoryPool(), makeReader(input), doc.memoryPool(), makeReader(input),
makeStringStorage(doc.memoryPool(), input), doc.nestingLimit) makeStringStorage(doc.memoryPool(), input), doc.nestingLimit)
.parse(doc.template to<VariantRef>()); .parse(doc.data());
} }
// //
// DeserializationError deserialize(TDocument& doc, TChar* input); // DeserializationError deserialize(JsonDocument& doc, TChar* input);
// TDocument = DynamicJsonDocument, StaticJsonDocument
// TChar* = char*, const char*, const FlashStringHelper* // TChar* = char*, const char*, const FlashStringHelper*
template <template <typename, typename> class TDeserializer, typename TDocument, template <template <typename, typename> class TDeserializer, typename TChar>
typename TChar> DeserializationError deserialize(JsonDocument &doc, TChar *input) {
DeserializationError deserialize(TDocument &doc, TChar *input) { doc.clear();
return makeDeserializer<TDeserializer>( return makeDeserializer<TDeserializer>(
doc.memoryPool(), makeReader(input), doc.memoryPool(), makeReader(input),
makeStringStorage(doc.memoryPool(), input), doc.nestingLimit) makeStringStorage(doc.memoryPool(), input), doc.nestingLimit)
.parse(doc.template to<VariantRef>()); .parse(doc.data());
} }
// //
// DeserializationError deserialize(TDocument& doc, TChar* input, size_t // DeserializationError deserialize(JsonDocument& doc, TChar* input, size_t
// inputSize); // inputSize);
// TDocument = DynamicJsonDocument, StaticJsonDocument
// TChar* = char*, const char*, const FlashStringHelper* // TChar* = char*, const char*, const FlashStringHelper*
template <template <typename, typename> class TDeserializer, typename TDocument, template <template <typename, typename> class TDeserializer, typename TChar>
typename TChar> DeserializationError deserialize(JsonDocument &doc, TChar *input,
DeserializationError deserialize(TDocument &doc, TChar *input,
size_t inputSize) { size_t inputSize) {
doc.clear();
return makeDeserializer<TDeserializer>( return makeDeserializer<TDeserializer>(
doc.memoryPool(), makeReader(input, inputSize), doc.memoryPool(), makeReader(input, inputSize),
makeStringStorage(doc.memoryPool(), input), doc.nestingLimit) makeStringStorage(doc.memoryPool(), input), doc.nestingLimit)
.parse(doc.template to<VariantRef>()); .parse(doc.data());
} }
// //
// DeserializationError deserialize(TDocument& doc, TStream input); // DeserializationError deserialize(JsonDocument& doc, TStream input);
// TDocument = DynamicJsonDocument, StaticJsonDocument
// TStream = std::istream&, Stream& // TStream = std::istream&, Stream&
template <template <typename, typename> class TDeserializer, typename TDocument, template <template <typename, typename> class TDeserializer, typename TStream>
typename TStream> DeserializationError deserialize(JsonDocument &doc, TStream &input) {
DeserializationError deserialize(TDocument &doc, TStream &input) { doc.clear();
return makeDeserializer<TDeserializer>( return makeDeserializer<TDeserializer>(
doc.memoryPool(), makeReader(input), doc.memoryPool(), makeReader(input),
makeStringStorage(doc.memoryPool(), input), doc.nestingLimit) makeStringStorage(doc.memoryPool(), input), doc.nestingLimit)
.parse(doc.template to<VariantRef>()); .parse(doc.data());
} }
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@ -30,8 +30,8 @@ class JsonDocument : public Visitable {
} }
void clear() { void clear() {
_memoryPool.clear(); _pool.clear();
_rootData.type = JSON_NULL; _data.setNull();
} }
template <typename T> template <typename T>
@ -40,16 +40,11 @@ class JsonDocument : public Visitable {
} }
size_t memoryUsage() const { size_t memoryUsage() const {
return _memoryPool.size(); return _pool.size();
} }
size_t capacity() const { size_t capacity() const {
return _memoryPool.capacity(); return _pool.capacity();
}
// for internal use only
MemoryPool& memoryPool() {
return _memoryPool;
} }
template <typename T> template <typename T>
@ -58,10 +53,18 @@ class JsonDocument : public Visitable {
return getVariant().template to<T>(); return getVariant().template to<T>();
} }
// for internal use only
MemoryPool& memoryPool() {
return _pool;
}
VariantData& data() {
return _data;
}
protected: protected:
JsonDocument(char* buf, size_t capa) JsonDocument(char* buf, size_t capa)
: nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT), : nestingLimit(ARDUINOJSON_DEFAULT_NESTING_LIMIT), _pool(buf, capa) {}
_memoryPool(buf, capa) {}
void copy(const JsonDocument& src) { void copy(const JsonDocument& src) {
nestingLimit = src.nestingLimit; nestingLimit = src.nestingLimit;
@ -70,15 +73,15 @@ class JsonDocument : public Visitable {
private: private:
VariantRef getVariant() { VariantRef getVariant() {
return VariantRef(&_memoryPool, &_rootData); return VariantRef(&_pool, &_data);
} }
VariantConstRef getVariant() const { VariantConstRef getVariant() const {
return VariantConstRef(&_rootData); return VariantConstRef(&_data);
} }
MemoryPool _memoryPool; MemoryPool _pool;
VariantData _rootData; VariantData _data;
}; };
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@ -9,7 +9,7 @@
#include "../Numbers/isFloat.hpp" #include "../Numbers/isFloat.hpp"
#include "../Numbers/isInteger.hpp" #include "../Numbers/isInteger.hpp"
#include "../Polyfills/type_traits.hpp" #include "../Polyfills/type_traits.hpp"
#include "../Variant/VariantRef.hpp" #include "../Variant/VariantData.hpp"
#include "EscapeSequence.hpp" #include "EscapeSequence.hpp"
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
@ -18,26 +18,26 @@ template <typename TReader, typename TStringStorage>
class JsonDeserializer { class JsonDeserializer {
typedef typename remove_reference<TStringStorage>::type::StringBuilder typedef typename remove_reference<TStringStorage>::type::StringBuilder
StringBuilder; StringBuilder;
typedef typename StringBuilder::StringType StringType; typedef const char *StringType;
public: public:
JsonDeserializer(MemoryPool &memoryPool, TReader reader, JsonDeserializer(MemoryPool &pool, TReader reader,
TStringStorage stringStorage, uint8_t nestingLimit) TStringStorage stringStorage, uint8_t nestingLimit)
: _memoryPool(&memoryPool), : _pool(&pool),
_reader(reader), _reader(reader),
_stringStorage(stringStorage), _stringStorage(stringStorage),
_nestingLimit(nestingLimit), _nestingLimit(nestingLimit),
_loaded(false) {} _loaded(false) {}
DeserializationError parse(VariantRef variant) { DeserializationError parse(VariantData &variant) {
DeserializationError err = skipSpacesAndComments(); DeserializationError err = skipSpacesAndComments();
if (err) return err; if (err) return err;
switch (current()) { switch (current()) {
case '[': case '[':
return parseArray(variant); return parseArray(variant.toArray());
case '{': case '{':
return parseObject(variant); return parseObject(variant.toObject());
default: default:
return parseValue(variant); return parseValue(variant);
@ -68,12 +68,9 @@ class JsonDeserializer {
return true; return true;
} }
DeserializationError parseArray(VariantRef variant) { DeserializationError parseArray(CollectionData &array) {
if (_nestingLimit == 0) return DeserializationError::TooDeep; if (_nestingLimit == 0) return DeserializationError::TooDeep;
ArrayRef array = variant.to<ArrayRef>();
if (array.isNull()) return DeserializationError::NoMemory;
// Check opening braket // Check opening braket
if (!eat('[')) return DeserializationError::InvalidInput; if (!eat('[')) return DeserializationError::InvalidInput;
@ -87,12 +84,12 @@ class JsonDeserializer {
// Read each value // Read each value
for (;;) { for (;;) {
// Allocate slot in array // Allocate slot in array
VariantRef value = array.add(); VariantData *value = array.add(_pool);
if (value.isInvalid()) return DeserializationError::NoMemory; if (!value) return DeserializationError::NoMemory;
// 1 - Parse value // 1 - Parse value
_nestingLimit--; _nestingLimit--;
err = parse(value); err = parse(*value);
_nestingLimit++; _nestingLimit++;
if (err) return err; if (err) return err;
@ -106,12 +103,9 @@ class JsonDeserializer {
} }
} }
DeserializationError parseObject(VariantRef variant) { DeserializationError parseObject(CollectionData &object) {
if (_nestingLimit == 0) return DeserializationError::TooDeep; if (_nestingLimit == 0) return DeserializationError::TooDeep;
ObjectRef object = variant.to<ObjectRef>();
if (object.isNull()) return DeserializationError::NoMemory;
// Check opening brace // Check opening brace
if (!eat('{')) return DeserializationError::InvalidInput; if (!eat('{')) return DeserializationError::InvalidInput;
@ -124,23 +118,24 @@ class JsonDeserializer {
// Read each key value pair // Read each key value pair
for (;;) { for (;;) {
// Allocate slot in object
VariantSlot *slot = object.addSlot(_pool);
if (!slot) return DeserializationError::NoMemory;
// Parse key // Parse key
StringType key; StringType key;
err = parseKey(key); err = parseKey(key);
if (err) return err; if (err) return err;
slot->setOwnedKey(key);
// Skip spaces // Skip spaces
err = skipSpacesAndComments(); err = skipSpacesAndComments();
if (err) return err; // Colon if (err) return err; // Colon
if (!eat(':')) return DeserializationError::InvalidInput; if (!eat(':')) return DeserializationError::InvalidInput;
// Allocate slot in object
VariantRef value = object.set(key);
if (value.isInvalid()) return DeserializationError::NoMemory;
// Parse value // Parse value
_nestingLimit--; _nestingLimit--;
err = parse(value); err = parse(*slot->data());
_nestingLimit++; _nestingLimit++;
if (err) return err; if (err) return err;
@ -158,7 +153,7 @@ class JsonDeserializer {
} }
} }
DeserializationError parseValue(VariantRef variant) { DeserializationError parseValue(VariantData &variant) {
if (isQuote(current())) { if (isQuote(current())) {
return parseStringValue(variant); return parseStringValue(variant);
} else { } else {
@ -174,11 +169,11 @@ class JsonDeserializer {
} }
} }
DeserializationError parseStringValue(VariantRef variant) { DeserializationError parseStringValue(VariantData &variant) {
StringType value; StringType value;
DeserializationError err = parseQuotedString(value); DeserializationError err = parseQuotedString(value);
if (err) return err; if (err) return err;
variant.set(value); variant.setOwnedString(value);
return DeserializationError::Ok; return DeserializationError::Ok;
} }
@ -208,7 +203,7 @@ class JsonDeserializer {
} }
result = builder.complete(); result = builder.complete();
if (result.isNull()) return DeserializationError::NoMemory; if (!result) return DeserializationError::NoMemory;
return DeserializationError::Ok; return DeserializationError::Ok;
} }
@ -229,11 +224,11 @@ class JsonDeserializer {
} }
result = builder.complete(); result = builder.complete();
if (result.isNull()) return DeserializationError::NoMemory; if (!result) return DeserializationError::NoMemory;
return DeserializationError::Ok; return DeserializationError::Ok;
} }
DeserializationError parseNumericValue(VariantRef result) { DeserializationError parseNumericValue(VariantData &result) {
char buffer[64]; char buffer[64];
uint8_t n = 0; uint8_t n = 0;
@ -246,13 +241,13 @@ class JsonDeserializer {
buffer[n] = 0; buffer[n] = 0;
if (isInteger(buffer)) { if (isInteger(buffer)) {
result.set(parseInteger<Integer>(buffer)); result.setInteger(parseInteger<Integer>(buffer));
} else if (isFloat(buffer)) { } else if (isFloat(buffer)) {
result.set(parseFloat<Float>(buffer)); result.setFloat(parseFloat<Float>(buffer));
} else if (!strcmp(buffer, "true")) { } else if (!strcmp(buffer, "true")) {
result.set(true); result.setBoolean(true);
} else if (!strcmp(buffer, "false")) { } else if (!strcmp(buffer, "false")) {
result.set(false); result.setBoolean(false);
} else if (!strcmp(buffer, "null")) { } else if (!strcmp(buffer, "null")) {
// already null // already null
} else { } else {
@ -333,7 +328,7 @@ class JsonDeserializer {
} }
} }
MemoryPool *_memoryPool; MemoryPool *_pool;
TReader _reader; TReader _reader;
TStringStorage _stringStorage; TStringStorage _stringStorage;
uint8_t _nestingLimit; uint8_t _nestingLimit;

View File

@ -20,15 +20,16 @@ class JsonSerializer {
_writer.writeFloat(value); _writer.writeFloat(value);
} }
void visitArray(ArrayConstRef array) { void visitArray(const CollectionData &array) {
_writer.beginArray(); _writer.beginArray();
ArrayConstRef::iterator it = array.begin(); VariantSlot *slot = array.head();
while (it != array.end()) {
it->accept(*this);
++it; while (slot != 0) {
if (it == array.end()) break; slot->data()->accept(*this);
slot = slot->next();
if (slot == 0) break;
_writer.writeComma(); _writer.writeComma();
} }
@ -36,17 +37,18 @@ class JsonSerializer {
_writer.endArray(); _writer.endArray();
} }
void visitObject(ObjectConstRef object) { void visitObject(const CollectionData &object) {
_writer.beginObject(); _writer.beginObject();
ObjectConstRef::iterator it = object.begin(); VariantSlot *slot = object.head();
while (it != object.end()) {
_writer.writeString(it->key());
_writer.writeColon();
it->value().accept(*this);
++it; while (slot != 0) {
if (it == object.end()) break; _writer.writeString(slot->key());
_writer.writeColon();
slot->data()->accept(*this);
slot = slot->next();
if (slot == 0) break;
_writer.writeComma(); _writer.writeComma();
} }

View File

@ -6,7 +6,6 @@
#include "../Polyfills/assert.hpp" #include "../Polyfills/assert.hpp"
#include "../Polyfills/mpl/max.hpp" #include "../Polyfills/mpl/max.hpp"
#include "../Strings/StringInMemoryPool.hpp"
#include "../Variant/VariantSlot.hpp" #include "../Variant/VariantSlot.hpp"
#include "Alignment.hpp" #include "Alignment.hpp"
#include "MemoryPool.hpp" #include "MemoryPool.hpp"

View File

@ -4,15 +4,12 @@
#pragma once #pragma once
#include "../Strings/StringInMemoryPool.hpp"
#include "MemoryPool.hpp" #include "MemoryPool.hpp"
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
class StringBuilder { class StringBuilder {
public: public:
typedef StringInMemoryPool StringType;
explicit StringBuilder(MemoryPool* parent) : _parent(parent), _size(0) { explicit StringBuilder(MemoryPool* parent) : _parent(parent), _size(0) {
_slot = _parent->allocExpandableString(); _slot = _parent->allocExpandableString();
} }
@ -36,7 +33,7 @@ class StringBuilder {
_slot.value[_size++] = c; _slot.value[_size++] = c;
} }
StringType complete() { char* complete() {
append('\0'); append('\0');
if (_slot.value) { if (_slot.value) {
_parent->freezeString(_slot, _size); _parent->freezeString(_slot, _size);

View File

@ -7,7 +7,7 @@
#include "../Deserialization/deserialize.hpp" #include "../Deserialization/deserialize.hpp"
#include "../Memory/MemoryPool.hpp" #include "../Memory/MemoryPool.hpp"
#include "../Polyfills/type_traits.hpp" #include "../Polyfills/type_traits.hpp"
#include "../Variant/VariantRef.hpp" #include "../Variant/VariantData.hpp"
#include "endianess.hpp" #include "endianess.hpp"
#include "ieee754.hpp" #include "ieee754.hpp"
@ -17,27 +17,28 @@ template <typename TReader, typename TStringStorage>
class MsgPackDeserializer { class MsgPackDeserializer {
typedef typename remove_reference<TStringStorage>::type::StringBuilder typedef typename remove_reference<TStringStorage>::type::StringBuilder
StringBuilder; StringBuilder;
typedef typename StringBuilder::StringType StringType; typedef const char *StringType;
public: public:
MsgPackDeserializer(MemoryPool &memoryPool, TReader reader, MsgPackDeserializer(MemoryPool &pool, TReader reader,
TStringStorage stringStorage, uint8_t nestingLimit) TStringStorage stringStorage, uint8_t nestingLimit)
: _memoryPool(&memoryPool), : _pool(&pool),
_reader(reader), _reader(reader),
_stringStorage(stringStorage), _stringStorage(stringStorage),
_nestingLimit(nestingLimit) {} _nestingLimit(nestingLimit) {}
DeserializationError parse(VariantRef variant) { DeserializationError parse(VariantData &variant) {
uint8_t code; uint8_t code;
if (!readByte(code)) return DeserializationError::IncompleteInput; if (!readByte(code)) return DeserializationError::IncompleteInput;
if ((code & 0x80) == 0) { if ((code & 0x80) == 0) {
variant.set(code); variant.setUnsignedInteger(code);
return DeserializationError::Ok; return DeserializationError::Ok;
} }
if ((code & 0xe0) == 0xe0) { if ((code & 0xe0) == 0xe0) {
variant.set(static_cast<int8_t>(code)); // TODO: add setNegativeInteger()
variant.setSignedInteger(static_cast<int8_t>(code));
return DeserializationError::Ok; return DeserializationError::Ok;
} }
@ -45,9 +46,13 @@ class MsgPackDeserializer {
return readString(variant, code & 0x1f); return readString(variant, code & 0x1f);
} }
if ((code & 0xf0) == 0x90) return readArray(variant, code & 0x0F); if ((code & 0xf0) == 0x90) {
return readArray(variant.toArray(), code & 0x0F);
}
if ((code & 0xf0) == 0x80) return readObject(variant, code & 0x0F); if ((code & 0xf0) == 0x80) {
return readObject(variant.toObject(), code & 0x0F);
}
switch (code) { switch (code) {
case 0xc0: case 0xc0:
@ -55,11 +60,11 @@ class MsgPackDeserializer {
return DeserializationError::Ok; return DeserializationError::Ok;
case 0xc2: case 0xc2:
variant.set(false); variant.setBoolean(false);
return DeserializationError::Ok; return DeserializationError::Ok;
case 0xc3: case 0xc3:
variant.set(true); variant.setBoolean(true);
return DeserializationError::Ok; return DeserializationError::Ok;
case 0xcc: case 0xcc:
@ -112,16 +117,16 @@ class MsgPackDeserializer {
return readString<uint32_t>(variant); return readString<uint32_t>(variant);
case 0xdc: case 0xdc:
return readArray<uint16_t>(variant); return readArray<uint16_t>(variant.toArray());
case 0xdd: case 0xdd:
return readArray<uint32_t>(variant); return readArray<uint32_t>(variant.toArray());
case 0xde: case 0xde:
return readObject<uint16_t>(variant); return readObject<uint16_t>(variant.toObject());
case 0xdf: case 0xdf:
return readObject<uint32_t>(variant); return readObject<uint32_t>(variant.toObject());
default: default:
return DeserializationError::NotSupported; return DeserializationError::NotSupported;
@ -174,48 +179,48 @@ class MsgPackDeserializer {
} }
template <typename T> template <typename T>
DeserializationError readInteger(VariantRef variant) { DeserializationError readInteger(VariantData &variant) {
T value; T value;
if (!readInteger(value)) return DeserializationError::IncompleteInput; if (!readInteger(value)) return DeserializationError::IncompleteInput;
variant.set(value); variant.setInteger(value);
return DeserializationError::Ok; return DeserializationError::Ok;
} }
template <typename T> template <typename T>
typename enable_if<sizeof(T) == 4, DeserializationError>::type readFloat( typename enable_if<sizeof(T) == 4, DeserializationError>::type readFloat(
VariantRef variant) { VariantData &variant) {
T value; T value;
if (!readBytes(value)) return DeserializationError::IncompleteInput; if (!readBytes(value)) return DeserializationError::IncompleteInput;
fixEndianess(value); fixEndianess(value);
variant.set(value); variant.setFloat(value);
return DeserializationError::Ok; return DeserializationError::Ok;
} }
template <typename T> template <typename T>
typename enable_if<sizeof(T) == 8, DeserializationError>::type readDouble( typename enable_if<sizeof(T) == 8, DeserializationError>::type readDouble(
VariantRef variant) { VariantData &variant) {
T value; T value;
if (!readBytes(value)) return DeserializationError::IncompleteInput; if (!readBytes(value)) return DeserializationError::IncompleteInput;
fixEndianess(value); fixEndianess(value);
variant.set(value); variant.setFloat(value);
return DeserializationError::Ok; return DeserializationError::Ok;
} }
template <typename T> template <typename T>
typename enable_if<sizeof(T) == 4, DeserializationError>::type readDouble( typename enable_if<sizeof(T) == 4, DeserializationError>::type readDouble(
VariantRef variant) { VariantData &variant) {
uint8_t i[8]; // input is 8 bytes uint8_t i[8]; // input is 8 bytes
T value; // output is 4 bytes T value; // output is 4 bytes
uint8_t *o = reinterpret_cast<uint8_t *>(&value); uint8_t *o = reinterpret_cast<uint8_t *>(&value);
if (!readBytes(i, 8)) return DeserializationError::IncompleteInput; if (!readBytes(i, 8)) return DeserializationError::IncompleteInput;
doubleToFloat(i, o); doubleToFloat(i, o);
fixEndianess(value); fixEndianess(value);
variant.set(value); variant.setFloat(value);
return DeserializationError::Ok; return DeserializationError::Ok;
} }
template <typename T> template <typename T>
DeserializationError readString(VariantRef variant) { DeserializationError readString(VariantData &variant) {
T size; T size;
if (!readInteger(size)) return DeserializationError::IncompleteInput; if (!readInteger(size)) return DeserializationError::IncompleteInput;
return readString(variant, size); return readString(variant, size);
@ -228,46 +233,40 @@ class MsgPackDeserializer {
return readString(str, size); return readString(str, size);
} }
DeserializationError readString(VariantRef variant, size_t n) { DeserializationError readString(VariantData &variant, size_t n) {
StringType s; StringType s;
DeserializationError err = readString(s, n); DeserializationError err = readString(s, n);
if (!err) variant.set(s); if (!err) variant.setOwnedString(s);
return err; return err;
} }
DeserializationError readString(StringType &s, size_t n) { DeserializationError readString(StringType &result, size_t n) {
StringBuilder builder = _stringStorage.startString(); StringBuilder builder = _stringStorage.startString();
for (; n; --n) { for (; n; --n) {
uint8_t c; uint8_t c;
if (!readBytes(c)) return DeserializationError::IncompleteInput; if (!readBytes(c)) return DeserializationError::IncompleteInput;
builder.append(static_cast<char>(c)); builder.append(static_cast<char>(c));
} }
s = builder.complete(); result = builder.complete();
if (s.isNull()) return DeserializationError::NoMemory; if (!result) return DeserializationError::NoMemory;
return DeserializationError::Ok; return DeserializationError::Ok;
} }
template <typename TSize> template <typename TSize>
DeserializationError readArray(VariantRef variant) { DeserializationError readArray(CollectionData &array) {
TSize size; TSize size;
if (!readInteger(size)) return DeserializationError::IncompleteInput; if (!readInteger(size)) return DeserializationError::IncompleteInput;
return readArray(variant, size); return readArray(array, size);
} }
DeserializationError readArray(VariantRef variant, size_t n) { DeserializationError readArray(CollectionData &array, size_t n) {
ArrayRef array = variant.to<ArrayRef>();
if (array.isNull()) return DeserializationError::NoMemory;
return readArray(array, n);
}
DeserializationError readArray(ArrayRef array, size_t n) {
if (_nestingLimit == 0) return DeserializationError::TooDeep; if (_nestingLimit == 0) return DeserializationError::TooDeep;
--_nestingLimit; --_nestingLimit;
for (; n; --n) { for (; n; --n) {
VariantRef value = array.add(); VariantData *value = array.add(_pool);
if (value.isInvalid()) return DeserializationError::NoMemory; if (!value) return DeserializationError::NoMemory;
DeserializationError err = parse(value); DeserializationError err = parse(*value);
if (err) return err; if (err) return err;
} }
++_nestingLimit; ++_nestingLimit;
@ -275,31 +274,25 @@ class MsgPackDeserializer {
} }
template <typename TSize> template <typename TSize>
DeserializationError readObject(VariantRef variant) { DeserializationError readObject(CollectionData &object) {
TSize size; TSize size;
if (!readInteger(size)) return DeserializationError::IncompleteInput; if (!readInteger(size)) return DeserializationError::IncompleteInput;
return readObject(variant, size); return readObject(object, size);
} }
DeserializationError readObject(VariantRef variant, size_t n) { DeserializationError readObject(CollectionData &object, size_t n) {
ObjectRef object = variant.to<ObjectRef>();
if (object.isNull()) return DeserializationError::NoMemory;
return readObject(object, n);
}
DeserializationError readObject(ObjectRef object, size_t n) {
if (_nestingLimit == 0) return DeserializationError::TooDeep; if (_nestingLimit == 0) return DeserializationError::TooDeep;
--_nestingLimit; --_nestingLimit;
for (; n; --n) { for (; n; --n) {
VariantSlot *slot = object.addSlot(_pool);
if (!slot) return DeserializationError::NoMemory;
StringType key; StringType key;
DeserializationError err = parseKey(key); DeserializationError err = parseKey(key);
if (err) return err; if (err) return err;
slot->setOwnedKey(key);
VariantRef value = object.set(key); err = parse(*slot->data());
if (value.isInvalid()) return DeserializationError::NoMemory;
err = parse(value);
if (err) return err; if (err) return err;
} }
++_nestingLimit; ++_nestingLimit;
@ -327,7 +320,7 @@ class MsgPackDeserializer {
} }
} }
MemoryPool *_memoryPool; MemoryPool *_pool;
TReader _reader; TReader _reader;
TStringStorage _stringStorage; TStringStorage _stringStorage;
uint8_t _nestingLimit; uint8_t _nestingLimit;

View File

@ -7,7 +7,7 @@
#include "../Polyfills/type_traits.hpp" #include "../Polyfills/type_traits.hpp"
#include "../Serialization/measure.hpp" #include "../Serialization/measure.hpp"
#include "../Serialization/serialize.hpp" #include "../Serialization/serialize.hpp"
#include "../Variant/VariantRef.hpp" #include "../Variant/VariantData.hpp"
#include "endianess.hpp" #include "endianess.hpp"
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
@ -35,7 +35,7 @@ class MsgPackSerializer {
} }
} }
void visitArray(ArrayConstRef array) { void visitArray(const CollectionData& array) {
size_t n = array.size(); size_t n = array.size();
if (n < 0x10) { if (n < 0x10) {
writeByte(uint8_t(0x90 + array.size())); writeByte(uint8_t(0x90 + array.size()));
@ -46,12 +46,12 @@ class MsgPackSerializer {
writeByte(0xDD); writeByte(0xDD);
writeInteger(uint32_t(n)); writeInteger(uint32_t(n));
} }
for (ArrayConstRef::iterator it = array.begin(); it != array.end(); ++it) { for (VariantSlot* slot = array.head(); slot; slot = slot->next()) {
it->accept(*this); slot->data()->accept(*this);
} }
} }
void visitObject(ObjectConstRef object) { void visitObject(const CollectionData& object) {
size_t n = object.size(); size_t n = object.size();
if (n < 0x10) { if (n < 0x10) {
writeByte(uint8_t(0x80 + n)); writeByte(uint8_t(0x80 + n));
@ -62,10 +62,9 @@ class MsgPackSerializer {
writeByte(0xDF); writeByte(0xDF);
writeInteger(uint32_t(n)); writeInteger(uint32_t(n));
} }
for (ObjectConstRef::iterator it = object.begin(); it != object.end(); for (VariantSlot* slot = object.head(); slot; slot = slot->next()) {
++it) { visitString(slot->key());
visitString(it->key()); slot->data()->accept(*this);
it->value().accept(*this);
} }
} }

View File

@ -15,7 +15,7 @@ class Key {
} }
const char* c_str() const { const char* c_str() const {
return _slot ? slotGetKey(_slot) : 0; return _slot ? _slot->key() : 0;
} }
bool isNull() const { bool isNull() const {

View File

@ -4,116 +4,52 @@
#pragma once #pragma once
#include "../Memory/MemoryPool.hpp" #include "../Collection/CollectionData.hpp"
#include "../Variant/SlotFunctions.hpp"
#include "../Variant/VariantData.hpp"
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
template <typename Visitor>
void objectAccept(const CollectionData *obj, Visitor &visitor) {
if (obj)
visitor.visitObject(*obj);
else
visitor.visitNull();
}
template <typename TKey> template <typename TKey>
inline VariantSlot* objectFindSlot(const ObjectData* obj, TKey key) { inline bool objectContainsKey(const CollectionData *obj, TKey key) {
return obj && obj->containsKey(key);
}
inline bool objectEquals(const CollectionData *lhs, const CollectionData *rhs) {
if (lhs == rhs) return true;
if (!lhs || !rhs) return false;
return lhs->equalsObject(*rhs);
}
template <typename TKey>
inline VariantData *objectGet(const CollectionData *obj, TKey key) {
if (!obj) return 0; if (!obj) return 0;
VariantSlot* slot = obj->head; return obj->get(key);
while (slot) {
if (key.equals(slotGetKey(slot))) break;
slot = slot->getNext();
}
return slot;
} }
template <typename TKey> template <typename TKey>
inline bool objectContainsKey(const ObjectData* obj, const TKey& key) { void objectRemove(CollectionData *obj, TKey key) {
return objectFindSlot(obj, key) != 0; if (!obj) return;
obj->remove(key);
} }
template <typename TKey> template <typename TKey>
inline VariantData* objectAdd(ObjectData* obj, TKey key, MemoryPool* pool) { inline VariantData *objectSet(CollectionData *obj, TKey key, MemoryPool *pool) {
VariantSlot* slot = pool->allocVariant();
if (!slot) return 0;
slot->init();
if (obj->tail) {
slot->attachTo(obj->tail);
obj->tail = slot;
} else {
obj->head = slot;
obj->tail = slot;
}
if (!slotSetKey(slot, key, pool)) return 0;
return slot->getData();
}
template <typename TKey>
inline VariantData* objectSet(ObjectData* obj, TKey key, MemoryPool* pool) {
if (!obj) return 0; if (!obj) return 0;
// ignore null key // ignore null key
if (key.isNull()) return 0; if (key.isNull()) return 0;
// search a matching key // search a matching key
VariantSlot* slot = objectFindSlot(obj, key); VariantData *var = obj->get(key);
if (slot) return slot->getData(); if (var) return var;
return objectAdd(obj, key, pool); return obj->add(key, pool);
}
template <typename TKey>
inline VariantData* objectGet(const ObjectData* obj, TKey key) {
VariantSlot* slot = objectFindSlot(obj, key);
return slot ? slot->getData() : 0;
}
inline void objectClear(ObjectData* obj) {
if (!obj) return;
obj->head = 0;
obj->tail = 0;
}
inline void objectRemove(ObjectData* obj, VariantSlot* slot) {
if (!obj) return;
if (!slot) return;
VariantSlot* prev = slot->getPrev(obj->head);
VariantSlot* next = slot->getNext();
if (prev)
prev->setNext(next);
else
obj->head = next;
if (!next) obj->tail = prev;
}
inline size_t objectSize(const ObjectData* obj) {
if (!obj) return 0;
return slotSize(obj->head);
}
// bool variantCopy(VariantData*, const VariantData*, MemoryPool*);
inline bool objectCopy(ObjectData* dst, const ObjectData* src,
MemoryPool* pool) {
if (!dst || !src) return false;
objectClear(dst);
for (VariantSlot* s = src->head; s; s = s->getNext()) {
VariantData* var;
if (s->ownsKey())
var = objectAdd(dst, ZeroTerminatedRamString(s->key()), pool);
else
var = objectAdd(dst, ZeroTerminatedRamStringConst(s->key()), pool);
if (!variantCopy(var, s->getData(), pool)) return false;
}
return true;
}
inline bool objectEquals(const ObjectData* o1, const ObjectData* o2) {
if (o1 == o2) return true;
if (!o1 || !o2) return false;
for (VariantSlot* s = o1->head; s; s = s->getNext()) {
VariantData* v1 = s->getData();
VariantData* v2 = objectGet(o2, makeString(slotGetKey(s)));
if (!variantEquals(v1, v2)) return false;
}
return true;
} }
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@ -11,8 +11,7 @@ namespace ARDUINOJSON_NAMESPACE {
class PairPtr { class PairPtr {
public: public:
PairPtr(MemoryPool *memoryPool, VariantSlot *slot) PairPtr(MemoryPool *pool, VariantSlot *slot) : _pair(pool, slot) {}
: _pair(memoryPool, slot) {}
const Pair *operator->() const { const Pair *operator->() const {
return &_pair; return &_pair;
@ -30,14 +29,14 @@ class ObjectIterator {
public: public:
ObjectIterator() : _slot(0) {} ObjectIterator() : _slot(0) {}
explicit ObjectIterator(MemoryPool *memoryPool, VariantSlot *slot) explicit ObjectIterator(MemoryPool *pool, VariantSlot *slot)
: _memoryPool(memoryPool), _slot(slot) {} : _pool(pool), _slot(slot) {}
Pair operator*() const { Pair operator*() const {
return Pair(_memoryPool, _slot); return Pair(_pool, _slot);
} }
PairPtr operator->() { PairPtr operator->() {
return PairPtr(_memoryPool, _slot); return PairPtr(_pool, _slot);
} }
bool operator==(const ObjectIterator &other) const { bool operator==(const ObjectIterator &other) const {
@ -49,12 +48,12 @@ class ObjectIterator {
} }
ObjectIterator &operator++() { ObjectIterator &operator++() {
_slot = _slot->getNext(); _slot = _slot->next();
return *this; return *this;
} }
ObjectIterator &operator+=(size_t distance) { ObjectIterator &operator+=(size_t distance) {
_slot = _slot->getNext(distance); _slot = _slot->next(distance);
return *this; return *this;
} }
@ -63,7 +62,7 @@ class ObjectIterator {
} }
private: private:
MemoryPool *_memoryPool; MemoryPool *_pool;
VariantSlot *_slot; VariantSlot *_slot;
}; };
@ -105,12 +104,12 @@ class ObjectConstIterator {
} }
ObjectConstIterator &operator++() { ObjectConstIterator &operator++() {
_slot = _slot->getNext(); _slot = _slot->next();
return *this; return *this;
} }
ObjectConstIterator &operator+=(size_t distance) { ObjectConstIterator &operator+=(size_t distance) {
_slot = _slot->getNext(distance); _slot = _slot->next(distance);
return *this; return *this;
} }

View File

@ -17,6 +17,11 @@ namespace ARDUINOJSON_NAMESPACE {
template <typename TData> template <typename TData>
class ObjectRefBase { class ObjectRefBase {
public: public:
template <typename Visitor>
FORCE_INLINE void accept(Visitor& visitor) const {
objectAccept(_data, visitor);
}
// Tells weither the specified key is present and associated with a value. // Tells weither the specified key is present and associated with a value.
// //
// bool containsKey(TKey); // bool containsKey(TKey);
@ -38,7 +43,7 @@ class ObjectRefBase {
} }
FORCE_INLINE size_t size() const { FORCE_INLINE size_t size() const {
return objectSize(_data); return _data ? _data->size() : 0;
} }
protected: protected:
@ -46,28 +51,20 @@ class ObjectRefBase {
TData* _data; TData* _data;
}; };
class ObjectConstRef : public ObjectRefBase<const ObjectData>, class ObjectConstRef : public ObjectRefBase<const CollectionData>,
public Visitable { public Visitable {
friend class ObjectRef; friend class ObjectRef;
typedef ObjectRefBase<const ObjectData> base_type; typedef ObjectRefBase<const CollectionData> base_type;
public: public:
typedef ObjectConstIterator iterator; typedef ObjectConstIterator iterator;
ObjectConstRef() : base_type(0) {} ObjectConstRef() : base_type(0) {}
ObjectConstRef(const ObjectData* data) : base_type(data) {} ObjectConstRef(const CollectionData* data) : base_type(data) {}
template <typename Visitor>
FORCE_INLINE void accept(Visitor& visitor) const {
if (_data)
visitor.visitObject(*this);
else
visitor.visitNull();
}
FORCE_INLINE iterator begin() const { FORCE_INLINE iterator begin() const {
if (!_data) return iterator(); if (!_data) return iterator();
return iterator(_data->head); return iterator(_data->head());
} }
FORCE_INLINE iterator end() const { FORCE_INLINE iterator end() const {
@ -122,18 +119,18 @@ class ObjectConstRef : public ObjectRefBase<const ObjectData>,
} }
}; };
class ObjectRef : public ObjectRefBase<ObjectData>, public Visitable { class ObjectRef : public ObjectRefBase<CollectionData>, public Visitable {
typedef ObjectRefBase<ObjectData> base_type; typedef ObjectRefBase<CollectionData> base_type;
public: public:
typedef ObjectIterator iterator; typedef ObjectIterator iterator;
FORCE_INLINE ObjectRef() : base_type(0), _memoryPool(0) {} FORCE_INLINE ObjectRef() : base_type(0), _pool(0) {}
FORCE_INLINE ObjectRef(MemoryPool* buf, ObjectData* data) FORCE_INLINE ObjectRef(MemoryPool* buf, CollectionData* data)
: base_type(data), _memoryPool(buf) {} : base_type(data), _pool(buf) {}
operator VariantRef() const { operator VariantRef() const {
return VariantRef(_memoryPool, getVariantData(_data)); return VariantRef(_pool, reinterpret_cast<VariantData*>(_data));
} }
operator ObjectConstRef() const { operator ObjectConstRef() const {
@ -142,7 +139,7 @@ class ObjectRef : public ObjectRefBase<ObjectData>, public Visitable {
FORCE_INLINE iterator begin() const { FORCE_INLINE iterator begin() const {
if (!_data) return iterator(); if (!_data) return iterator();
return iterator(_memoryPool, _data->head); return iterator(_pool, _data->head());
} }
FORCE_INLINE iterator end() const { FORCE_INLINE iterator end() const {
@ -150,11 +147,13 @@ class ObjectRef : public ObjectRefBase<ObjectData>, public Visitable {
} }
void clear() const { void clear() const {
objectClear(_data); if (!_data) return;
_data->clear();
} }
FORCE_INLINE bool copyFrom(ObjectConstRef src) { FORCE_INLINE bool copyFrom(ObjectConstRef src) {
return objectCopy(_data, src._data, _memoryPool); if (!_data || !src._data) return false;
return _data->copyFrom(*src._data, _pool);
} }
// Creates and adds a ArrayRef. // Creates and adds a ArrayRef.
@ -225,7 +224,8 @@ class ObjectRef : public ObjectRefBase<ObjectData>, public Visitable {
} }
FORCE_INLINE void remove(iterator it) const { FORCE_INLINE void remove(iterator it) const {
objectRemove(_data, it.internal()); if (!_data) return;
_data->remove(it.internal());
} }
// Removes the specified key and the associated value. // Removes the specified key and the associated value.
@ -234,14 +234,14 @@ class ObjectRef : public ObjectRefBase<ObjectData>, public Visitable {
// TKey = const std::string&, const String& // TKey = const std::string&, const String&
template <typename TKey> template <typename TKey>
FORCE_INLINE void remove(const TKey& key) const { FORCE_INLINE void remove(const TKey& key) const {
remove_impl(makeString(key)); objectRemove(_data, makeString(key));
} }
// //
// void remove(TKey); // void remove(TKey);
// TKey = char*, const char*, char[], const char[], const FlashStringHelper* // TKey = char*, const char*, char[], const char[], const FlashStringHelper*
template <typename TKey> template <typename TKey>
FORCE_INLINE void remove(TKey* key) const { FORCE_INLINE void remove(TKey* key) const {
remove_impl(makeString(key)); objectRemove(_data, makeString(key));
} }
template <typename TKey> template <typename TKey>
@ -254,35 +254,17 @@ class ObjectRef : public ObjectRefBase<ObjectData>, public Visitable {
return set_impl(makeString(key)); return set_impl(makeString(key));
} }
FORCE_INLINE VariantRef set(StringInMemoryPool key) const {
return set_impl(key);
}
FORCE_INLINE VariantRef set(ZeroTerminatedRamStringConst key) const {
return set_impl(key);
}
template <typename Visitor>
FORCE_INLINE void accept(Visitor& visitor) const {
ObjectConstRef(_data).accept(visitor);
}
private: private:
template <typename TStringRef> template <typename TKey>
FORCE_INLINE VariantRef get_impl(TStringRef key) const { FORCE_INLINE VariantRef get_impl(TKey key) const {
return VariantRef(_memoryPool, objectGet(_data, key)); return VariantRef(_pool, objectGet(_data, key));
} }
template <typename TKey> template <typename TKey>
FORCE_INLINE VariantRef set_impl(TKey key) const { FORCE_INLINE VariantRef set_impl(TKey key) const {
return VariantRef(_memoryPool, objectSet(_data, key, _memoryPool)); return VariantRef(_pool, objectSet(_data, key, _pool));
} }
template <typename TStringRef> MemoryPool* _pool;
FORCE_INLINE void remove_impl(TStringRef key) const {
objectRemove(_data, objectFindSlot(_data, key));
}
MemoryPool* _memoryPool;
}; };
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@ -8,12 +8,12 @@
#include "Key.hpp" #include "Key.hpp"
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
// A key value pair for ObjectData. // A key value pair for CollectionData.
class Pair { class Pair {
public: public:
Pair(MemoryPool* memoryPool, VariantSlot* slot) : _key(slot) { Pair(MemoryPool* pool, VariantSlot* slot) : _key(slot) {
if (slot) { if (slot) {
_value = VariantRef(memoryPool, slot->getData()); _value = VariantRef(pool, slot->data());
} }
} }
@ -34,7 +34,7 @@ class PairConst {
public: public:
PairConst(const VariantSlot* slot) : _key(slot) { PairConst(const VariantSlot* slot) : _key(slot) {
if (slot) { if (slot) {
_value = VariantConstRef(slot->getData()); _value = VariantConstRef(slot->data());
} }
} }

View File

@ -4,6 +4,8 @@
#pragma once #pragma once
#include <stddef.h> // size_t
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
template <typename T> template <typename T>

View File

@ -13,13 +13,13 @@ class StringCopier {
public: public:
typedef ARDUINOJSON_NAMESPACE::StringBuilder StringBuilder; typedef ARDUINOJSON_NAMESPACE::StringBuilder StringBuilder;
StringCopier(MemoryPool* memoryPool) : _memoryPool(memoryPool) {} StringCopier(MemoryPool* pool) : _pool(pool) {}
StringBuilder startString() { StringBuilder startString() {
return StringBuilder(_memoryPool); return StringBuilder(_pool);
} }
private: private:
MemoryPool* _memoryPool; MemoryPool* _pool;
}; };
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@ -10,17 +10,15 @@ class StringMover {
public: public:
class StringBuilder { class StringBuilder {
public: public:
typedef ZeroTerminatedRamStringConst StringType;
StringBuilder(char** ptr) : _writePtr(ptr), _startPtr(*ptr) {} StringBuilder(char** ptr) : _writePtr(ptr), _startPtr(*ptr) {}
void append(char c) { void append(char c) {
*(*_writePtr)++ = char(c); *(*_writePtr)++ = char(c);
} }
StringType complete() const { char* complete() const {
*(*_writePtr)++ = 0; *(*_writePtr)++ = 0;
return reinterpret_cast<const char*>(_startPtr); return _startPtr;
} }
private: private:

View File

@ -12,10 +12,10 @@ class ArduinoString {
public: public:
ArduinoString(const ::String& str) : _str(&str) {} ArduinoString(const ::String& str) : _str(&str) {}
char* save(MemoryPool* memoryPool) const { char* save(MemoryPool* pool) const {
if (isNull()) return NULL; if (isNull()) return NULL;
size_t n = _str->length() + 1; size_t n = _str->length() + 1;
char* dup = memoryPool->allocFrozenString(n); char* dup = pool->allocFrozenString(n);
if (dup) memcpy(dup, _str->c_str(), n); if (dup) memcpy(dup, _str->c_str(), n);
return dup; return dup;
} }

View File

@ -21,9 +21,9 @@ class FixedSizeFlashString {
return !_str; return !_str;
} }
char* save(MemoryPool* memoryPool) const { char* save(MemoryPool* pool) const {
if (!_str) return NULL; if (!_str) return NULL;
char* dup = memoryPool->allocFrozenString(_size); char* dup = pool->allocFrozenString(_size);
if (!dup) memcpy_P(dup, (const char*)_str, _size); if (!dup) memcpy_P(dup, (const char*)_str, _size);
return dup; return dup;
} }

View File

@ -22,10 +22,9 @@ class FixedSizeRamString {
return !_str; return !_str;
} }
template <typename TMemoryPool> char* save(MemoryPool* pool) const {
char* save(TMemoryPool* memoryPool) const {
if (!_str) return NULL; if (!_str) return NULL;
char* dup = memoryPool->allocFrozenString(_size); char* dup = pool->allocFrozenString(_size);
if (dup) memcpy(dup, _str, _size); if (dup) memcpy(dup, _str, _size);
return dup; return dup;
} }

View File

@ -12,9 +12,9 @@ class StlString {
public: public:
StlString(const std::string& str) : _str(&str) {} StlString(const std::string& str) : _str(&str) {}
char* save(MemoryPool* memoryPool) const { char* save(MemoryPool* pool) const {
size_t n = _str->length() + 1; size_t n = _str->length() + 1;
char* dup = memoryPool->allocFrozenString(n); char* dup = pool->allocFrozenString(n);
if (dup) memcpy(dup, _str->c_str(), n); if (dup) memcpy(dup, _str->c_str(), n);
return dup; return dup;
} }

View File

@ -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

View File

@ -4,6 +4,7 @@
#pragma once #pragma once
#include "../Memory/MemoryPool.hpp"
#include "../Polyfills/type_traits.hpp" #include "../Polyfills/type_traits.hpp"
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
@ -18,7 +19,6 @@ struct IsString<T&> : IsString<T> {};
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE
#include "FixedSizeRamString.hpp" #include "FixedSizeRamString.hpp"
#include "StringInMemoryPool.hpp"
#include "ZeroTerminatedRamString.hpp" #include "ZeroTerminatedRamString.hpp"
#include "ZeroTerminatedRamStringConst.hpp" #include "ZeroTerminatedRamStringConst.hpp"

View File

@ -20,10 +20,10 @@ class ZeroTerminatedFlashString {
return !_str; return !_str;
} }
char* save(MemoryPool* memoryPool) const { char* save(MemoryPool* pool) const {
if (!_str) return NULL; if (!_str) return NULL;
size_t n = size() + 1; // copy the terminator size_t n = size() + 1; // copy the terminator
char* dup = memoryPool->allocFrozenString(n); char* dup = pool->allocFrozenString(n);
if (dup) memcpy_P(dup, reinterpret_cast<const char*>(_str), n); if (dup) memcpy_P(dup, reinterpret_cast<const char*>(_str), n);
return dup; return dup;
} }

View File

@ -13,11 +13,10 @@ class ZeroTerminatedRamString : public ZeroTerminatedRamStringConst {
ZeroTerminatedRamString(const char* str) ZeroTerminatedRamString(const char* str)
: ZeroTerminatedRamStringConst(str) {} : ZeroTerminatedRamStringConst(str) {}
template <typename TMemoryPool> char* save(MemoryPool* pool) const {
char* save(TMemoryPool* memoryPool) const {
if (!_str) return NULL; if (!_str) return NULL;
size_t n = size() + 1; size_t n = size() + 1;
char* dup = memoryPool->allocFrozenString(n); char* dup = pool->allocFrozenString(n);
if (dup) memcpy(dup, _str, n); if (dup) memcpy(dup, _str, n);
return dup; return dup;
} }

View File

@ -13,32 +13,25 @@ namespace ARDUINOJSON_NAMESPACE {
template <typename TKey> template <typename TKey>
inline bool slotSetKey(VariantSlot* var, TKey key, MemoryPool* pool) { inline bool slotSetKey(VariantSlot* var, TKey key, MemoryPool* pool) {
if (!var) return false;
char* dup = key.save(pool); char* dup = key.save(pool);
if (!dup) return false; if (!dup) return false;
var->setKey(dup, true); var->setOwnedKey(dup);
return true; return true;
} }
inline bool slotSetKey(VariantSlot* var, ZeroTerminatedRamStringConst key, inline bool slotSetKey(VariantSlot* var, ZeroTerminatedRamStringConst key,
MemoryPool*) { MemoryPool*) {
var->setKey(key.c_str(), false); if (!var) return false;
var->setLinkedKey(key.c_str());
return true; return true;
} }
inline bool slotSetKey(VariantSlot* var, StringInMemoryPool key, MemoryPool*) {
var->setKey(key.c_str(), true);
return true;
}
inline const char* slotGetKey(const VariantSlot* var) {
return var->key();
}
inline size_t slotSize(const VariantSlot* var) { inline size_t slotSize(const VariantSlot* var) {
size_t n = 0; size_t n = 0;
while (var) { while (var) {
n++; n++;
var = var->getNext(); var = var->next();
} }
return n; return n;
} }

View File

@ -5,7 +5,6 @@
#pragma once #pragma once
#include "../Serialization/DynamicStringWriter.hpp" #include "../Serialization/DynamicStringWriter.hpp"
#include "VariantFunctions.hpp"
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
@ -55,19 +54,19 @@ struct VariantConstAs<ArrayRef> {
template <typename T> template <typename T>
inline typename enable_if<is_integral<T>::value, T>::type variantAs( inline typename enable_if<is_integral<T>::value, T>::type variantAs(
const VariantData* _data) { const VariantData* _data) {
return variantAsIntegral<T>(_data); return _data != 0 ? _data->asIntegral<T>() : T(0);
} }
template <typename T> template <typename T>
inline typename enable_if<is_same<T, bool>::value, T>::type variantAs( inline typename enable_if<is_same<T, bool>::value, T>::type variantAs(
const VariantData* _data) { const VariantData* _data) {
return variantAsBoolean(_data); return _data != 0 ? _data->asBoolean() : false;
} }
template <typename T> template <typename T>
inline typename enable_if<is_floating_point<T>::value, T>::type variantAs( inline typename enable_if<is_floating_point<T>::value, T>::type variantAs(
const VariantData* _data) { const VariantData* _data) {
return variantAsFloat<T>(_data); return _data != 0 ? _data->asFloat<T>() : T(0);
} }
template <typename T> template <typename T>
@ -75,7 +74,7 @@ inline typename enable_if<is_same<T, const char*>::value ||
is_same<T, char*>::value, is_same<T, char*>::value,
const char*>::type const char*>::type
variantAs(const VariantData* _data) { variantAs(const VariantData* _data) {
return variantAsString(_data); return _data != 0 ? _data->asString() : 0;
} }
template <typename T> template <typename T>

View File

@ -5,7 +5,6 @@
#pragma once #pragma once
#include "../Serialization/DynamicStringWriter.hpp" #include "../Serialization/DynamicStringWriter.hpp"
#include "VariantFunctions.hpp"
#include "VariantRef.hpp" #include "VariantRef.hpp"
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
@ -19,7 +18,7 @@ variantAs(const VariantData* _data) {
template <typename T> template <typename T>
inline typename enable_if<IsWriteableString<T>::value, T>::type variantAs( inline typename enable_if<IsWriteableString<T>::value, T>::type variantAs(
const VariantData* _data) { const VariantData* _data) {
const char* cstr = variantAsString(_data); const char* cstr = _data != 0 ? _data->asString() : 0;
if (cstr) return T(cstr); if (cstr) return T(cstr);
T s; T s;
serializeJson(VariantConstRef(_data), s); serializeJson(VariantConstRef(_data), s);

View 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

View File

@ -4,78 +4,285 @@
#pragma once #pragma once
#include <stddef.h> // ptrdiff_t, size_t #include "../Misc/SerializedValue.hpp"
#include "VariantContent.hpp"
#include "../Numbers/Float.hpp"
#include "../Numbers/Integer.hpp"
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
class VariantSlot; class VariantData {
VariantContent _content; // must be first to allow cast from array to variant
uint8_t _flags;
enum VariantType { public:
JSON_NULL, // Must be a POD!
JSON_LINKED_RAW, // - no constructor
JSON_OWNED_RAW, // - no destructor
JSON_LINKED_STRING, // - no virtual
JSON_OWNED_STRING, // - no inheritance
JSON_BOOLEAN,
JSON_POSITIVE_INTEGER, template <typename Visitor>
JSON_NEGATIVE_INTEGER, void accept(Visitor &visitor) const {
JSON_ARRAY, switch (type()) {
JSON_OBJECT, case VALUE_IS_FLOAT:
JSON_FLOAT return visitor.visitFloat(_content.asFloat);
case VALUE_IS_ARRAY:
return visitor.visitArray(_content.asCollection);
case VALUE_IS_OBJECT:
return visitor.visitObject(_content.asCollection);
case VALUE_IS_LINKED_STRING:
case VALUE_IS_OWNED_STRING:
return visitor.visitString(_content.asString);
case VALUE_IS_OWNED_RAW:
case VALUE_IS_LINKED_RAW:
return visitor.visitRawJson(_content.asRaw.data, _content.asRaw.size);
case VALUE_IS_NEGATIVE_INTEGER:
return visitor.visitNegativeInteger(_content.asInteger);
case VALUE_IS_POSITIVE_INTEGER:
return visitor.visitPositiveInteger(_content.asInteger);
case VALUE_IS_BOOLEAN:
return visitor.visitBoolean(_content.asInteger != 0);
default:
return visitor.visitNull();
}
}
template <typename T>
T asIntegral() const;
template <typename T>
T asFloat() const;
const char *asString() const;
bool asBoolean() const {
return asIntegral<int>() != 0;
}
CollectionData *asArray() {
if (type() == VALUE_IS_ARRAY)
return &_content.asCollection;
else
return 0;
}
const CollectionData *asArray() const {
return const_cast<VariantData *>(this)->asArray();
}
CollectionData *asObject() {
if (type() == VALUE_IS_OBJECT)
return &_content.asCollection;
else
return 0;
}
const CollectionData *asObject() const {
return const_cast<VariantData *>(this)->asObject();
}
bool copyFrom(const VariantData &src, MemoryPool *pool) {
switch (src.type()) {
case VALUE_IS_ARRAY:
return toArray().copyFrom(src._content.asCollection, pool);
case VALUE_IS_OBJECT:
return toObject().copyFrom(src._content.asCollection, pool);
case VALUE_IS_OWNED_STRING:
return setOwnedString(ZeroTerminatedRamString(src._content.asString),
pool);
case VALUE_IS_OWNED_RAW:
return setOwnedRaw(
serialized(src._content.asRaw.data, src._content.asRaw.size), pool);
default:
setType(src.type());
_content = src._content;
return true;
}
}
bool equals(const VariantData &other) const {
if (type() != other.type()) return false;
switch (type()) {
case VALUE_IS_LINKED_STRING:
case VALUE_IS_OWNED_STRING:
return !strcmp(_content.asString, other._content.asString);
case VALUE_IS_LINKED_RAW:
case VALUE_IS_OWNED_RAW:
return _content.asRaw.size == other._content.asRaw.size &&
!memcmp(_content.asRaw.data, other._content.asRaw.data,
_content.asRaw.size);
case VALUE_IS_BOOLEAN:
case VALUE_IS_POSITIVE_INTEGER:
case VALUE_IS_NEGATIVE_INTEGER:
return _content.asInteger == other._content.asInteger;
case VALUE_IS_ARRAY:
return _content.asCollection.equalsArray(other._content.asCollection);
case VALUE_IS_OBJECT:
return _content.asCollection.equalsObject(other._content.asCollection);
case VALUE_IS_FLOAT:
return _content.asFloat == other._content.asFloat;
case VALUE_IS_NULL:
default:
return true;
}
}
bool isArray() const {
return type() == VALUE_IS_ARRAY;
}
bool isBoolean() const {
return type() == VALUE_IS_BOOLEAN;
}
bool isInteger() const {
return type() == VALUE_IS_POSITIVE_INTEGER ||
type() == VALUE_IS_NEGATIVE_INTEGER;
}
bool isFloat() const {
return type() == VALUE_IS_FLOAT || type() == VALUE_IS_POSITIVE_INTEGER ||
type() == VALUE_IS_NEGATIVE_INTEGER;
}
bool isString() const {
return (type() == VALUE_IS_LINKED_STRING ||
type() == VALUE_IS_OWNED_STRING);
}
bool isObject() const {
return type() == VALUE_IS_OBJECT;
}
bool isNull() const {
return type() == VALUE_IS_NULL;
}
void setBoolean(bool value) {
setType(VALUE_IS_BOOLEAN);
_content.asInteger = static_cast<UInt>(value);
}
void setFloat(Float value) {
setType(VALUE_IS_FLOAT);
_content.asFloat = value;
}
void setLinkedRaw(SerializedValue<const char *> value) {
setType(VALUE_IS_LINKED_RAW);
_content.asRaw.data = value.data();
_content.asRaw.size = value.size();
}
template <typename T>
bool setOwnedRaw(SerializedValue<T> value, MemoryPool *pool) {
char *dup = makeString(value.data(), value.size()).save(pool);
if (dup) {
setType(VALUE_IS_OWNED_RAW);
_content.asRaw.data = dup;
_content.asRaw.size = value.size();
return true;
} else {
setType(VALUE_IS_NULL);
return false;
}
}
template <typename T>
typename enable_if<is_unsigned<T>::value>::type setInteger(T value) {
setUnsignedInteger(value);
}
template <typename T>
typename enable_if<is_signed<T>::value>::type setInteger(T value) {
setSignedInteger(value);
}
template <typename T>
void setSignedInteger(T value) {
if (value >= 0) {
setType(VALUE_IS_POSITIVE_INTEGER);
_content.asInteger = static_cast<UInt>(value);
} else {
setType(VALUE_IS_NEGATIVE_INTEGER);
_content.asInteger = ~static_cast<UInt>(value) + 1;
}
}
void setLinkedString(const char *value) {
setType(VALUE_IS_LINKED_STRING);
_content.asString = value;
}
void setNull() {
setType(VALUE_IS_NULL);
}
void setOwnedString(const char *s) {
setType(VALUE_IS_OWNED_STRING);
_content.asString = s;
}
template <typename T>
bool setOwnedString(T value, MemoryPool *pool) {
char *dup = value.save(pool);
if (dup) {
setType(VALUE_IS_OWNED_STRING);
_content.asString = dup;
return true;
} else {
setType(VALUE_IS_NULL);
return false;
}
}
void setUnsignedInteger(UInt value) {
setType(VALUE_IS_POSITIVE_INTEGER);
_content.asInteger = static_cast<UInt>(value);
}
CollectionData &toArray() {
setType(VALUE_IS_ARRAY);
_content.asCollection.clear();
return _content.asCollection;
}
CollectionData &toObject() {
setType(VALUE_IS_OBJECT);
_content.asCollection.clear();
return _content.asCollection;
}
size_t size() const {
if (type() == VALUE_IS_OBJECT || type() == VALUE_IS_ARRAY)
return _content.asCollection.size();
else
return 0;
}
private:
uint8_t type() const {
return _flags & VALUE_MASK;
}
void setType(uint8_t t) {
_flags &= KEY_IS_OWNED;
_flags |= t;
}
}; };
struct ObjectData {
VariantSlot *head;
VariantSlot *tail;
};
struct ArrayData {
VariantSlot *head;
VariantSlot *tail;
};
struct RawData {
const char *data;
size_t size;
};
// A union that defines the actual content of a VariantData.
// The enum VariantType determines which member is in use.
union VariantContent {
Float asFloat;
UInt asInteger;
ArrayData asArray;
ObjectData asObject;
const char *asString;
struct {
const char *data;
size_t size;
} asRaw;
};
// this struct must be a POD type to prevent error calling offsetof on clang
struct VariantData {
VariantContent content;
bool keyIsOwned : 1;
VariantType type : 7;
};
inline VariantData *getVariantData(ArrayData *arr) {
const ptrdiff_t offset =
offsetof(VariantData, content) - offsetof(VariantContent, asArray);
if (!arr) return 0;
return reinterpret_cast<VariantData *>(reinterpret_cast<char *>(arr) -
offset);
}
inline VariantData *getVariantData(ObjectData *obj) {
const ptrdiff_t offset =
offsetof(VariantData, content) - offsetof(VariantContent, asObject);
if (!obj) return 0;
return reinterpret_cast<VariantData *>(reinterpret_cast<char *>(obj) -
offset);
}
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@ -4,292 +4,142 @@
#pragma once #pragma once
#include "../Array/ArrayFunctions.hpp"
#include "../Misc/SerializedValue.hpp"
#include "../Numbers/parseFloat.hpp"
#include "../Numbers/parseInteger.hpp"
#include "../Object/ObjectFunctions.hpp"
#include "VariantData.hpp" #include "VariantData.hpp"
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
template <typename T>
inline T variantAsIntegral(const VariantData* var) {
if (!var) return 0;
switch (var->type) {
case JSON_POSITIVE_INTEGER:
case JSON_BOOLEAN:
return T(var->content.asInteger);
case JSON_NEGATIVE_INTEGER:
return T(~var->content.asInteger + 1);
case JSON_LINKED_STRING:
case JSON_OWNED_STRING:
return parseInteger<T>(var->content.asString);
case JSON_FLOAT:
return T(var->content.asFloat);
default:
return 0;
}
}
inline bool variantAsBoolean(const VariantData* var) { template <typename Visitor>
return variantAsIntegral<int>(var) != 0; inline void variantAccept(const VariantData *var, Visitor &visitor) {
} if (var != 0)
var->accept(visitor);
// T = float/double
template <typename T>
inline T variantAsFloat(const VariantData* var) {
if (!var) return 0;
switch (var->type) {
case JSON_POSITIVE_INTEGER:
case JSON_BOOLEAN:
return static_cast<T>(var->content.asInteger);
case JSON_NEGATIVE_INTEGER:
return -static_cast<T>(var->content.asInteger);
case JSON_LINKED_STRING:
case JSON_OWNED_STRING:
return parseFloat<T>(var->content.asString);
case JSON_FLOAT:
return static_cast<T>(var->content.asFloat);
default:
return 0;
}
}
inline const char* variantAsString(const VariantData* var) {
if (!var) return 0;
switch (var->type) {
case JSON_LINKED_STRING:
case JSON_OWNED_STRING:
return var->content.asString;
default:
return 0;
}
}
inline ArrayData* variantAsArray(VariantData* var) {
if (var && var->type == JSON_ARRAY)
return &var->content.asArray;
else else
return 0; visitor.visitNull();
} }
inline const ArrayData* variantAsArray(const VariantData* var) { inline const CollectionData *variantAsObject(const VariantData *var) {
if (var && var->type == JSON_ARRAY) return var != 0 ? var->asObject() : 0;
return &var->content.asArray;
else
return 0;
} }
inline ObjectData* variantAsObject(VariantData* var) { inline CollectionData *variantAsObject(VariantData *var) {
if (var && var->type == JSON_OBJECT) return var != 0 ? var->asObject() : 0;
return &var->content.asObject;
else
return 0;
} }
inline const ObjectData* variantAsObject(const VariantData* var) { inline bool variantCopyFrom(VariantData *dst, const VariantData *src,
if (var && var->type == JSON_OBJECT) MemoryPool *pool) {
return &var->content.asObject;
else
return 0;
}
inline bool variantSetBoolean(VariantData* var, bool value) {
if (!var) return false;
var->type = JSON_BOOLEAN;
var->content.asInteger = static_cast<UInt>(value);
return true;
}
inline bool variantSetFloat(VariantData* var, Float value) {
if (!var) return false;
var->type = JSON_FLOAT;
var->content.asFloat = value;
return true;
}
template <typename T>
inline bool variantSetSignedInteger(VariantData* var, T value) {
if (!var) return false;
if (value >= 0) {
var->type = JSON_POSITIVE_INTEGER;
var->content.asInteger = static_cast<UInt>(value);
} else {
var->type = JSON_NEGATIVE_INTEGER;
var->content.asInteger = ~static_cast<UInt>(value) + 1;
}
return true;
}
inline bool variantSetUnsignedInteger(VariantData* var, UInt value) {
if (!var) return false;
var->type = JSON_POSITIVE_INTEGER;
var->content.asInteger = static_cast<UInt>(value);
return true;
}
inline bool variantSetLinkedRaw(VariantData* var,
SerializedValue<const char*> value) {
if (!var) return false;
var->type = JSON_LINKED_RAW;
var->content.asRaw.data = value.data();
var->content.asRaw.size = value.size();
return true;
}
template <typename T>
inline bool variantSetOwnedRaw(VariantData* var, SerializedValue<T> value,
MemoryPool* pool) {
if (!var) return false;
char* dup = makeString(value.data(), value.size()).save(pool);
if (dup) {
var->type = JSON_OWNED_RAW;
var->content.asRaw.data = dup;
var->content.asRaw.size = value.size();
return true;
} else {
var->type = JSON_NULL;
return false;
}
}
template <typename T>
inline bool variantSetString(VariantData* var, T value, MemoryPool* pool) {
if (!var) return false;
char* dup = value.save(pool);
if (dup) {
var->type = JSON_OWNED_STRING;
var->content.asString = dup;
return true;
} else {
var->type = JSON_NULL;
return false;
}
}
inline bool variantSetOwnedString(VariantData* var, char* s) {
if (!var) return false;
var->type = JSON_OWNED_STRING;
var->content.asString = s;
return true;
}
inline bool variantSetString(VariantData* var, const char* value) {
if (!var) return false;
var->type = JSON_LINKED_STRING;
var->content.asString = value;
return true;
}
inline void variantSetNull(VariantData* var) {
if (!var) return;
var->type = JSON_NULL;
}
inline ArrayData* variantToArray(VariantData* var) {
if (!var) return 0;
var->type = JSON_ARRAY;
var->content.asArray.head = 0;
var->content.asArray.tail = 0;
return &var->content.asArray;
}
inline ObjectData* variantToObject(VariantData* var) {
if (!var) return 0;
var->type = JSON_OBJECT;
var->content.asObject.head = 0;
var->content.asObject.tail = 0;
return &var->content.asObject;
}
inline bool variantCopy(VariantData* dst, const VariantData* src,
MemoryPool* pool) {
if (!dst) return false; if (!dst) return false;
if (!src) { if (!src) {
dst->type = JSON_NULL; dst->setNull();
return true; return true;
} }
switch (src->type) { return dst->copyFrom(*src, pool);
case JSON_ARRAY:
return arrayCopy(variantToArray(dst), &src->content.asArray, pool);
case JSON_OBJECT:
return objectCopy(variantToObject(dst), &src->content.asObject, pool);
case JSON_OWNED_STRING:
return variantSetString(
dst, ZeroTerminatedRamString(src->content.asString), pool);
case JSON_OWNED_RAW:
return variantSetOwnedRaw(
dst, serialized(src->content.asRaw.data, src->content.asRaw.size),
pool);
default:
// caution: don't override keyIsOwned
dst->type = src->type;
dst->content = src->content;
return true;
}
} }
inline bool variantIsInteger(const VariantData* var) { inline bool variantEquals(const VariantData *a, const VariantData *b) {
return var && (var->type == JSON_POSITIVE_INTEGER ||
var->type == JSON_NEGATIVE_INTEGER);
}
inline bool variantIsFloat(const VariantData* var) {
return var &&
(var->type == JSON_FLOAT || var->type == JSON_POSITIVE_INTEGER ||
var->type == JSON_NEGATIVE_INTEGER);
}
inline bool variantIsString(const VariantData* var) {
return var &&
(var->type == JSON_LINKED_STRING || var->type == JSON_OWNED_STRING);
}
inline bool variantIsArray(const VariantData* var) {
return var && var->type == JSON_ARRAY;
}
inline bool variantIsObject(const VariantData* var) {
return var && var->type == JSON_OBJECT;
}
inline bool variantIsNull(const VariantData* var) {
return var == 0 || var->type == JSON_NULL;
}
inline bool variantEquals(const VariantData* a, const VariantData* b) {
if (a == b) return true; if (a == b) return true;
if (!a || !b) return false; if (!a || !b) return false;
if (a->type != b->type) return false; return a->equals(*b);
switch (a->type) {
case JSON_LINKED_STRING:
case JSON_OWNED_STRING:
return !strcmp(a->content.asString, b->content.asString);
case JSON_LINKED_RAW:
case JSON_OWNED_RAW:
return a->content.asRaw.size == b->content.asRaw.size &&
!memcmp(a->content.asRaw.data, b->content.asRaw.data,
a->content.asRaw.size);
case JSON_BOOLEAN:
case JSON_POSITIVE_INTEGER:
case JSON_NEGATIVE_INTEGER:
return a->content.asInteger == b->content.asInteger;
case JSON_ARRAY:
return arrayEquals(&a->content.asArray, &b->content.asArray);
case JSON_OBJECT:
return objectEquals(&a->content.asObject, &b->content.asObject);
case JSON_FLOAT:
return a->content.asFloat == b->content.asFloat;
case JSON_NULL:
default:
return true;
}
} }
inline bool variantIsArray(const VariantData *var) {
return var && var->isArray();
}
inline bool variantIsBoolean(const VariantData *var) {
return var && var->isBoolean();
}
inline bool variantIsInteger(const VariantData *var) {
return var && var->isInteger();
}
inline bool variantIsFloat(const VariantData *var) {
return var && var->isFloat();
}
inline bool variantIsString(const VariantData *var) {
return var && var->isString();
}
inline bool variantIsObject(const VariantData *var) {
return var && var->isObject();
}
inline bool variantIsNull(const VariantData *var) {
return var == 0 || var->isNull();
}
inline bool variantSetBoolean(VariantData *var, bool value) {
if (!var) return false;
var->setBoolean(value);
return true;
}
inline bool variantSetFloat(VariantData *var, Float value) {
if (!var) return false;
var->setFloat(value);
return true;
}
inline bool variantSetLinkedRaw(VariantData *var,
SerializedValue<const char *> value) {
if (!var) return false;
var->setLinkedRaw(value);
return true;
}
template <typename T>
inline bool variantSetOwnedRaw(VariantData *var, SerializedValue<T> value,
MemoryPool *pool) {
return var != 0 && var->setOwnedRaw(value, pool);
}
template <typename T>
inline bool variantSetSignedInteger(VariantData *var, T value) {
if (!var) return false;
var->setSignedInteger(value);
return true;
}
inline bool variantSetLinkedString(VariantData *var, const char *value) {
if (!var) return false;
var->setLinkedString(value);
return true;
}
inline void variantSetNull(VariantData *var) {
if (!var) return;
var->setNull();
}
inline bool variantSetOwnedString(VariantData *var, char *value) {
if (!var) return false;
var->setOwnedString(value);
return true;
}
template <typename T>
inline bool variantSetOwnedString(VariantData *var, T value, MemoryPool *pool) {
return var != 0 && var->setOwnedString(value, pool);
}
inline bool variantSetUnsignedInteger(VariantData *var, UInt value) {
if (!var) return false;
var->setUnsignedInteger(value);
return true;
}
inline size_t variantSize(const VariantData *var) {
return var != 0 ? var->size() : 0;
}
inline CollectionData *variantToArray(VariantData *var) {
if (!var) return 0;
return &var->toArray();
}
inline CollectionData *variantToObject(VariantData *var) {
if (!var) return 0;
return &var->toObject();
}
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@ -13,6 +13,53 @@
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
template <typename T>
inline T VariantData::asIntegral() const {
switch (type()) {
case VALUE_IS_POSITIVE_INTEGER:
case VALUE_IS_BOOLEAN:
return T(_content.asInteger);
case VALUE_IS_NEGATIVE_INTEGER:
return T(~_content.asInteger + 1);
case VALUE_IS_LINKED_STRING:
case VALUE_IS_OWNED_STRING:
return parseInteger<T>(_content.asString);
case VALUE_IS_FLOAT:
return T(_content.asFloat);
default:
return 0;
}
}
// T = float/double
template <typename T>
inline T VariantData::asFloat() const {
switch (type()) {
case VALUE_IS_POSITIVE_INTEGER:
case VALUE_IS_BOOLEAN:
return static_cast<T>(_content.asInteger);
case VALUE_IS_NEGATIVE_INTEGER:
return -static_cast<T>(_content.asInteger);
case VALUE_IS_LINKED_STRING:
case VALUE_IS_OWNED_STRING:
return parseFloat<T>(_content.asString);
case VALUE_IS_FLOAT:
return static_cast<T>(_content.asFloat);
default:
return 0;
}
}
inline const char* VariantData::asString() const {
switch (type()) {
case VALUE_IS_LINKED_STRING:
case VALUE_IS_OWNED_STRING:
return _content.asString;
default:
return 0;
}
}
inline bool VariantRef::set(ArrayRef array) const { inline bool VariantRef::set(ArrayRef array) const {
return to<ArrayRef>().copyFrom(array); return to<ArrayRef>().copyFrom(array);
} }
@ -31,35 +78,35 @@ inline bool VariantRef::set(const ObjectSubscript<TString>& value) const {
} }
inline bool VariantRef::set(VariantConstRef value) const { inline bool VariantRef::set(VariantConstRef value) const {
return variantCopy(_data, value._data, _memoryPool); return variantCopyFrom(_data, value._data, _pool);
} }
inline bool VariantRef::set(VariantRef value) const { inline bool VariantRef::set(VariantRef value) const {
return variantCopy(_data, value._data, _memoryPool); return variantCopyFrom(_data, value._data, _pool);
} }
template <typename T> template <typename T>
inline typename enable_if<is_same<T, ArrayRef>::value, T>::type VariantRef::as() inline typename enable_if<is_same<T, ArrayRef>::value, T>::type VariantRef::as()
const { const {
return ArrayRef(_memoryPool, variantAsArray(_data)); return ArrayRef(_pool, _data != 0 ? _data->asArray() : 0);
} }
template <typename T> template <typename T>
inline typename enable_if<is_same<T, ObjectRef>::value, T>::type inline typename enable_if<is_same<T, ObjectRef>::value, T>::type
VariantRef::as() const { VariantRef::as() const {
return ObjectRef(_memoryPool, variantAsObject(_data)); return ObjectRef(_pool, variantAsObject(_data));
} }
template <typename T> template <typename T>
inline typename enable_if<is_same<T, ArrayRef>::value, ArrayRef>::type inline typename enable_if<is_same<T, ArrayRef>::value, ArrayRef>::type
VariantRef::to() const { VariantRef::to() const {
return ArrayRef(_memoryPool, variantToArray(_data)); return ArrayRef(_pool, variantToArray(_data));
} }
template <typename T> template <typename T>
typename enable_if<is_same<T, ObjectRef>::value, ObjectRef>::type typename enable_if<is_same<T, ObjectRef>::value, ObjectRef>::type
VariantRef::to() const { VariantRef::to() const {
return ObjectRef(_memoryPool, variantToObject(_data)); return ObjectRef(_pool, variantToObject(_data));
} }
template <typename T> template <typename T>
@ -69,50 +116,8 @@ VariantRef::to() const {
return *this; return *this;
} }
template <typename Visitor>
inline void VariantRef::accept(Visitor& visitor) const {
return VariantConstRef(_data).accept(visitor);
}
template <typename Visitor>
inline void VariantConstRef::accept(Visitor& visitor) const {
if (!_data) return visitor.visitNull();
switch (_data->type) {
case JSON_FLOAT:
return visitor.visitFloat(_data->content.asFloat);
case JSON_ARRAY:
return visitor.visitArray(ArrayConstRef(&_data->content.asArray));
case JSON_OBJECT:
return visitor.visitObject(ObjectConstRef(&_data->content.asObject));
case JSON_LINKED_STRING:
case JSON_OWNED_STRING:
return visitor.visitString(_data->content.asString);
case JSON_OWNED_RAW:
case JSON_LINKED_RAW:
return visitor.visitRawJson(_data->content.asRaw.data,
_data->content.asRaw.size);
case JSON_NEGATIVE_INTEGER:
return visitor.visitNegativeInteger(_data->content.asInteger);
case JSON_POSITIVE_INTEGER:
return visitor.visitPositiveInteger(_data->content.asInteger);
case JSON_BOOLEAN:
return visitor.visitBoolean(_data->content.asInteger != 0);
default:
return visitor.visitNull();
}
}
inline VariantConstRef VariantConstRef::operator[](size_t index) const { inline VariantConstRef VariantConstRef::operator[](size_t index) const {
return ArrayConstRef(variantAsArray(_data))[index]; return ArrayConstRef(_data != 0 ? _data->asArray() : 0)[index];
} }
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@ -14,7 +14,6 @@
#include "../Operators/VariantOperators.hpp" #include "../Operators/VariantOperators.hpp"
#include "../Polyfills/type_traits.hpp" #include "../Polyfills/type_traits.hpp"
#include "VariantAs.hpp" #include "VariantAs.hpp"
#include "VariantData.hpp"
#include "VariantFunctions.hpp" #include "VariantFunctions.hpp"
#include "VariantRef.hpp" #include "VariantRef.hpp"
@ -58,7 +57,7 @@ class VariantRefBase {
template <typename T> template <typename T>
FORCE_INLINE typename enable_if<is_same<T, bool>::value, bool>::type is() FORCE_INLINE typename enable_if<is_same<T, bool>::value, bool>::type is()
const { const {
return _data && _data->type == JSON_BOOLEAN; return variantIsBoolean(_data);
} }
// //
// bool is<const char*>() const; // bool is<const char*>() const;
@ -96,13 +95,8 @@ class VariantRefBase {
return variantIsNull(_data); return variantIsNull(_data);
} }
FORCE_INLINE bool isInvalid() const {
return _data == 0;
}
size_t size() const { size_t size() const {
return objectSize(variantAsObject(_data)) + return variantSize(_data);
arraySize(variantAsArray(_data));
} }
protected: protected:
@ -125,11 +119,11 @@ class VariantRef : public VariantRefBase<VariantData>,
public: public:
// Intenal use only // Intenal use only
FORCE_INLINE VariantRef(MemoryPool *memoryPool, VariantData *data) FORCE_INLINE VariantRef(MemoryPool *pool, VariantData *data)
: base_type(data), _memoryPool(memoryPool) {} : base_type(data), _pool(pool) {}
// Creates an uninitialized VariantRef // Creates an uninitialized VariantRef
FORCE_INLINE VariantRef() : base_type(0), _memoryPool(0) {} FORCE_INLINE VariantRef() : base_type(0), _pool(0) {}
// set(bool value) // set(bool value)
FORCE_INLINE bool set(bool value) const { FORCE_INLINE bool set(bool value) const {
@ -180,7 +174,7 @@ class VariantRef : public VariantRefBase<VariantData>,
FORCE_INLINE bool set( FORCE_INLINE bool set(
SerializedValue<T> value, SerializedValue<T> value,
typename enable_if<!is_same<const char *, T>::value>::type * = 0) const { typename enable_if<!is_same<const char *, T>::value>::type * = 0) const {
return variantSetOwnedRaw(_data, value, _memoryPool); return variantSetOwnedRaw(_data, value, _pool);
} }
// set(const std::string&) // set(const std::string&)
@ -189,28 +183,20 @@ class VariantRef : public VariantRefBase<VariantData>,
FORCE_INLINE bool set( FORCE_INLINE bool set(
const T &value, const T &value,
typename enable_if<IsString<T>::value>::type * = 0) const { typename enable_if<IsString<T>::value>::type * = 0) const {
return variantSetString(_data, makeString(value), _memoryPool); return variantSetOwnedString(_data, makeString(value), _pool);
} }
// set(char*) // set(char*)
// set(const __FlashStringHelper*)
template <typename T> template <typename T>
FORCE_INLINE bool set( FORCE_INLINE bool set(
T *value, typename enable_if<IsString<T *>::value>::type * = 0) const { T *value, typename enable_if<IsString<T *>::value>::type * = 0) const {
return variantSetString(_data, makeString(value), _memoryPool); return variantSetOwnedString(_data, makeString(value), _pool);
} }
// set(const char*); // set(const char*);
FORCE_INLINE bool set(const char *value) const { FORCE_INLINE bool set(const char *value) const {
return variantSetString(_data, value); return variantSetLinkedString(_data, value);
}
// for internal use only
FORCE_INLINE bool set(StringInMemoryPool value) const {
return variantSetOwnedString(_data,
value.save(_memoryPool)); // TODO: remove?
}
FORCE_INLINE bool set(ZeroTerminatedRamStringConst value) const {
return variantSetString(_data, value.c_str());
} }
bool set(VariantConstRef value) const; bool set(VariantConstRef value) const;
@ -255,7 +241,9 @@ class VariantRef : public VariantRefBase<VariantData>,
} }
template <typename Visitor> template <typename Visitor>
void accept(Visitor &visitor) const; void accept(Visitor &visitor) const {
variantAccept(_data, visitor);
}
FORCE_INLINE bool operator==(VariantRef lhs) const { FORCE_INLINE bool operator==(VariantRef lhs) const {
return variantEquals(_data, lhs._data); return variantEquals(_data, lhs._data);
@ -281,7 +269,7 @@ class VariantRef : public VariantRefBase<VariantData>,
const; const;
private: private:
MemoryPool *_memoryPool; MemoryPool *_pool;
}; };
class VariantConstRef : public VariantRefBase<const VariantData>, class VariantConstRef : public VariantRefBase<const VariantData>,
@ -296,7 +284,9 @@ class VariantConstRef : public VariantRefBase<const VariantData>,
VariantConstRef(VariantRef var) : base_type(var._data) {} VariantConstRef(VariantRef var) : base_type(var._data) {}
template <typename Visitor> template <typename Visitor>
void accept(Visitor &visitor) const; void accept(Visitor &visitor) const {
variantAccept(_data, visitor);
}
// Get the variant as the specified type. // Get the variant as the specified type.
// //
@ -323,7 +313,8 @@ class VariantConstRef : public VariantRefBase<const VariantData>,
FORCE_INLINE FORCE_INLINE
typename enable_if<IsString<TString *>::value, VariantConstRef>::type typename enable_if<IsString<TString *>::value, VariantConstRef>::type
operator[](TString *key) const { operator[](TString *key) const {
return VariantConstRef(objectGet(variantAsObject(_data), makeString(key))); const CollectionData *obj = variantAsObject(_data);
return VariantConstRef(obj ? obj->get(makeString(key)) : 0);
} }
}; };
} // namespace ARDUINOJSON_NAMESPACE } // namespace ARDUINOJSON_NAMESPACE

View File

@ -5,7 +5,9 @@
#pragma once #pragma once
#include "../Polyfills/type_traits.hpp" #include "../Polyfills/type_traits.hpp"
#include "../Variant/VariantData.hpp" #include "../Variant/VariantContent.hpp"
#include <stdint.h> // int8_t, int16_t
namespace ARDUINOJSON_NAMESPACE { namespace ARDUINOJSON_NAMESPACE {
@ -16,8 +18,7 @@ class VariantSlot {
// we cannot use composition because it adds padding // we cannot use composition because it adds padding
// (+20% on ESP8266 for example) // (+20% on ESP8266 for example)
VariantContent _content; VariantContent _content;
bool _keyIsOwned : 1; uint8_t _flags;
VariantType _type : 7;
VariantSlotDiff _next; VariantSlotDiff _next;
const char* _key; const char* _key;
@ -28,23 +29,23 @@ class VariantSlot {
// - no virtual // - no virtual
// - no inheritance // - no inheritance
VariantData* getData() { VariantData* data() {
return reinterpret_cast<VariantData*>(&_content); return reinterpret_cast<VariantData*>(&_content);
} }
const VariantData* getData() const { const VariantData* data() const {
return reinterpret_cast<const VariantData*>(&_content); return reinterpret_cast<const VariantData*>(&_content);
} }
VariantSlot* getNext() { VariantSlot* next() {
return _next ? this + _next : 0; return _next ? this + _next : 0;
} }
const VariantSlot* getNext() const { const VariantSlot* next() const {
return const_cast<VariantSlot*>(this)->getNext(); return const_cast<VariantSlot*>(this)->next();
} }
VariantSlot* getNext(size_t distance) { VariantSlot* next(size_t distance) {
VariantSlot* slot = this; VariantSlot* slot = this;
while (distance--) { while (distance--) {
if (!slot->_next) return 0; if (!slot->_next) return 0;
@ -53,29 +54,26 @@ class VariantSlot {
return slot; return slot;
} }
VariantSlot* getPrev(VariantSlot* head) { const VariantSlot* next(size_t distance) const {
while (head) { return const_cast<VariantSlot*>(this)->next(distance);
VariantSlot* nxt = head->getNext();
if (nxt == this) return head;
head = nxt;
}
return head;
}
const VariantSlot* getNext(size_t distance) const {
return const_cast<VariantSlot*>(this)->getNext(distance);
} }
void setNext(VariantSlot* slot) { void setNext(VariantSlot* slot) {
_next = VariantSlotDiff(slot ? slot - this : 0); _next = VariantSlotDiff(slot ? slot - this : 0);
} }
void attachTo(VariantSlot* tail) { void setNextNotNull(VariantSlot* slot) {
tail->_next = VariantSlotDiff(this - tail); ARDUINOJSON_ASSERT(slot != 0);
_next = VariantSlotDiff(slot - this);
} }
void setKey(const char* k, bool owned) { void setOwnedKey(const char* k) {
_keyIsOwned = owned; _flags |= KEY_IS_OWNED;
_key = k;
}
void setLinkedKey(const char* k) {
_flags &= VALUE_MASK;
_key = k; _key = k;
} }
@ -84,13 +82,13 @@ class VariantSlot {
} }
bool ownsKey() const { bool ownsKey() const {
return _keyIsOwned; return (_flags & KEY_IS_OWNED) != 0;
} }
void init() { void clear() {
_next = 0; _next = 0;
_type = JSON_NULL; _flags = 0;
_keyIsOwned = false; _key = 0;
} }
}; };

View File

@ -22,7 +22,25 @@ TEST_CASE("JsonArray::operator==()") {
REQUIRE_FALSE(array1c == array2c); REQUIRE_FALSE(array1c == array2c);
} }
SECTION("should return false when arrays differ") { SECTION("should return false when LHS has more elements") {
array1.add(1);
array1.add(2);
array2.add(1);
REQUIRE_FALSE(array1 == array2);
REQUIRE_FALSE(array1c == array2c);
}
SECTION("should return false when RKS has more elements") {
array1.add(1);
array2.add(1);
array2.add(2);
REQUIRE_FALSE(array1 == array2);
REQUIRE_FALSE(array1c == array2c);
}
SECTION("should return true when arrays equal") {
array1.add("coucou"); array1.add("coucou");
array2.add("coucou"); array2.add("coucou");

View File

@ -22,7 +22,25 @@ TEST_CASE("JsonObject::operator==()") {
REQUIRE_FALSE(obj1c == obj2c); REQUIRE_FALSE(obj1c == obj2c);
} }
SECTION("should return false when objs differ") { SECTION("should return false when LHS has more elements") {
obj1["hello"] = "coucou";
obj1["world"] = 666;
obj2["hello"] = "coucou";
REQUIRE_FALSE(obj1 == obj2);
REQUIRE_FALSE(obj1c == obj2c);
}
SECTION("should return false when RKS has more elements") {
obj1["hello"] = "coucou";
obj2["hello"] = "coucou";
obj2["world"] = 666;
REQUIRE_FALSE(obj1 == obj2);
REQUIRE_FALSE(obj1c == obj2c);
}
SECTION("should return true when objs equal") {
obj1["hello"] = "world"; obj1["hello"] = "world";
obj1["anwser"] = 42; obj1["anwser"] = 42;
// insert in different order // insert in different order

View File

@ -12,30 +12,30 @@ static char buffer[4096];
TEST_CASE("StringBuilder") { TEST_CASE("StringBuilder") {
SECTION("Works when buffer is big enough") { SECTION("Works when buffer is big enough") {
MemoryPool memoryPool(buffer, addPadding(JSON_STRING_SIZE(6))); MemoryPool pool(buffer, addPadding(JSON_STRING_SIZE(6)));
StringBuilder str(&memoryPool); StringBuilder str(&pool);
str.append("hello"); str.append("hello");
REQUIRE(str.complete().equals("hello")); REQUIRE(str.complete() == std::string("hello"));
} }
SECTION("Returns null when too small") { SECTION("Returns null when too small") {
MemoryPool memoryPool(buffer, sizeof(void*)); MemoryPool pool(buffer, sizeof(void*));
StringBuilder str(&memoryPool); StringBuilder str(&pool);
str.append("hello world!"); str.append("hello world!");
REQUIRE(str.complete().isNull()); REQUIRE(str.complete() == 0);
} }
SECTION("Increases size of memory pool") { SECTION("Increases size of memory pool") {
MemoryPool memoryPool(buffer, addPadding(JSON_STRING_SIZE(6))); MemoryPool pool(buffer, addPadding(JSON_STRING_SIZE(6)));
StringBuilder str(&memoryPool); StringBuilder str(&pool);
str.append('h'); str.append('h');
str.complete(); str.complete();
REQUIRE(JSON_STRING_SIZE(2) == memoryPool.size()); REQUIRE(JSON_STRING_SIZE(2) == pool.size());
} }
} }

View File

@ -11,21 +11,21 @@ static const size_t poolCapacity = 512;
TEST_CASE("MemoryPool::clear()") { TEST_CASE("MemoryPool::clear()") {
char buffer[poolCapacity]; char buffer[poolCapacity];
MemoryPool memoryPool(buffer, sizeof(buffer)); MemoryPool pool(buffer, sizeof(buffer));
SECTION("Discards allocated variants") { SECTION("Discards allocated variants") {
memoryPool.allocVariant(); pool.allocVariant();
memoryPool.clear(); pool.clear();
REQUIRE(memoryPool.size() == 0); REQUIRE(pool.size() == 0);
} }
SECTION("Discards allocated strings") { SECTION("Discards allocated strings") {
memoryPool.allocFrozenString(10); pool.allocFrozenString(10);
REQUIRE(memoryPool.size() > 0); REQUIRE(pool.size() > 0);
memoryPool.clear(); pool.clear();
REQUIRE(memoryPool.size() == 0); REQUIRE(pool.size() == 0);
} }
} }

View File

@ -11,48 +11,48 @@ char buffer[4096];
TEST_CASE("MemoryPool::capacity()") { TEST_CASE("MemoryPool::capacity()") {
const size_t capacity = 64; const size_t capacity = 64;
MemoryPool memoryPool(buffer, capacity); MemoryPool pool(buffer, capacity);
REQUIRE(capacity == memoryPool.capacity()); REQUIRE(capacity == pool.capacity());
} }
TEST_CASE("MemoryPool::size()") { TEST_CASE("MemoryPool::size()") {
MemoryPool memoryPool(buffer, sizeof(buffer)); MemoryPool pool(buffer, sizeof(buffer));
SECTION("Initial size is 0") { SECTION("Initial size is 0") {
REQUIRE(0 == memoryPool.size()); REQUIRE(0 == pool.size());
} }
SECTION("size() == capacity() after allocExpandableString()") { SECTION("size() == capacity() after allocExpandableString()") {
memoryPool.allocExpandableString(); pool.allocExpandableString();
REQUIRE(memoryPool.size() == memoryPool.capacity()); REQUIRE(pool.size() == pool.capacity());
} }
SECTION("Decreases after freezeString()") { SECTION("Decreases after freezeString()") {
StringSlot a = memoryPool.allocExpandableString(); StringSlot a = pool.allocExpandableString();
memoryPool.freezeString(a, 1); pool.freezeString(a, 1);
REQUIRE(memoryPool.size() == JSON_STRING_SIZE(1)); REQUIRE(pool.size() == JSON_STRING_SIZE(1));
StringSlot b = memoryPool.allocExpandableString(); StringSlot b = pool.allocExpandableString();
memoryPool.freezeString(b, 1); pool.freezeString(b, 1);
REQUIRE(memoryPool.size() == 2 * JSON_STRING_SIZE(1)); REQUIRE(pool.size() == 2 * JSON_STRING_SIZE(1));
} }
SECTION("Increases after allocFrozenString()") { SECTION("Increases after allocFrozenString()") {
memoryPool.allocFrozenString(0); pool.allocFrozenString(0);
REQUIRE(memoryPool.size() == JSON_STRING_SIZE(0)); REQUIRE(pool.size() == JSON_STRING_SIZE(0));
memoryPool.allocFrozenString(0); pool.allocFrozenString(0);
REQUIRE(memoryPool.size() == 2 * JSON_STRING_SIZE(0)); REQUIRE(pool.size() == 2 * JSON_STRING_SIZE(0));
} }
SECTION("Doesn't grow when memory pool is full") { SECTION("Doesn't grow when memory pool is full") {
const size_t variantCount = sizeof(buffer) / sizeof(VariantSlot); const size_t variantCount = sizeof(buffer) / sizeof(VariantSlot);
for (size_t i = 0; i < variantCount; i++) memoryPool.allocVariant(); for (size_t i = 0; i < variantCount; i++) pool.allocVariant();
size_t size = memoryPool.size(); size_t size = pool.size();
memoryPool.allocVariant(); pool.allocVariant();
REQUIRE(size == memoryPool.size()); REQUIRE(size == pool.size());
} }
} }