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.
* Restored the monotonic allocator because the code was getting too big
* Reduced the memory usage
* Reduced the code size
* Removed spurious files in the Particle library
v6.6.0-beta (2018-11-13)

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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