Update to ArduinoJson 7.0.4

This commit is contained in:
iranl
2024-04-19 14:44:01 +02:00
parent 1378732081
commit 81be0a689a
444 changed files with 10842 additions and 9422 deletions

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -13,7 +13,8 @@
// Include Arduino.h before stdlib.h to avoid conflict with atexit()
// https://github.com/bblanchon/ArduinoJson/pull/1693#issuecomment-1001060240
#if ARDUINOJSON_ENABLE_ARDUINO_STRING || ARDUINOJSON_ENABLE_ARDUINO_STREAM || \
ARDUINOJSON_ENABLE_ARDUINO_PRINT || ARDUINOJSON_ENABLE_PROGMEM
ARDUINOJSON_ENABLE_ARDUINO_PRINT || \
(ARDUINOJSON_ENABLE_PROGMEM && defined(ARDUINO))
# include <Arduino.h>
#endif
@@ -29,18 +30,19 @@
#include "ArduinoJson/Object/JsonObject.hpp"
#include "ArduinoJson/Variant/JsonVariantConst.hpp"
#include "ArduinoJson/Document/DynamicJsonDocument.hpp"
#include "ArduinoJson/Document/StaticJsonDocument.hpp"
#include "ArduinoJson/Document/JsonDocument.hpp"
#include "ArduinoJson/Array/ArrayImpl.hpp"
#include "ArduinoJson/Array/ElementProxy.hpp"
#include "ArduinoJson/Array/JsonArrayImpl.hpp"
#include "ArduinoJson/Array/Utilities.hpp"
#include "ArduinoJson/Collection/CollectionImpl.hpp"
#include "ArduinoJson/Object/JsonObjectImpl.hpp"
#include "ArduinoJson/Memory/VariantPoolImpl.hpp"
#include "ArduinoJson/Object/MemberProxy.hpp"
#include "ArduinoJson/Object/ObjectImpl.hpp"
#include "ArduinoJson/Variant/ConverterImpl.hpp"
#include "ArduinoJson/Variant/JsonVariantCopier.hpp"
#include "ArduinoJson/Variant/VariantCompare.hpp"
#include "ArduinoJson/Variant/VariantImpl.hpp"
#include "ArduinoJson/Variant/VariantRefBaseImpl.hpp"
#include "ArduinoJson/Json/JsonDeserializer.hpp"
#include "ArduinoJson/Json/JsonSerializer.hpp"

View File

@@ -0,0 +1,57 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Collection/CollectionData.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
class ArrayData : public CollectionData {
public:
VariantData* addElement(ResourceManager* resources) {
return addSlot(resources).data();
}
static VariantData* addElement(ArrayData* array, ResourceManager* resources) {
if (!array)
return nullptr;
return array->addElement(resources);
}
VariantData* getOrAddElement(size_t index, ResourceManager* resources);
VariantData* getElement(size_t index, const ResourceManager* resources) const;
static VariantData* getElement(const ArrayData* array, size_t index,
const ResourceManager* resources) {
if (!array)
return nullptr;
return array->getElement(index, resources);
}
void removeElement(size_t index, ResourceManager* resources);
static void removeElement(ArrayData* array, size_t index,
ResourceManager* resources) {
if (!array)
return;
array->removeElement(index, resources);
}
bool copyFrom(const ArrayData& src, ResourceManager* resources);
static bool copy(ArrayData* dst, const ArrayData* src,
ResourceManager* resources) {
if (!dst || !src)
return false;
return dst->copyFrom(*src, resources);
}
private:
iterator at(size_t index, const ResourceManager* resources) const;
};
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -0,0 +1,50 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Array/ArrayData.hpp>
#include <ArduinoJson/Variant/VariantCompare.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
inline ArrayData::iterator ArrayData::at(
size_t index, const ResourceManager* resources) const {
auto it = createIterator(resources);
while (!it.done() && index) {
it.next(resources);
--index;
}
return it;
}
inline VariantData* ArrayData::getOrAddElement(size_t index,
ResourceManager* resources) {
auto it = createIterator(resources);
while (!it.done() && index > 0) {
it.next(resources);
index--;
}
if (it.done())
index++;
VariantData* element = it.data();
while (index > 0) {
element = addElement(resources);
if (!element)
return nullptr;
index--;
}
return element;
}
inline VariantData* ArrayData::getElement(
size_t index, const ResourceManager* resources) const {
return at(index, resources).data();
}
inline void ArrayData::removeElement(size_t index, ResourceManager* resources) {
remove(at(index, resources), resources);
}
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -9,7 +9,7 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
// A proxy class to get or set an element of an array.
// https://arduinojson.org/v6/api/jsonarray/subscript/
// https://arduinojson.org/v7/api/jsonarray/subscript/
template <typename TUpstream>
class ElementProxy : public VariantRefBase<ElementProxy<TUpstream>>,
public VariantOperators<ElementProxy<TUpstream>> {
@@ -17,44 +17,49 @@ class ElementProxy : public VariantRefBase<ElementProxy<TUpstream>>,
public:
ElementProxy(TUpstream upstream, size_t index)
: _upstream(upstream), _index(index) {}
: upstream_(upstream), index_(index) {}
ElementProxy(const ElementProxy& src)
: _upstream(src._upstream), _index(src._index) {}
: upstream_(src.upstream_), index_(src.index_) {}
FORCE_INLINE ElementProxy& operator=(const ElementProxy& src) {
ElementProxy& operator=(const ElementProxy& src) {
this->set(src);
return *this;
}
template <typename T>
FORCE_INLINE ElementProxy& operator=(const T& src) {
ElementProxy& operator=(const T& src) {
this->set(src);
return *this;
}
template <typename T>
FORCE_INLINE ElementProxy& operator=(T* src) {
ElementProxy& operator=(T* src) {
this->set(src);
return *this;
}
private:
FORCE_INLINE MemoryPool* getPool() const {
return VariantAttorney::getPool(_upstream);
ResourceManager* getResourceManager() const {
return VariantAttorney::getResourceManager(upstream_);
}
FORCE_INLINE VariantData* getData() const {
return variantGetElement(VariantAttorney::getData(_upstream), _index);
return VariantData::getElement(
VariantAttorney::getData(upstream_), index_,
VariantAttorney::getResourceManager(upstream_));
}
FORCE_INLINE VariantData* getOrCreateData() const {
return variantGetOrAddElement(VariantAttorney::getOrCreateData(_upstream),
_index, VariantAttorney::getPool(_upstream));
VariantData* getOrCreateData() const {
auto data = VariantAttorney::getOrCreateData(upstream_);
if (!data)
return nullptr;
return data->getOrAddElement(
index_, VariantAttorney::getResourceManager(upstream_));
}
TUpstream _upstream;
size_t _index;
TUpstream upstream_;
size_t index_;
};
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -12,7 +12,7 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
class JsonObject;
// A reference to an array in a JsonDocument
// https://arduinojson.org/v6/api/jsonarray/
// https://arduinojson.org/v7/api/jsonarray/
class JsonArray : public detail::VariantOperators<JsonArray> {
friend class detail::VariantAttorney;
@@ -20,192 +20,177 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
typedef JsonArrayIterator iterator;
// Constructs an unbound reference.
FORCE_INLINE JsonArray() : _data(0), _pool(0) {}
JsonArray() : data_(0), resources_(0) {}
// INTERNAL USE ONLY
FORCE_INLINE JsonArray(detail::MemoryPool* pool, detail::CollectionData* data)
: _data(data), _pool(pool) {}
JsonArray(detail::ArrayData* data, detail::ResourceManager* resources)
: data_(data), resources_(resources) {}
// Returns a JsonVariant pointing to the array.
// https://arduinojson.org/v6/api/jsonvariant/
// https://arduinojson.org/v7/api/jsonvariant/
operator JsonVariant() {
void* data = _data; // prevent warning cast-align
return JsonVariant(_pool, reinterpret_cast<detail::VariantData*>(data));
void* data = data_; // prevent warning cast-align
return JsonVariant(reinterpret_cast<detail::VariantData*>(data),
resources_);
}
// Returns a read-only reference to the array.
// https://arduinojson.org/v6/api/jsonarrayconst/
// https://arduinojson.org/v7/api/jsonarrayconst/
operator JsonArrayConst() const {
return JsonArrayConst(_data);
return JsonArrayConst(data_, resources_);
}
// Appends a new (empty) element to the array.
// Returns a reference to the new element.
// https://arduinojson.org/v7/api/jsonarray/add/
template <typename T>
typename detail::enable_if<!detail::is_same<T, JsonVariant>::value, T>::type
add() const {
return add<JsonVariant>().to<T>();
}
// Appends a new (null) element to the array.
// Returns a reference to the new element.
// https://arduinojson.org/v6/api/jsonarray/add/
JsonVariant add() const {
if (!_data)
return JsonVariant();
return JsonVariant(_pool, _data->addElement(_pool));
// https://arduinojson.org/v7/api/jsonarray/add/
template <typename T>
typename detail::enable_if<detail::is_same<T, JsonVariant>::value, T>::type
add() const {
return JsonVariant(detail::ArrayData::addElement(data_, resources_),
resources_);
}
// Appends a value to the array.
// https://arduinojson.org/v6/api/jsonarray/add/
// https://arduinojson.org/v7/api/jsonarray/add/
template <typename T>
FORCE_INLINE bool add(const T& value) const {
return add().set(value);
bool add(const T& value) const {
return add<JsonVariant>().set(value);
}
// Appends a value to the array.
// https://arduinojson.org/v6/api/jsonarray/add/
// https://arduinojson.org/v7/api/jsonarray/add/
template <typename T>
FORCE_INLINE bool add(T* value) const {
return add().set(value);
bool add(T* value) const {
return add<JsonVariant>().set(value);
}
// Returns an iterator to the first element of the array.
// https://arduinojson.org/v6/api/jsonarray/begin/
FORCE_INLINE iterator begin() const {
if (!_data)
// https://arduinojson.org/v7/api/jsonarray/begin/
iterator begin() const {
if (!data_)
return iterator();
return iterator(_pool, _data->head());
return iterator(data_->createIterator(resources_), resources_);
}
// Returns an iterator following the last element of the array.
// https://arduinojson.org/v6/api/jsonarray/end/
FORCE_INLINE iterator end() const {
// https://arduinojson.org/v7/api/jsonarray/end/
iterator end() const {
return iterator();
}
// Copies an array.
// https://arduinojson.org/v6/api/jsonarray/set/
FORCE_INLINE bool set(JsonArrayConst src) const {
if (!_data || !src._data)
// https://arduinojson.org/v7/api/jsonarray/set/
bool set(JsonArrayConst src) const {
if (!data_)
return false;
return _data->copyFrom(*src._data, _pool);
}
// Compares the content of two arrays.
FORCE_INLINE bool operator==(JsonArray rhs) const {
return JsonArrayConst(_data) == JsonArrayConst(rhs._data);
clear();
for (auto element : src) {
if (!add(element))
return false;
}
return true;
}
// Removes the element at the specified iterator.
// ⚠️ Doesn't release the memory associated with the removed element.
// https://arduinojson.org/v6/api/jsonarray/remove/
FORCE_INLINE void remove(iterator it) const {
if (!_data)
return;
_data->removeSlot(it._slot);
// https://arduinojson.org/v7/api/jsonarray/remove/
void remove(iterator it) const {
detail::ArrayData::remove(data_, it.iterator_, resources_);
}
// Removes the element at the specified index.
// ⚠️ Doesn't release the memory associated with the removed element.
// https://arduinojson.org/v6/api/jsonarray/remove/
FORCE_INLINE void remove(size_t index) const {
if (!_data)
return;
_data->removeElement(index);
// https://arduinojson.org/v7/api/jsonarray/remove/
void remove(size_t index) const {
detail::ArrayData::removeElement(data_, index, resources_);
}
// Removes all the elements of the array.
// ⚠️ Doesn't release the memory associated with the removed elements.
// https://arduinojson.org/v6/api/jsonarray/clear/
// https://arduinojson.org/v7/api/jsonarray/clear/
void clear() const {
if (!_data)
return;
_data->clear();
detail::ArrayData::clear(data_, resources_);
}
// Gets or sets the element at the specified index.
// https://arduinojson.org/v6/api/jsonarray/subscript/
FORCE_INLINE detail::ElementProxy<JsonArray> operator[](size_t index) const {
// https://arduinojson.org/v7/api/jsonarray/subscript/
detail::ElementProxy<JsonArray> operator[](size_t index) const {
return {*this, index};
}
// Creates an object and appends it to the array.
// https://arduinojson.org/v6/api/jsonarray/createnestedobject/
FORCE_INLINE JsonObject createNestedObject() const;
// Creates an array and appends it to the array.
// https://arduinojson.org/v6/api/jsonarray/createnestedarray/
FORCE_INLINE JsonArray createNestedArray() const {
return add().to<JsonArray>();
}
operator JsonVariantConst() const {
return JsonVariantConst(collectionToVariant(_data));
return JsonVariantConst(collectionToVariant(data_), resources_);
}
// Returns true if the reference is unbound.
// https://arduinojson.org/v6/api/jsonarray/isnull/
FORCE_INLINE bool isNull() const {
return _data == 0;
// https://arduinojson.org/v7/api/jsonarray/isnull/
bool isNull() const {
return data_ == 0;
}
// Returns true if the reference is bound.
// https://arduinojson.org/v6/api/jsonarray/isnull/
FORCE_INLINE operator bool() const {
return _data != 0;
}
// Returns the number of bytes occupied by the array.
// https://arduinojson.org/v6/api/jsonarray/memoryusage/
FORCE_INLINE size_t memoryUsage() const {
return _data ? _data->memoryUsage() : 0;
// https://arduinojson.org/v7/api/jsonarray/isnull/
operator bool() const {
return data_ != 0;
}
// Returns the depth (nesting level) of the array.
// https://arduinojson.org/v6/api/jsonarray/nesting/
FORCE_INLINE size_t nesting() const {
return variantNesting(collectionToVariant(_data));
// https://arduinojson.org/v7/api/jsonarray/nesting/
size_t nesting() const {
return detail::VariantData::nesting(collectionToVariant(data_), resources_);
}
// Returns the number of elements in the array.
// https://arduinojson.org/v6/api/jsonarray/size/
FORCE_INLINE size_t size() const {
return _data ? _data->size() : 0;
// https://arduinojson.org/v7/api/jsonarray/size/
size_t size() const {
return data_ ? data_->size(resources_) : 0;
}
// DEPRECATED: use add<JsonVariant>() instead
ARDUINOJSON_DEPRECATED("use add<JsonVariant>() instead")
JsonVariant add() const {
return add<JsonVariant>();
}
// DEPRECATED: use add<JsonArray>() instead
ARDUINOJSON_DEPRECATED("use add<JsonArray>() instead")
JsonArray createNestedArray() const {
return add<JsonArray>();
}
// DEPRECATED: use add<JsonObject>() instead
ARDUINOJSON_DEPRECATED("use add<JsonObject>() instead")
JsonObject createNestedObject() const;
// DEPRECATED: always returns zero
ARDUINOJSON_DEPRECATED("always returns zero")
size_t memoryUsage() const {
return 0;
}
private:
detail::MemoryPool* getPool() const {
return _pool;
detail::ResourceManager* getResourceManager() const {
return resources_;
}
detail::VariantData* getData() const {
return collectionToVariant(_data);
return collectionToVariant(data_);
}
detail::VariantData* getOrCreateData() const {
return collectionToVariant(_data);
return collectionToVariant(data_);
}
detail::CollectionData* _data;
detail::MemoryPool* _pool;
};
template <>
struct Converter<JsonArray> : private detail::VariantAttorney {
static void toJson(JsonVariantConst src, JsonVariant dst) {
variantCopyFrom(getData(dst), getData(src), getPool(dst));
}
static JsonArray fromJson(JsonVariant src) {
auto data = getData(src);
auto pool = getPool(src);
return JsonArray(pool, data != 0 ? data->asArray() : 0);
}
static detail::InvalidConversion<JsonVariantConst, JsonArray> fromJson(
JsonVariantConst);
static bool checkJson(JsonVariantConst) {
return false;
}
static bool checkJson(JsonVariant src) {
auto data = getData(src);
return data && data->isArray();
}
detail::ArrayData* data_;
detail::ResourceManager* resources_;
};
ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -13,7 +13,7 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
class JsonObject;
// A read-only reference to an array in a JsonDocument
// https://arduinojson.org/v6/api/jsonarrayconst/
// https://arduinojson.org/v7/api/jsonarrayconst/
class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
friend class JsonArray;
friend class detail::VariantAttorney;
@@ -22,114 +22,98 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
typedef JsonArrayConstIterator iterator;
// Returns an iterator to the first element of the array.
// https://arduinojson.org/v6/api/jsonarrayconst/begin/
FORCE_INLINE iterator begin() const {
if (!_data)
// https://arduinojson.org/v7/api/jsonarrayconst/begin/
iterator begin() const {
if (!data_)
return iterator();
return iterator(_data->head());
return iterator(data_->createIterator(resources_), resources_);
}
// Returns an iterator to the element following the last element of the array.
// https://arduinojson.org/v6/api/jsonarrayconst/end/
FORCE_INLINE iterator end() const {
// https://arduinojson.org/v7/api/jsonarrayconst/end/
iterator end() const {
return iterator();
}
// Creates an unbound reference.
FORCE_INLINE JsonArrayConst() : _data(0) {}
JsonArrayConst() : data_(0) {}
// INTERNAL USE ONLY
FORCE_INLINE JsonArrayConst(const detail::CollectionData* data)
: _data(data) {}
// Compares the content of two arrays.
// Returns true if the two arrays are equal.
FORCE_INLINE bool operator==(JsonArrayConst rhs) const {
if (_data == rhs._data)
return true;
if (!_data || !rhs._data)
return false;
iterator it1 = begin();
iterator it2 = rhs.begin();
for (;;) {
bool end1 = it1 == end();
bool end2 = it2 == rhs.end();
if (end1 && end2)
return true;
if (end1 || end2)
return false;
if (*it1 != *it2)
return false;
++it1;
++it2;
}
}
JsonArrayConst(const detail::ArrayData* data,
const detail::ResourceManager* resources)
: data_(data), resources_(resources) {}
// Returns the element at the specified index.
// https://arduinojson.org/v6/api/jsonarrayconst/subscript/
FORCE_INLINE JsonVariantConst operator[](size_t index) const {
return JsonVariantConst(_data ? _data->getElement(index) : 0);
// https://arduinojson.org/v7/api/jsonarrayconst/subscript/
JsonVariantConst operator[](size_t index) const {
return JsonVariantConst(
detail::ArrayData::getElement(data_, index, resources_), resources_);
}
operator JsonVariantConst() const {
return JsonVariantConst(collectionToVariant(_data));
return JsonVariantConst(getData(), resources_);
}
// Returns true if the reference is unbound.
// https://arduinojson.org/v6/api/jsonarrayconst/isnull/
FORCE_INLINE bool isNull() const {
return _data == 0;
// https://arduinojson.org/v7/api/jsonarrayconst/isnull/
bool isNull() const {
return data_ == 0;
}
// Returns true if the reference is bound.
// https://arduinojson.org/v6/api/jsonarrayconst/isnull/
FORCE_INLINE operator bool() const {
return _data != 0;
}
// Returns the number of bytes occupied by the array.
// https://arduinojson.org/v6/api/jsonarrayconst/memoryusage/
FORCE_INLINE size_t memoryUsage() const {
return _data ? _data->memoryUsage() : 0;
// https://arduinojson.org/v7/api/jsonarrayconst/isnull/
operator bool() const {
return data_ != 0;
}
// Returns the depth (nesting level) of the array.
// https://arduinojson.org/v6/api/jsonarrayconst/nesting/
FORCE_INLINE size_t nesting() const {
return variantNesting(collectionToVariant(_data));
// https://arduinojson.org/v7/api/jsonarrayconst/nesting/
size_t nesting() const {
return detail::VariantData::nesting(getData(), resources_);
}
// Returns the number of elements in the array.
// https://arduinojson.org/v6/api/jsonarrayconst/size/
FORCE_INLINE size_t size() const {
return _data ? _data->size() : 0;
// https://arduinojson.org/v7/api/jsonarrayconst/size/
size_t size() const {
return data_ ? data_->size(resources_) : 0;
}
// DEPRECATED: always returns zero
ARDUINOJSON_DEPRECATED("always returns zero")
size_t memoryUsage() const {
return 0;
}
private:
const detail::VariantData* getData() const {
return collectionToVariant(_data);
return collectionToVariant(data_);
}
const detail::CollectionData* _data;
const detail::ArrayData* data_;
const detail::ResourceManager* resources_;
};
template <>
struct Converter<JsonArrayConst> : private detail::VariantAttorney {
static void toJson(JsonVariantConst src, JsonVariant dst) {
variantCopyFrom(getData(dst), getData(src), getPool(dst));
}
// Compares the content of two arrays.
// Returns true if the two arrays are equal.
inline bool operator==(JsonArrayConst lhs, JsonArrayConst rhs) {
if (!lhs && !rhs)
return true;
if (!lhs || !rhs)
return false;
static JsonArrayConst fromJson(JsonVariantConst src) {
auto data = getData(src);
return data ? data->asArray() : 0;
}
auto a = lhs.begin();
auto b = rhs.begin();
static bool checkJson(JsonVariantConst src) {
auto data = getData(src);
return data && data->isArray();
for (;;) {
if (a == b) // same pointer or both null
return true;
if (a == lhs.end() || b == rhs.end())
return false;
if (*a != *b)
return false;
++a;
++b;
}
};
}
ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@@ -1,36 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Array/JsonArray.hpp>
#include <ArduinoJson/Object/JsonObject.hpp>
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
inline JsonObject JsonArray::createNestedObject() const {
return add().to<JsonObject>();
}
ARDUINOJSON_END_PUBLIC_NAMESPACE
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename TDerived>
inline JsonArray VariantRefBase<TDerived>::createNestedArray() const {
return add().template to<JsonArray>();
}
template <typename TDerived>
inline JsonObject VariantRefBase<TDerived>::createNestedObject() const {
return add().template to<JsonObject>();
}
template <typename TDerived>
inline ElementProxy<TDerived> VariantRefBase<TDerived>::operator[](
size_t index) const {
return ElementProxy<TDerived>(derived(), index);
}
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -1,121 +1,96 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Variant/JsonVariant.hpp>
#include <ArduinoJson/Variant/SlotFunctions.hpp>
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
class VariantPtr {
template <typename T>
class Ptr {
public:
VariantPtr(detail::MemoryPool* pool, detail::VariantData* data)
: _variant(pool, data) {}
Ptr(T value) : value_(value) {}
JsonVariant* operator->() {
return &_variant;
T* operator->() {
return &value_;
}
JsonVariant& operator*() {
return _variant;
T& operator*() {
return value_;
}
private:
JsonVariant _variant;
T value_;
};
class JsonArrayIterator {
friend class JsonArray;
public:
JsonArrayIterator() : _slot(0) {}
explicit JsonArrayIterator(detail::MemoryPool* pool,
detail::VariantSlot* slot)
: _pool(pool), _slot(slot) {}
JsonArrayIterator() {}
explicit JsonArrayIterator(detail::ArrayData::iterator iterator,
detail::ResourceManager* resources)
: iterator_(iterator), resources_(resources) {}
JsonVariant operator*() const {
return JsonVariant(_pool, _slot->data());
JsonVariant operator*() {
return JsonVariant(iterator_.data(), resources_);
}
VariantPtr operator->() {
return VariantPtr(_pool, _slot->data());
Ptr<JsonVariant> operator->() {
return operator*();
}
bool operator==(const JsonArrayIterator& other) const {
return _slot == other._slot;
return iterator_ == other.iterator_;
}
bool operator!=(const JsonArrayIterator& other) const {
return _slot != other._slot;
return iterator_ != other.iterator_;
}
JsonArrayIterator& operator++() {
_slot = _slot->next();
return *this;
}
JsonArrayIterator& operator+=(size_t distance) {
_slot = _slot->next(distance);
iterator_.next(resources_);
return *this;
}
private:
detail::MemoryPool* _pool;
detail::VariantSlot* _slot;
};
class VariantConstPtr {
public:
VariantConstPtr(const detail::VariantData* data) : _variant(data) {}
JsonVariantConst* operator->() {
return &_variant;
}
JsonVariantConst& operator*() {
return _variant;
}
private:
JsonVariantConst _variant;
detail::ArrayData::iterator iterator_;
detail::ResourceManager* resources_;
};
class JsonArrayConstIterator {
friend class JsonArray;
public:
JsonArrayConstIterator() : _slot(0) {}
explicit JsonArrayConstIterator(const detail::VariantSlot* slot)
: _slot(slot) {}
JsonArrayConstIterator() {}
explicit JsonArrayConstIterator(detail::ArrayData::iterator iterator,
const detail::ResourceManager* resources)
: iterator_(iterator), resources_(resources) {}
JsonVariantConst operator*() const {
return JsonVariantConst(_slot->data());
return JsonVariantConst(iterator_.data(), resources_);
}
VariantConstPtr operator->() {
return VariantConstPtr(_slot->data());
Ptr<JsonVariantConst> operator->() {
return operator*();
}
bool operator==(const JsonArrayConstIterator& other) const {
return _slot == other._slot;
return iterator_ == other.iterator_;
}
bool operator!=(const JsonArrayConstIterator& other) const {
return _slot != other._slot;
return iterator_ != other.iterator_;
}
JsonArrayConstIterator& operator++() {
_slot = _slot->next();
return *this;
}
JsonArrayConstIterator& operator+=(size_t distance) {
_slot = _slot->next(distance);
iterator_.next(resources_);
return *this;
}
private:
const detail::VariantSlot* _slot;
detail::ArrayData::iterator iterator_;
const detail::ResourceManager* resources_;
};
ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -18,7 +18,7 @@ copyArray(const T& src, JsonVariant dst) {
}
// Copies values from an array to a JsonArray or a JsonVariant.
// https://arduinojson.org/v6/api/misc/copyarray/
// https://arduinojson.org/v7/api/misc/copyarray/
template <typename T, size_t N, typename TDestination>
inline typename detail::enable_if<
!detail::is_base_of<JsonDocument, TDestination>::value, bool>::type
@@ -27,14 +27,14 @@ copyArray(T (&src)[N], const TDestination& dst) {
}
// Copies values from an array to a JsonArray or a JsonVariant.
// https://arduinojson.org/v6/api/misc/copyarray/
// https://arduinojson.org/v7/api/misc/copyarray/
template <typename T, typename TDestination>
inline typename detail::enable_if<
!detail::is_base_of<JsonDocument, TDestination>::value, bool>::type
copyArray(const T* src, size_t len, const TDestination& dst) {
bool ok = true;
for (size_t i = 0; i < len; i++) {
ok &= copyArray(src[i], dst.add());
ok &= copyArray(src[i], dst.template add<JsonVariant>());
}
return ok;
}
@@ -47,14 +47,14 @@ inline bool copyArray(const char* src, size_t, const TDestination& dst) {
}
// Copies values from an array to a JsonDocument.
// https://arduinojson.org/v6/api/misc/copyarray/
// https://arduinojson.org/v7/api/misc/copyarray/
template <typename T>
inline bool copyArray(const T& src, JsonDocument& dst) {
return copyArray(src, dst.to<JsonArray>());
}
// Copies an array to a JsonDocument.
// https://arduinojson.org/v6/api/misc/copyarray/
// https://arduinojson.org/v7/api/misc/copyarray/
template <typename T>
inline bool copyArray(const T* src, size_t len, JsonDocument& dst) {
return copyArray(src, len, dst.to<JsonArray>());
@@ -70,14 +70,14 @@ copyArray(JsonVariantConst src, T& dst) {
}
// Copies values from a JsonArray or JsonVariant to an array.
// https://arduinojson.org/v6/api/misc/copyarray/
// https://arduinojson.org/v7/api/misc/copyarray/
template <typename T, size_t N>
inline size_t copyArray(JsonArrayConst src, T (&dst)[N]) {
return copyArray(src, dst, N);
}
// Copies values from a JsonArray or JsonVariant to an array.
// https://arduinojson.org/v6/api/misc/copyarray/
// https://arduinojson.org/v7/api/misc/copyarray/
template <typename T>
inline size_t copyArray(JsonArrayConst src, T* dst, size_t len) {
size_t i = 0;
@@ -101,7 +101,7 @@ inline size_t copyArray(JsonVariantConst src, char (&dst)[N]) {
}
// Copies values from a JsonDocument to an array.
// https://arduinojson.org/v6/api/misc/copyarray/
// https://arduinojson.org/v7/api/misc/copyarray/
template <typename TSource, typename T>
inline typename detail::enable_if<
detail::is_array<T>::value &&

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -11,74 +11,112 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
class MemoryPool;
class VariantData;
class VariantSlot;
class CollectionData {
VariantSlot* _head;
VariantSlot* _tail;
class CollectionIterator {
friend class CollectionData;
public:
// Must be a POD!
// - no constructor
// - no destructor
// - no virtual
// - no inheritance
CollectionIterator() : slot_(nullptr), currentId_(NULL_SLOT) {}
// Array only
void next(const ResourceManager* resources);
VariantData* addElement(MemoryPool* pool);
VariantData* getElement(size_t index) const;
VariantData* getOrAddElement(size_t index, MemoryPool* pool);
void removeElement(size_t index);
// Object only
template <typename TAdaptedString>
VariantData* addMember(TAdaptedString key, MemoryPool* pool);
template <typename TAdaptedString>
VariantData* getMember(TAdaptedString key) const;
template <typename TAdaptedString>
VariantData* getOrAddMember(TAdaptedString key, MemoryPool* pool);
template <typename TAdaptedString>
void removeMember(TAdaptedString key) {
removeSlot(getSlot(key));
bool done() const {
return slot_ == nullptr;
}
template <typename TAdaptedString>
bool containsKey(const TAdaptedString& key) const;
// Generic
void clear();
size_t memoryUsage() const;
size_t size() const;
VariantSlot* addSlot(MemoryPool*);
void removeSlot(VariantSlot* slot);
bool copyFrom(const CollectionData& src, MemoryPool* pool);
VariantSlot* head() const {
return _head;
bool operator==(const CollectionIterator& other) const {
return slot_ == other.slot_;
}
void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance);
bool operator!=(const CollectionIterator& other) const {
return slot_ != other.slot_;
}
VariantData* operator->() {
ARDUINOJSON_ASSERT(slot_ != nullptr);
return data();
}
VariantData& operator*() {
ARDUINOJSON_ASSERT(slot_ != nullptr);
return *data();
}
const VariantData& operator*() const {
ARDUINOJSON_ASSERT(slot_ != nullptr);
return *data();
}
const char* key() const;
bool ownsKey() const;
void setKey(StringNode*);
void setKey(const char*);
VariantData* data() {
return reinterpret_cast<VariantData*>(slot_);
}
const VariantData* data() const {
return reinterpret_cast<const VariantData*>(slot_);
}
private:
VariantSlot* getSlot(size_t index) const;
CollectionIterator(VariantSlot* slot, SlotId slotId);
template <typename TAdaptedString>
VariantSlot* getSlot(TAdaptedString key) const;
VariantSlot* slot_;
SlotId currentId_, nextId_;
};
VariantSlot* getPreviousSlot(VariantSlot*) const;
class CollectionData {
SlotId head_ = NULL_SLOT;
SlotId tail_ = NULL_SLOT;
public:
// Placement new
static void* operator new(size_t, void* p) noexcept {
return p;
}
static void operator delete(void*, void*) noexcept {}
using iterator = CollectionIterator;
iterator createIterator(const ResourceManager* resources) const {
return iterator(resources->getSlot(head_), head_);
}
size_t size(const ResourceManager*) const;
size_t nesting(const ResourceManager*) const;
void clear(ResourceManager* resources);
static void clear(CollectionData* collection, ResourceManager* resources) {
if (!collection)
return;
collection->clear(resources);
}
void remove(iterator it, ResourceManager* resources);
static void remove(CollectionData* collection, iterator it,
ResourceManager* resources) {
if (collection)
return collection->remove(it, resources);
}
SlotId head() const {
return head_;
}
protected:
iterator addSlot(ResourceManager*);
private:
SlotWithId getPreviousSlot(VariantSlot*, const ResourceManager*) const;
void releaseSlot(SlotWithId, ResourceManager*);
};
inline const VariantData* collectionToVariant(

View File

@@ -1,197 +1,133 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Collection/CollectionData.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp>
#include <ArduinoJson/Memory/Alignment.hpp>
#include <ArduinoJson/Strings/StringAdapters.hpp>
#include <ArduinoJson/Variant/VariantCompare.hpp>
#include <ArduinoJson/Variant/VariantData.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
inline VariantSlot* CollectionData::addSlot(MemoryPool* pool) {
VariantSlot* slot = pool->allocVariant();
if (!slot)
return 0;
inline CollectionIterator::CollectionIterator(VariantSlot* slot, SlotId slotId)
: slot_(slot), currentId_(slotId) {
nextId_ = slot_ ? slot_->next() : NULL_SLOT;
}
if (_tail) {
ARDUINOJSON_ASSERT(pool->owns(_tail)); // Can't alter a linked array/object
_tail->setNextNotNull(slot);
_tail = slot;
inline const char* CollectionIterator::key() const {
ARDUINOJSON_ASSERT(slot_ != nullptr);
return slot_->key();
}
inline void CollectionIterator::setKey(const char* s) {
ARDUINOJSON_ASSERT(slot_ != nullptr);
ARDUINOJSON_ASSERT(s != nullptr);
return slot_->setKey(s);
}
inline void CollectionIterator::setKey(StringNode* s) {
ARDUINOJSON_ASSERT(slot_ != nullptr);
ARDUINOJSON_ASSERT(s != nullptr);
return slot_->setKey(s);
}
inline bool CollectionIterator::ownsKey() const {
ARDUINOJSON_ASSERT(slot_ != nullptr);
return slot_->ownsKey();
}
inline void CollectionIterator::next(const ResourceManager* resources) {
ARDUINOJSON_ASSERT(currentId_ != NULL_SLOT);
slot_ = resources->getSlot(nextId_);
currentId_ = nextId_;
if (slot_)
nextId_ = slot_->next();
}
inline CollectionData::iterator CollectionData::addSlot(
ResourceManager* resources) {
auto slot = resources->allocSlot();
if (!slot)
return {};
if (tail_ != NULL_SLOT) {
auto tail = resources->getSlot(tail_);
tail->setNext(slot.id());
tail_ = slot.id();
} else {
_head = slot;
_tail = slot;
head_ = slot.id();
tail_ = slot.id();
}
return iterator(slot, slot.id());
}
inline void CollectionData::clear(ResourceManager* resources) {
auto next = head_;
while (next != NULL_SLOT) {
auto currId = next;
auto slot = resources->getSlot(next);
next = slot->next();
releaseSlot(SlotWithId(slot, currId), resources);
}
slot->clear();
return slot;
head_ = NULL_SLOT;
tail_ = NULL_SLOT;
}
inline VariantData* CollectionData::addElement(MemoryPool* pool) {
return slotData(addSlot(pool));
}
template <typename TAdaptedString>
inline VariantData* CollectionData::addMember(TAdaptedString key,
MemoryPool* pool) {
VariantSlot* slot = addSlot(pool);
if (!slotSetKey(slot, key, pool)) {
removeSlot(slot);
return 0;
inline SlotWithId CollectionData::getPreviousSlot(
VariantSlot* target, const ResourceManager* resources) const {
auto prev = SlotWithId();
auto currentId = head_;
while (currentId != NULL_SLOT) {
auto currentSlot = resources->getSlot(currentId);
if (currentSlot == target)
return prev;
prev = SlotWithId(currentSlot, currentId);
currentId = currentSlot->next();
}
return slot->data();
return SlotWithId();
}
inline void CollectionData::clear() {
_head = 0;
_tail = 0;
}
template <typename TAdaptedString>
inline bool CollectionData::containsKey(const TAdaptedString& 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) {
JsonString key(s->key(),
s->ownsKey() ? JsonString::Copied : JsonString::Linked);
var = addMember(adaptString(key), pool);
} else {
var = addElement(pool);
}
if (!var)
return false;
if (!var->copyFrom(*s->data(), pool))
return false;
}
return true;
}
template <typename TAdaptedString>
inline VariantSlot* CollectionData::getSlot(TAdaptedString key) const {
if (key.isNull())
return 0;
VariantSlot* slot = _head;
while (slot) {
if (stringEquals(key, adaptString(slot->key())))
break;
slot = slot->next();
}
return slot;
}
inline VariantSlot* CollectionData::getSlot(size_t index) const {
if (!_head)
return 0;
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 TAdaptedString>
inline VariantData* CollectionData::getMember(TAdaptedString key) const {
VariantSlot* slot = getSlot(key);
return slot ? slot->data() : 0;
}
template <typename TAdaptedString>
inline VariantData* CollectionData::getOrAddMember(TAdaptedString key,
MemoryPool* pool) {
// ignore null key
if (key.isNull())
return 0;
// search a matching key
VariantSlot* slot = getSlot(key);
if (slot)
return slot->data();
return addMember(key, pool);
}
inline VariantData* CollectionData::getElement(size_t index) const {
VariantSlot* slot = getSlot(index);
return slot ? slot->data() : 0;
}
inline VariantData* CollectionData::getOrAddElement(size_t index,
MemoryPool* pool) {
VariantSlot* slot = _head;
while (slot && index > 0) {
slot = slot->next();
index--;
}
if (!slot)
index++;
while (index > 0) {
slot = addSlot(pool);
index--;
}
return slotData(slot);
}
inline void CollectionData::removeSlot(VariantSlot* slot) {
if (!slot)
inline void CollectionData::remove(iterator it, ResourceManager* resources) {
if (it.done())
return;
VariantSlot* prev = getPreviousSlot(slot);
VariantSlot* next = slot->next();
auto curr = it.slot_;
auto prev = getPreviousSlot(curr, resources);
auto next = curr->next();
if (prev)
prev->setNext(next);
else
_head = next;
if (!next)
_tail = prev;
head_ = next;
if (next == NULL_SLOT)
tail_ = prev.id();
releaseSlot({it.slot_, it.currentId_}, resources);
}
inline void CollectionData::removeElement(size_t index) {
removeSlot(getSlot(index));
}
inline size_t CollectionData::memoryUsage() const {
size_t total = 0;
for (VariantSlot* s = _head; s; s = s->next()) {
total += sizeof(VariantSlot) + s->data()->memoryUsage();
if (s->ownsKey())
total += strlen(s->key()) + 1;
inline size_t CollectionData::nesting(const ResourceManager* resources) const {
size_t maxChildNesting = 0;
for (auto it = createIterator(resources); !it.done(); it.next(resources)) {
size_t childNesting = it->nesting(resources);
if (childNesting > maxChildNesting)
maxChildNesting = childNesting;
}
return total;
return maxChildNesting + 1;
}
inline size_t CollectionData::size() const {
return slotSize(_head);
inline size_t CollectionData::size(const ResourceManager* resources) const {
size_t count = 0;
for (auto it = createIterator(resources); !it.done(); it.next(resources))
count++;
return count;
}
template <typename T>
inline void movePointer(T*& p, ptrdiff_t offset) {
if (!p)
return;
p = reinterpret_cast<T*>(
reinterpret_cast<void*>(reinterpret_cast<char*>(p) + offset));
ARDUINOJSON_ASSERT(isAligned(p));
}
inline void CollectionData::movePointers(ptrdiff_t stringDistance,
ptrdiff_t variantDistance) {
movePointer(_head, variantDistance);
movePointer(_tail, variantDistance);
for (VariantSlot* slot = _head; slot; slot = slot->next())
slot->movePointers(stringDistance, variantDistance);
inline void CollectionData::releaseSlot(SlotWithId slot,
ResourceManager* resources) {
if (slot->ownsKey())
resources->dereferenceString(slot->key());
slot->data()->setNull(resources);
resources->freeSlot(slot);
}
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -1,10 +1,11 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
// Support std::istream and std::ostream
// https://arduinojson.org/v7/config/enable_std_stream/
#ifndef ARDUINOJSON_ENABLE_STD_STREAM
# ifdef __has_include
# if __has_include(<istream>) && \
@@ -25,6 +26,7 @@
#endif
// Support std::string
// https://arduinojson.org/v7/config/enable_std_string/
#ifndef ARDUINOJSON_ENABLE_STD_STRING
# ifdef __has_include
# if __has_include(<string>) && !defined(min) && !defined(max)
@@ -55,50 +57,97 @@
#endif
// Store floating-point values with float (0) or double (1)
// https://arduinojson.org/v7/config/use_double/
#ifndef ARDUINOJSON_USE_DOUBLE
# define ARDUINOJSON_USE_DOUBLE 1
#endif
// Store integral values with long (0) or long long (1)
#ifndef ARDUINOJSON_USE_LONG_LONG
# if defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ >= 4 || \
defined(_MSC_VER)
# define ARDUINOJSON_USE_LONG_LONG 1
// Pointer size: a heuristic to set sensible defaults
#ifndef ARDUINOJSON_SIZEOF_POINTER
# if defined(__SIZEOF_POINTER__)
# define ARDUINOJSON_SIZEOF_POINTER __SIZEOF_POINTER__
# elif defined(_WIN64) && _WIN64
# define ARDUINOJSON_SIZEOF_POINTER 8 // 64 bits
# else
# define ARDUINOJSON_SIZEOF_POINTER 4 // assume 32 bits otherwise
# endif
#endif
// Store integral values with long (0) or long long (1)
// https://arduinojson.org/v7/config/use_long_long/
#ifndef ARDUINOJSON_USE_LONG_LONG
# define ARDUINOJSON_USE_LONG_LONG 0
# if ARDUINOJSON_SIZEOF_POINTER >= 4 // 32 & 64 bits systems
# define ARDUINOJSON_USE_LONG_LONG 1
# else
# define ARDUINOJSON_USE_LONG_LONG 0
# endif
#endif
// Limit nesting as the stack is likely to be small
// https://arduinojson.org/v7/config/default_nesting_limit/
#ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT
# define ARDUINOJSON_DEFAULT_NESTING_LIMIT 10
#endif
// Number of bits to store the pointer to next node
// (saves RAM but limits the number of values in a document)
#ifndef ARDUINOJSON_SLOT_OFFSET_SIZE
# if defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ <= 2
// Address space == 16-bit => max 127 values
# define ARDUINOJSON_SLOT_OFFSET_SIZE 1
# elif defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ >= 8 || \
defined(_WIN64) && _WIN64
// Address space == 64-bit => max 2147483647 values
# define ARDUINOJSON_SLOT_OFFSET_SIZE 4
// Number of bytes to store a slot id
// https://arduinojson.org/v7/config/slot_id_size/
#ifndef ARDUINOJSON_SLOT_ID_SIZE
# if ARDUINOJSON_SIZEOF_POINTER <= 2
# define ARDUINOJSON_SLOT_ID_SIZE 1 // up to 255 slots
# elif ARDUINOJSON_SIZEOF_POINTER == 4
# define ARDUINOJSON_SLOT_ID_SIZE 2 // up to 65535 slots
# else
// Address space == 32-bit => max 32767 values
# define ARDUINOJSON_SLOT_OFFSET_SIZE 2
# define ARDUINOJSON_SLOT_ID_SIZE 4 // up to 4294967295 slots
# endif
#endif
// Capacity of each variant pool (in slots)
#ifndef ARDUINOJSON_POOL_CAPACITY
# if ARDUINOJSON_SIZEOF_POINTER <= 2
# define ARDUINOJSON_POOL_CAPACITY 16 // 128 bytes
# elif ARDUINOJSON_SIZEOF_POINTER == 4
# define ARDUINOJSON_POOL_CAPACITY 64 // 1024 bytes
# else
# define ARDUINOJSON_POOL_CAPACITY 128 // 3072 bytes
# endif
#endif
// Initial capacity of the pool list
#ifndef ARDUINOJSON_INITIAL_POOL_COUNT
# define ARDUINOJSON_INITIAL_POOL_COUNT 4
#endif
// Automatically call shrinkToFit() from deserializeXxx()
// Disabled by default on 8-bit platforms because it's not worth the increase in
// code size
#ifndef ARDUINOJSON_AUTO_SHRINK
# if ARDUINOJSON_SIZEOF_POINTER <= 2
# define ARDUINOJSON_AUTO_SHRINK 0
# else
# define ARDUINOJSON_AUTO_SHRINK 1
# endif
#endif
// Number of bytes to store the length of a string
// https://arduinojson.org/v7/config/string_length_size/
#ifndef ARDUINOJSON_STRING_LENGTH_SIZE
# if ARDUINOJSON_SIZEOF_POINTER <= 2
# define ARDUINOJSON_STRING_LENGTH_SIZE 1 // up to 255 characters
# else
# define ARDUINOJSON_STRING_LENGTH_SIZE 2 // up to 65535 characters
# endif
#endif
#ifdef ARDUINO
// Enable support for Arduino's String class
// https://arduinojson.org/v7/config/enable_arduino_string/
# ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
# define ARDUINOJSON_ENABLE_ARDUINO_STRING 1
# endif
// Enable support for Arduino's Stream class
// https://arduinojson.org/v7/config/enable_arduino_stream/
# ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM
# define ARDUINOJSON_ENABLE_ARDUINO_STREAM 1
# endif
@@ -109,6 +158,7 @@
# endif
// Enable support for PROGMEM
// https://arduinojson.org/v7/config/enable_progmem/
# ifndef ARDUINOJSON_ENABLE_PROGMEM
# define ARDUINOJSON_ENABLE_PROGMEM 1
# endif
@@ -116,11 +166,13 @@
#else // ARDUINO
// Disable support for Arduino's String class
// https://arduinojson.org/v7/config/enable_arduino_string/
# ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
# define ARDUINOJSON_ENABLE_ARDUINO_STRING 0
# endif
// Disable support for Arduino's Stream class
// https://arduinojson.org/v7/config/enable_arduino_stream/
# ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM
# define ARDUINOJSON_ENABLE_ARDUINO_STREAM 0
# endif
@@ -130,40 +182,51 @@
# define ARDUINOJSON_ENABLE_ARDUINO_PRINT 0
# endif
// Disable support for PROGMEM
// Enable PROGMEM support on AVR only
// https://arduinojson.org/v7/config/enable_progmem/
# ifndef ARDUINOJSON_ENABLE_PROGMEM
# define ARDUINOJSON_ENABLE_PROGMEM 0
# ifdef __AVR__
# define ARDUINOJSON_ENABLE_PROGMEM 1
# else
# define ARDUINOJSON_ENABLE_PROGMEM 0
# endif
# endif
#endif // ARDUINO
// Convert unicode escape sequence (\u0123) to UTF-8
// https://arduinojson.org/v7/config/decode_unicode/
#ifndef ARDUINOJSON_DECODE_UNICODE
# define ARDUINOJSON_DECODE_UNICODE 1
#endif
// Ignore comments in input
// https://arduinojson.org/v7/config/enable_comments/
#ifndef ARDUINOJSON_ENABLE_COMMENTS
# define ARDUINOJSON_ENABLE_COMMENTS 0
#endif
// Support NaN in JSON
// https://arduinojson.org/v7/config/enable_nan/
#ifndef ARDUINOJSON_ENABLE_NAN
# define ARDUINOJSON_ENABLE_NAN 0
#endif
// Support Infinity in JSON
// https://arduinojson.org/v7/config/enable_infinity/
#ifndef ARDUINOJSON_ENABLE_INFINITY
# define ARDUINOJSON_ENABLE_INFINITY 0
#endif
// Control the exponentiation threshold for big numbers
// CAUTION: cannot be more that 1e9 !!!!
// https://arduinojson.org/v7/config/positive_exponentiation_threshold/
#ifndef ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD
# define ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD 1e7
#endif
// Control the exponentiation threshold for small numbers
// https://arduinojson.org/v7/config/negative_exponentiation_threshold/
#ifndef ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD
# define ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD 1e-5
#endif
@@ -191,10 +254,6 @@
# define ARDUINOJSON_TAB " "
#endif
#ifndef ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
# define ARDUINOJSON_ENABLE_STRING_DEDUPLICATION 1
#endif
#ifndef ARDUINOJSON_STRING_BUFFER_SIZE
# define ARDUINOJSON_STRING_BUFFER_SIZE 32
#endif

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -26,49 +26,49 @@ class DeserializationError {
};
DeserializationError() {}
DeserializationError(Code c) : _code(c) {}
DeserializationError(Code c) : code_(c) {}
// Compare with DeserializationError
friend bool operator==(const DeserializationError& lhs,
const DeserializationError& rhs) {
return lhs._code == rhs._code;
return lhs.code_ == rhs.code_;
}
friend bool operator!=(const DeserializationError& lhs,
const DeserializationError& rhs) {
return lhs._code != rhs._code;
return lhs.code_ != rhs.code_;
}
// Compare with Code
friend bool operator==(const DeserializationError& lhs, Code rhs) {
return lhs._code == rhs;
return lhs.code_ == rhs;
}
friend bool operator==(Code lhs, const DeserializationError& rhs) {
return lhs == rhs._code;
return lhs == rhs.code_;
}
friend bool operator!=(const DeserializationError& lhs, Code rhs) {
return lhs._code != rhs;
return lhs.code_ != rhs;
}
friend bool operator!=(Code lhs, const DeserializationError& rhs) {
return lhs != rhs._code;
return lhs != rhs.code_;
}
// Returns true if there is an error
explicit operator bool() const {
return _code != Ok;
return code_ != Ok;
}
// Returns internal enum, useful for switch statement
Code code() const {
return _code;
return code_;
}
const char* c_str() const {
static const char* messages[] = {
"Ok", "EmptyInput", "IncompleteInput",
"InvalidInput", "NoMemory", "TooDeep"};
ARDUINOJSON_ASSERT(static_cast<size_t>(_code) <
ARDUINOJSON_ASSERT(static_cast<size_t>(code_) <
sizeof(messages) / sizeof(messages[0]));
return messages[_code];
return messages[code_];
}
#if ARDUINOJSON_ENABLE_PROGMEM
@@ -82,12 +82,12 @@ class DeserializationError {
ARDUINOJSON_DEFINE_PROGMEM_ARRAY(const char*, messages,
{s0, s1, s2, s3, s4, s5});
return reinterpret_cast<const __FlashStringHelper*>(
detail::pgm_read(messages + _code));
detail::pgm_read(messages + code_));
}
#endif
private:
Code _code;
Code code_;
};
#if ARDUINOJSON_ENABLE_STD_STREAM

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,44 +1,51 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Namespace.hpp>
#include <ArduinoJson/Variant/JsonVariant.hpp>
#include <ArduinoJson/Variant/VariantAttorney.hpp>
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
namespace DeserializationOption {
class Filter {
public:
explicit Filter(JsonVariantConst v) : _variant(v) {}
#if ARDUINOJSON_AUTO_SHRINK
explicit Filter(JsonDocument& doc) : variant_(doc) {
doc.shrinkToFit();
}
#endif
explicit Filter(JsonVariantConst variant) : variant_(variant) {}
bool allow() const {
return _variant;
return variant_;
}
bool allowArray() const {
return _variant == true || _variant.is<JsonArrayConst>();
return variant_ == true || variant_.is<JsonArrayConst>();
}
bool allowObject() const {
return _variant == true || _variant.is<JsonObjectConst>();
return variant_ == true || variant_.is<JsonObjectConst>();
}
bool allowValue() const {
return _variant == true;
return variant_ == true;
}
template <typename TKey>
Filter operator[](const TKey& key) const {
if (_variant == true) // "true" means "allow recursively"
if (variant_ == true) // "true" means "allow recursively"
return *this;
JsonVariantConst member = _variant[key];
return Filter(member.isNull() ? _variant["*"] : member);
JsonVariantConst member = variant_[key];
return Filter(member.isNull() ? variant_["*"] : member);
}
private:
JsonVariantConst _variant;
JsonVariantConst variant_;
};
} // namespace DeserializationOption

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -12,20 +12,20 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
namespace DeserializationOption {
class NestingLimit {
public:
NestingLimit() : _value(ARDUINOJSON_DEFAULT_NESTING_LIMIT) {}
explicit NestingLimit(uint8_t n) : _value(n) {}
NestingLimit() : value_(ARDUINOJSON_DEFAULT_NESTING_LIMIT) {}
explicit NestingLimit(uint8_t n) : value_(n) {}
NestingLimit decrement() const {
ARDUINOJSON_ASSERT(_value > 0);
return NestingLimit(static_cast<uint8_t>(_value - 1));
ARDUINOJSON_ASSERT(value_ > 0);
return NestingLimit(static_cast<uint8_t>(value_ - 1));
}
bool reached() const {
return _value == 0;
return value_ == 0;
}
private:
uint8_t _value;
uint8_t value_;
};
} // namespace DeserializationOption

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -15,18 +15,20 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename TSource, typename Enable = void>
struct Reader {
public:
Reader(TSource& source) : _source(&source) {}
Reader(TSource& source) : source_(&source) {}
int read() {
return _source->read(); // Error here? You passed an unsupported input type
// clang-format off
return source_->read(); // Error here? See https://arduinojson.org/v7/invalid-input/
// clang-format on
}
size_t readBytes(char* buffer, size_t length) {
return _source->readBytes(buffer, length);
return source_->readBytes(buffer, length);
}
private:
TSource* _source;
TSource* source_;
};
template <typename TSource, typename Enable = void>

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -12,20 +12,20 @@ template <typename TSource>
struct Reader<TSource,
typename enable_if<is_base_of<Stream, TSource>::value>::type> {
public:
explicit Reader(Stream& stream) : _stream(&stream) {}
explicit Reader(Stream& stream) : stream_(&stream) {}
int read() {
// don't use _stream.read() as it ignores the timeout
// don't use stream_->read() as it ignores the timeout
char c;
return _stream->readBytes(&c, 1) ? static_cast<unsigned char>(c) : -1;
return stream_->readBytes(&c, 1) ? static_cast<unsigned char>(c) : -1;
}
size_t readBytes(char* buffer, size_t length) {
return _stream->readBytes(buffer, length);
return stream_->readBytes(buffer, length);
}
private:
Stream* _stream;
Stream* stream_;
};
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,54 +1,54 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <Arduino.h>
#include <ArduinoJson/Polyfills/pgmspace.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <>
struct Reader<const __FlashStringHelper*, void> {
const char* _ptr;
const char* ptr_;
public:
explicit Reader(const __FlashStringHelper* ptr)
: _ptr(reinterpret_cast<const char*>(ptr)) {}
: ptr_(reinterpret_cast<const char*>(ptr)) {}
int read() {
return pgm_read_byte(_ptr++);
return pgm_read_byte(ptr_++);
}
size_t readBytes(char* buffer, size_t length) {
memcpy_P(buffer, _ptr, length);
_ptr += length;
memcpy_P(buffer, ptr_, length);
ptr_ += length;
return length;
}
};
template <>
struct BoundedReader<const __FlashStringHelper*, void> {
const char* _ptr;
const char* _end;
const char* ptr_;
const char* end_;
public:
explicit BoundedReader(const __FlashStringHelper* ptr, size_t size)
: _ptr(reinterpret_cast<const char*>(ptr)), _end(_ptr + size) {}
: ptr_(reinterpret_cast<const char*>(ptr)), end_(ptr_ + size) {}
int read() {
if (_ptr < _end)
return pgm_read_byte(_ptr++);
if (ptr_ < end_)
return pgm_read_byte(ptr_++);
else
return -1;
}
size_t readBytes(char* buffer, size_t length) {
size_t available = static_cast<size_t>(_end - _ptr);
size_t available = static_cast<size_t>(end_ - ptr_);
if (available < length)
length = available;
memcpy_P(buffer, _ptr, length);
_ptr += length;
memcpy_P(buffer, ptr_, length);
ptr_ += length;
return length;
}
};

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -8,23 +8,23 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename TIterator>
class IteratorReader {
TIterator _ptr, _end;
TIterator ptr_, end_;
public:
explicit IteratorReader(TIterator begin, TIterator end)
: _ptr(begin), _end(end) {}
: ptr_(begin), end_(end) {}
int read() {
if (_ptr < _end)
return static_cast<unsigned char>(*_ptr++);
if (ptr_ < end_)
return static_cast<unsigned char>(*ptr_++);
else
return -1;
}
size_t readBytes(char* buffer, size_t length) {
size_t i = 0;
while (i < length && _ptr < _end)
buffer[i++] = *_ptr++;
while (i < length && ptr_ < end_)
buffer[i++] = *ptr_++;
return i;
}
};

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -21,19 +21,19 @@ struct IsCharOrVoid<const T> : IsCharOrVoid<T> {};
template <typename TSource>
struct Reader<TSource*,
typename enable_if<IsCharOrVoid<TSource>::value>::type> {
const char* _ptr;
const char* ptr_;
public:
explicit Reader(const void* ptr)
: _ptr(ptr ? reinterpret_cast<const char*>(ptr) : "") {}
: ptr_(ptr ? reinterpret_cast<const char*>(ptr) : "") {}
int read() {
return static_cast<unsigned char>(*_ptr++);
return static_cast<unsigned char>(*ptr_++);
}
size_t readBytes(char* buffer, size_t length) {
for (size_t i = 0; i < length; i++)
buffer[i] = *_ptr++;
buffer[i] = *ptr_++;
return length;
}
};

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -12,19 +12,19 @@ template <typename TSource>
struct Reader<TSource, typename enable_if<
is_base_of<std::istream, TSource>::value>::type> {
public:
explicit Reader(std::istream& stream) : _stream(&stream) {}
explicit Reader(std::istream& stream) : stream_(&stream) {}
int read() {
return _stream->get();
return stream_->get();
}
size_t readBytes(char* buffer, size_t length) {
_stream->read(buffer, static_cast<std::streamsize>(length));
return static_cast<size_t>(_stream->gcount());
stream_->read(buffer, static_cast<std::streamsize>(length));
return static_cast<size_t>(stream_->gcount());
}
private:
std::istream* _stream;
std::istream* stream_;
};
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -8,46 +8,76 @@
#include <ArduinoJson/Deserialization/DeserializationOptions.hpp>
#include <ArduinoJson/Deserialization/Reader.hpp>
#include <ArduinoJson/Polyfills/utility.hpp>
#include <ArduinoJson/StringStorage/StringStorage.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <template <typename, typename> class TDeserializer, typename TReader,
typename TWriter>
TDeserializer<TReader, TWriter> makeDeserializer(MemoryPool* pool,
TReader reader,
TWriter writer) {
ARDUINOJSON_ASSERT(pool != 0);
return TDeserializer<TReader, TWriter>(pool, reader, writer);
// A meta-function that returns the first type of the parameter pack
// or void if empty
template <typename...>
struct first_or_void {
using type = void;
};
template <typename T, typename... Rest>
struct first_or_void<T, Rest...> {
using type = T;
};
// A meta-function that returns true if T is a valid destination type for
// deserialize()
template <class T, class = void>
struct is_deserialize_destination : false_type {};
template <class T>
struct is_deserialize_destination<
T, typename enable_if<is_same<decltype(VariantAttorney::getResourceManager(
detail::declval<T&>())),
ResourceManager*>::value>::type> : true_type {
};
template <typename TDestination>
inline void shrinkJsonDocument(TDestination&) {
// no-op by default
}
template <template <typename, typename> class TDeserializer, typename TStream,
typename... Args>
DeserializationError deserialize(JsonDocument& doc, TStream&& input,
#if ARDUINOJSON_AUTO_SHRINK
inline void shrinkJsonDocument(JsonDocument& doc) {
doc.shrinkToFit();
}
#endif
template <template <typename> class TDeserializer, typename TDestination,
typename TReader, typename TOptions>
DeserializationError doDeserialize(TDestination&& dst, TReader reader,
TOptions options) {
auto data = VariantAttorney::getOrCreateData(dst);
if (!data)
return DeserializationError::NoMemory;
auto resources = VariantAttorney::getResourceManager(dst);
dst.clear();
auto err = TDeserializer<TReader>(resources, reader)
.parse(*data, options.filter, options.nestingLimit);
shrinkJsonDocument(dst);
return err;
}
template <template <typename> class TDeserializer, typename TDestination,
typename TStream, typename... Args,
typename = typename enable_if< // issue #1897
!is_integral<typename first_or_void<Args...>::type>::value>::type>
DeserializationError deserialize(TDestination&& dst, TStream&& input,
Args... args) {
auto reader = makeReader(detail::forward<TStream>(input));
auto data = VariantAttorney::getData(doc);
auto pool = VariantAttorney::getPool(doc);
auto options = makeDeserializationOptions(args...);
doc.clear();
return makeDeserializer<TDeserializer>(pool, reader,
makeStringStorage(input, pool))
.parse(*data, options.filter, options.nestingLimit);
return doDeserialize<TDeserializer>(
dst, makeReader(detail::forward<TStream>(input)),
makeDeserializationOptions(args...));
}
template <template <typename, typename> class TDeserializer, typename TChar,
typename Size, typename... Args,
template <template <typename> class TDeserializer, typename TDestination,
typename TChar, typename Size, typename... Args,
typename = typename enable_if<is_integral<Size>::value>::type>
DeserializationError deserialize(JsonDocument& doc, TChar* input,
DeserializationError deserialize(TDestination&& dst, TChar* input,
Size inputSize, Args... args) {
auto reader = makeReader(input, size_t(inputSize));
auto data = VariantAttorney::getData(doc);
auto pool = VariantAttorney::getPool(doc);
auto options = makeDeserializationOptions(args...);
doc.clear();
return makeDeserializer<TDeserializer>(pool, reader,
makeStringStorage(input, pool))
.parse(*data, options.filter, options.nestingLimit);
return doDeserialize<TDeserializer>(dst, makeReader(input, size_t(inputSize)),
makeDeserializationOptions(args...));
}
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -1,169 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Document/JsonDocument.hpp>
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
// Helper to implement the "base-from-member" idiom
// (we need to store the allocator before constructing JsonDocument)
template <typename TAllocator>
class AllocatorOwner {
public:
AllocatorOwner() {}
AllocatorOwner(TAllocator a) : _allocator(a) {}
void* allocate(size_t size) {
return _allocator.allocate(size);
}
void deallocate(void* ptr) {
if (ptr)
_allocator.deallocate(ptr);
}
void* reallocate(void* ptr, size_t new_size) {
return _allocator.reallocate(ptr, new_size);
}
TAllocator& allocator() {
return _allocator;
}
private:
TAllocator _allocator;
};
// A JsonDocument that uses the provided allocator to allocate its memory pool.
// https://arduinojson.org/v6/api/basicjsondocument/
template <typename TAllocator>
class BasicJsonDocument : AllocatorOwner<TAllocator>, public JsonDocument {
public:
explicit BasicJsonDocument(size_t capa, TAllocator alloc = TAllocator())
: AllocatorOwner<TAllocator>(alloc), JsonDocument(allocPool(capa)) {}
// Copy-constructor
BasicJsonDocument(const BasicJsonDocument& src)
: AllocatorOwner<TAllocator>(src), JsonDocument() {
copyAssignFrom(src);
}
// Move-constructor
BasicJsonDocument(BasicJsonDocument&& src) : AllocatorOwner<TAllocator>(src) {
moveAssignFrom(src);
}
BasicJsonDocument(const JsonDocument& src) {
copyAssignFrom(src);
}
// Construct from variant, array, or object
template <typename T>
BasicJsonDocument(const T& src,
typename detail::enable_if<
detail::is_same<T, JsonVariant>::value ||
detail::is_same<T, JsonVariantConst>::value ||
detail::is_same<T, JsonArray>::value ||
detail::is_same<T, JsonArrayConst>::value ||
detail::is_same<T, JsonObject>::value ||
detail::is_same<T, JsonObjectConst>::value>::type* = 0)
: JsonDocument(allocPool(src.memoryUsage())) {
set(src);
}
// disambiguate
BasicJsonDocument(JsonVariant src)
: JsonDocument(allocPool(src.memoryUsage())) {
set(src);
}
~BasicJsonDocument() {
freePool();
}
BasicJsonDocument& operator=(const BasicJsonDocument& src) {
copyAssignFrom(src);
return *this;
}
BasicJsonDocument& operator=(BasicJsonDocument&& src) {
moveAssignFrom(src);
return *this;
}
template <typename T>
BasicJsonDocument& operator=(const T& src) {
size_t requiredSize = src.memoryUsage();
if (requiredSize > capacity())
reallocPool(requiredSize);
set(src);
return *this;
}
// Reduces the capacity of the memory pool to match the current usage.
// https://arduinojson.org/v6/api/basicjsondocument/shrinktofit/
void shrinkToFit() {
ptrdiff_t bytes_reclaimed = _pool.squash();
if (bytes_reclaimed == 0)
return;
void* old_ptr = _pool.buffer();
void* new_ptr = this->reallocate(old_ptr, _pool.capacity());
ptrdiff_t ptr_offset =
static_cast<char*>(new_ptr) - static_cast<char*>(old_ptr);
_pool.movePointers(ptr_offset);
_data.movePointers(ptr_offset, ptr_offset - bytes_reclaimed);
}
// Reclaims the memory leaked when removing and replacing values.
// https://arduinojson.org/v6/api/jsondocument/garbagecollect/
bool garbageCollect() {
// make a temporary clone and move assign
BasicJsonDocument tmp(*this);
if (!tmp.capacity())
return false;
tmp.set(*this);
moveAssignFrom(tmp);
return true;
}
using AllocatorOwner<TAllocator>::allocator;
private:
detail::MemoryPool allocPool(size_t requiredSize) {
size_t capa = detail::addPadding(requiredSize);
return {reinterpret_cast<char*>(this->allocate(capa)), capa};
}
void reallocPool(size_t requiredSize) {
size_t capa = detail::addPadding(requiredSize);
if (capa == _pool.capacity())
return;
freePool();
replacePool(allocPool(detail::addPadding(requiredSize)));
}
void freePool() {
this->deallocate(getPool()->buffer());
}
void copyAssignFrom(const JsonDocument& src) {
reallocPool(src.capacity());
set(src);
}
void moveAssignFrom(BasicJsonDocument& src) {
freePool();
_data = src._data;
_pool = src._pool;
src._data.setNull();
src._pool = {0, 0};
}
};
ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@@ -1,32 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Document/BasicJsonDocument.hpp>
#include <stdlib.h> // malloc, free
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
// The allocator of DynamicJsonDocument.
struct DefaultAllocator {
void* allocate(size_t size) {
return malloc(size);
}
void deallocate(void* ptr) {
free(ptr);
}
void* reallocate(void* ptr, size_t new_size) {
return realloc(ptr, new_size);
}
};
// A JsonDocument with a memory pool in the heap.
// https://arduinojson.org/v6/api/dynamicjsondocument/
typedef BasicJsonDocument<DefaultAllocator> DynamicJsonDocument;
ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@@ -1,107 +1,143 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Array/ElementProxy.hpp>
#include <ArduinoJson/Memory/MemoryPool.hpp>
#include <ArduinoJson/Memory/Allocator.hpp>
#include <ArduinoJson/Memory/ResourceManager.hpp>
#include <ArduinoJson/Object/JsonObject.hpp>
#include <ArduinoJson/Object/MemberProxy.hpp>
#include <ArduinoJson/Strings/StoragePolicy.hpp>
#include <ArduinoJson/Polyfills/utility.hpp>
#include <ArduinoJson/Variant/JsonVariantConst.hpp>
#include <ArduinoJson/Variant/VariantTo.hpp>
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
// A JSON document.
// https://arduinojson.org/v6/api/jsondocument/
// https://arduinojson.org/v7/api/jsondocument/
class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
friend class detail::VariantAttorney;
public:
JsonDocument(const JsonDocument&) = delete;
JsonDocument& operator=(const JsonDocument&) = delete;
explicit JsonDocument(Allocator* alloc = detail::DefaultAllocator::instance())
: resources_(alloc) {}
// Copy-constructor
JsonDocument(const JsonDocument& src) : JsonDocument(src.allocator()) {
set(src);
}
// Move-constructor
JsonDocument(JsonDocument&& src)
: JsonDocument(detail::DefaultAllocator::instance()) {
swap(*this, src);
}
// Construct from variant, array, or object
template <typename T>
JsonDocument(const T& src,
Allocator* alloc = detail::DefaultAllocator::instance(),
typename detail::enable_if<
detail::is_same<T, JsonVariant>::value ||
detail::is_same<T, JsonVariantConst>::value ||
detail::is_same<T, JsonArray>::value ||
detail::is_same<T, JsonArrayConst>::value ||
detail::is_same<T, JsonObject>::value ||
detail::is_same<T, JsonObjectConst>::value>::type* = 0)
: JsonDocument(alloc) {
set(src);
}
JsonDocument& operator=(JsonDocument src) {
swap(*this, src);
return *this;
}
template <typename T>
JsonDocument& operator=(const T& src) {
set(src);
return *this;
}
Allocator* allocator() const {
return resources_.allocator();
}
// Reduces the capacity of the memory pool to match the current usage.
// https://arduinojson.org/v7/api/jsondocument/shrinktofit/
void shrinkToFit() {
resources_.shrinkToFit();
}
// Casts the root to the specified type.
// https://arduinojson.org/v6/api/jsondocument/as/
// https://arduinojson.org/v7/api/jsondocument/as/
template <typename T>
T as() {
return getVariant().template as<T>();
}
// Casts the root to the specified type.
// https://arduinojson.org/v6/api/jsondocument/as/
// https://arduinojson.org/v7/api/jsondocument/as/
template <typename T>
T as() const {
return getVariant().template as<T>();
}
// Empties the document and resets the memory pool
// https://arduinojson.org/v6/api/jsondocument/clear/
// https://arduinojson.org/v7/api/jsondocument/clear/
void clear() {
_pool.clear();
_data.init();
resources_.clear();
data_.reset();
}
// Returns true if the root is of the specified type.
// https://arduinojson.org/v6/api/jsondocument/is/
// https://arduinojson.org/v7/api/jsondocument/is/
template <typename T>
bool is() {
return getVariant().template is<T>();
}
// Returns true if the root is of the specified type.
// https://arduinojson.org/v6/api/jsondocument/is/
// https://arduinojson.org/v7/api/jsondocument/is/
template <typename T>
bool is() const {
return getVariant().template is<T>();
}
// Returns true if the root is null.
// https://arduinojson.org/v6/api/jsondocument/isnull/
// https://arduinojson.org/v7/api/jsondocument/isnull/
bool isNull() const {
return getVariant().isNull();
}
// Returns the number of used bytes in the memory pool.
// https://arduinojson.org/v6/api/jsondocument/memoryusage/
size_t memoryUsage() const {
return _pool.size();
}
// Returns trues if the memory pool was too small.
// https://arduinojson.org/v6/api/jsondocument/overflowed/
// https://arduinojson.org/v7/api/jsondocument/overflowed/
bool overflowed() const {
return _pool.overflowed();
return resources_.overflowed();
}
// Returns the depth (nesting level) of the array.
// https://arduinojson.org/v6/api/jsondocument/nesting/
// https://arduinojson.org/v7/api/jsondocument/nesting/
size_t nesting() const {
return variantNesting(&_data);
}
// Returns the capacity of the memory pool.
// https://arduinojson.org/v6/api/jsondocument/capacity/
size_t capacity() const {
return _pool.capacity();
return data_.nesting(&resources_);
}
// Returns the number of elements in the root array or object.
// https://arduinojson.org/v6/api/jsondocument/size/
// https://arduinojson.org/v7/api/jsondocument/size/
size_t size() const {
return _data.size();
return data_.size(&resources_);
}
// Copies the specified document.
// https://arduinojson.org/v6/api/jsondocument/set/
// https://arduinojson.org/v7/api/jsondocument/set/
bool set(const JsonDocument& src) {
return to<JsonVariant>().set(src.as<JsonVariantConst>());
}
// Replaces the root with the specified value.
// https://arduinojson.org/v6/api/jsondocument/set/
// https://arduinojson.org/v7/api/jsondocument/set/
template <typename T>
typename detail::enable_if<!detail::is_base_of<JsonDocument, T>::value,
bool>::type
@@ -110,218 +146,226 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
}
// Clears the document and converts it to the specified type.
// https://arduinojson.org/v6/api/jsondocument/to/
// https://arduinojson.org/v7/api/jsondocument/to/
template <typename T>
typename detail::VariantTo<T>::type to() {
clear();
return getVariant().template to<T>();
}
// Creates an array and appends it to the root array.
// https://arduinojson.org/v6/api/jsondocument/createnestedarray/
JsonArray createNestedArray() {
return add().to<JsonArray>();
}
// Creates an array and adds it to the root object.
// https://arduinojson.org/v6/api/jsondocument/createnestedarray/
template <typename TChar>
JsonArray createNestedArray(TChar* key) {
return operator[](key).template to<JsonArray>();
}
// Creates an array and adds it to the root object.
// https://arduinojson.org/v6/api/jsondocument/createnestedarray/
template <typename TString>
JsonArray createNestedArray(const TString& key) {
return operator[](key).template to<JsonArray>();
}
// Creates an object and appends it to the root array.
// https://arduinojson.org/v6/api/jsondocument/createnestedobject/
JsonObject createNestedObject() {
return add().to<JsonObject>();
}
// Creates an object and adds it to the root object.
// https://arduinojson.org/v6/api/jsondocument/createnestedobject/
template <typename TChar>
JsonObject createNestedObject(TChar* key) {
return operator[](key).template to<JsonObject>();
}
// Creates an object and adds it to the root object.
// https://arduinojson.org/v6/api/jsondocument/createnestedobject/
template <typename TString>
JsonObject createNestedObject(const TString& key) {
return operator[](key).template to<JsonObject>();
}
// Returns true if the root object contains the specified key.
// https://arduinojson.org/v6/api/jsondocument/containskey/
// https://arduinojson.org/v7/api/jsondocument/containskey/
template <typename TChar>
bool containsKey(TChar* key) const {
return _data.getMember(detail::adaptString(key)) != 0;
return data_.getMember(detail::adaptString(key), &resources_) != 0;
}
// Returns true if the root object contains the specified key.
// https://arduinojson.org/v6/api/jsondocument/containskey/
// https://arduinojson.org/v7/api/jsondocument/containskey/
template <typename TString>
bool containsKey(const TString& key) const {
return _data.getMember(detail::adaptString(key)) != 0;
return data_.getMember(detail::adaptString(key), &resources_) != 0;
}
// Gets or sets a root object's member.
// https://arduinojson.org/v6/api/jsondocument/subscript/
// https://arduinojson.org/v7/api/jsondocument/subscript/
template <typename TString>
FORCE_INLINE typename detail::enable_if<
detail::IsString<TString>::value,
detail::MemberProxy<JsonDocument&, TString>>::type
typename detail::enable_if<detail::IsString<TString>::value,
detail::MemberProxy<JsonDocument&, TString>>::type
operator[](const TString& key) {
return {*this, key};
}
// Gets or sets a root object's member.
// https://arduinojson.org/v6/api/jsondocument/subscript/
// https://arduinojson.org/v7/api/jsondocument/subscript/
template <typename TChar>
FORCE_INLINE typename detail::enable_if<
detail::IsString<TChar*>::value,
detail::MemberProxy<JsonDocument&, TChar*>>::type
typename detail::enable_if<detail::IsString<TChar*>::value,
detail::MemberProxy<JsonDocument&, TChar*>>::type
operator[](TChar* key) {
return {*this, key};
}
// Gets a root object's member.
// https://arduinojson.org/v6/api/jsondocument/subscript/
// https://arduinojson.org/v7/api/jsondocument/subscript/
template <typename TString>
FORCE_INLINE typename detail::enable_if<detail::IsString<TString>::value,
JsonVariantConst>::type
typename detail::enable_if<detail::IsString<TString>::value,
JsonVariantConst>::type
operator[](const TString& key) const {
return JsonVariantConst(_data.getMember(detail::adaptString(key)));
return JsonVariantConst(
data_.getMember(detail::adaptString(key), &resources_), &resources_);
}
// Gets a root object's member.
// https://arduinojson.org/v6/api/jsondocument/subscript/
// https://arduinojson.org/v7/api/jsondocument/subscript/
template <typename TChar>
FORCE_INLINE typename detail::enable_if<detail::IsString<TChar*>::value,
JsonVariantConst>::type
typename detail::enable_if<detail::IsString<TChar*>::value,
JsonVariantConst>::type
operator[](TChar* key) const {
return JsonVariantConst(_data.getMember(detail::adaptString(key)));
return JsonVariantConst(
data_.getMember(detail::adaptString(key), &resources_), &resources_);
}
// Gets or sets a root array's element.
// https://arduinojson.org/v6/api/jsondocument/subscript/
FORCE_INLINE detail::ElementProxy<JsonDocument&> operator[](size_t index) {
// https://arduinojson.org/v7/api/jsondocument/subscript/
detail::ElementProxy<JsonDocument&> operator[](size_t index) {
return {*this, index};
}
// Gets a root array's member.
// https://arduinojson.org/v6/api/jsondocument/subscript/
FORCE_INLINE JsonVariantConst operator[](size_t index) const {
return JsonVariantConst(_data.getElement(index));
// https://arduinojson.org/v7/api/jsondocument/subscript/
JsonVariantConst operator[](size_t index) const {
return JsonVariantConst(data_.getElement(index, &resources_), &resources_);
}
// Appends a new (empty) element to the root array.
// Returns a reference to the new element.
// https://arduinojson.org/v7/api/jsondocument/add/
template <typename T>
typename detail::enable_if<!detail::is_same<T, JsonVariant>::value, T>::type
add() {
return add<JsonVariant>().to<T>();
}
// Appends a new (null) element to the root array.
// Returns a reference to the new element.
// https://arduinojson.org/v6/api/jsondocument/add/
FORCE_INLINE JsonVariant add() {
return JsonVariant(&_pool, _data.addElement(&_pool));
// https://arduinojson.org/v7/api/jsondocument/add/
template <typename T>
typename detail::enable_if<detail::is_same<T, JsonVariant>::value, T>::type
add() {
return JsonVariant(data_.addElement(&resources_), &resources_);
}
// Appends a value to the root array.
// https://arduinojson.org/v6/api/jsondocument/add/
// https://arduinojson.org/v7/api/jsondocument/add/
template <typename TValue>
FORCE_INLINE bool add(const TValue& value) {
return add().set(value);
bool add(const TValue& value) {
return add<JsonVariant>().set(value);
}
// Appends a value to the root array.
// https://arduinojson.org/v6/api/jsondocument/add/
// https://arduinojson.org/v7/api/jsondocument/add/
template <typename TChar>
FORCE_INLINE bool add(TChar* value) {
return add().set(value);
bool add(TChar* value) {
return add<JsonVariant>().set(value);
}
// Removes an element of the root array.
// ⚠️ Doesn't release the memory associated with the removed element.
// https://arduinojson.org/v6/api/jsondocument/remove/
FORCE_INLINE void remove(size_t index) {
_data.remove(index);
// https://arduinojson.org/v7/api/jsondocument/remove/
void remove(size_t index) {
detail::VariantData::removeElement(getData(), index, getResourceManager());
}
// Removes a member of the root object.
// ⚠️ Doesn't release the memory associated with the removed element.
// https://arduinojson.org/v6/api/jsondocument/remove/
// https://arduinojson.org/v7/api/jsondocument/remove/
template <typename TChar>
FORCE_INLINE typename detail::enable_if<detail::IsString<TChar*>::value>::type
remove(TChar* key) {
_data.remove(detail::adaptString(key));
typename detail::enable_if<detail::IsString<TChar*>::value>::type remove(
TChar* key) {
detail::VariantData::removeMember(getData(), detail::adaptString(key),
getResourceManager());
}
// Removes a member of the root object.
// ⚠️ Doesn't release the memory associated with the removed element.
// https://arduinojson.org/v6/api/jsondocument/remove/
// https://arduinojson.org/v7/api/jsondocument/remove/
template <typename TString>
FORCE_INLINE
typename detail::enable_if<detail::IsString<TString>::value>::type
remove(const TString& key) {
_data.remove(detail::adaptString(key));
typename detail::enable_if<detail::IsString<TString>::value>::type remove(
const TString& key) {
detail::VariantData::removeMember(getData(), detail::adaptString(key),
getResourceManager());
}
FORCE_INLINE operator JsonVariant() {
operator JsonVariant() {
return getVariant();
}
FORCE_INLINE operator JsonVariantConst() const {
operator JsonVariantConst() const {
return getVariant();
}
protected:
JsonDocument() : _pool(0, 0) {
_data.init();
friend void swap(JsonDocument& a, JsonDocument& b) {
swap(a.resources_, b.resources_);
swap_(a.data_, b.data_);
}
JsonDocument(detail::MemoryPool pool) : _pool(pool) {
_data.init();
// DEPRECATED: use add<JsonVariant>() instead
ARDUINOJSON_DEPRECATED("use add<JsonVariant>() instead")
JsonVariant add() {
return add<JsonVariant>();
}
JsonDocument(char* buf, size_t capa) : _pool(buf, capa) {
_data.init();
// DEPRECATED: use add<JsonArray>() instead
ARDUINOJSON_DEPRECATED("use add<JsonArray>() instead")
JsonArray createNestedArray() {
return add<JsonArray>();
}
~JsonDocument() {}
void replacePool(detail::MemoryPool pool) {
_pool = pool;
// DEPRECATED: use doc[key].to<JsonArray>() instead
template <typename TChar>
ARDUINOJSON_DEPRECATED("use doc[key].to<JsonArray>() instead")
JsonArray createNestedArray(TChar* key) {
return operator[](key).template to<JsonArray>();
}
// DEPRECATED: use doc[key].to<JsonArray>() instead
template <typename TString>
ARDUINOJSON_DEPRECATED("use doc[key].to<JsonArray>() instead")
JsonArray createNestedArray(const TString& key) {
return operator[](key).template to<JsonArray>();
}
// DEPRECATED: use add<JsonObject>() instead
ARDUINOJSON_DEPRECATED("use add<JsonObject>() instead")
JsonObject createNestedObject() {
return add<JsonObject>();
}
// DEPRECATED: use doc[key].to<JsonObject>() instead
template <typename TChar>
ARDUINOJSON_DEPRECATED("use doc[key].to<JsonObject>() instead")
JsonObject createNestedObject(TChar* key) {
return operator[](key).template to<JsonObject>();
}
// DEPRECATED: use doc[key].to<JsonObject>() instead
template <typename TString>
ARDUINOJSON_DEPRECATED("use doc[key].to<JsonObject>() instead")
JsonObject createNestedObject(const TString& key) {
return operator[](key).template to<JsonObject>();
}
// DEPRECATED: always returns zero
ARDUINOJSON_DEPRECATED("always returns zero")
size_t memoryUsage() const {
return 0;
}
private:
JsonVariant getVariant() {
return JsonVariant(&_pool, &_data);
return JsonVariant(&data_, &resources_);
}
JsonVariantConst getVariant() const {
return JsonVariantConst(&_data);
return JsonVariantConst(&data_, &resources_);
}
detail::MemoryPool _pool;
detail::VariantData _data;
protected:
detail::MemoryPool* getPool() {
return &_pool;
detail::ResourceManager* getResourceManager() {
return &resources_;
}
detail::VariantData* getData() {
return &_data;
return &data_;
}
const detail::VariantData* getData() const {
return &_data;
return &data_;
}
detail::VariantData* getOrCreateData() {
return &_data;
return &data_;
}
detail::ResourceManager resources_;
detail::VariantData data_;
};
inline void convertToJson(const JsonDocument& src, JsonVariant dst) {

View File

@@ -1,61 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Document/JsonDocument.hpp>
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
// A JsonDocument with a memory pool on the stack.
template <size_t desiredCapacity>
class StaticJsonDocument : public JsonDocument {
static const size_t _capacity =
detail::AddPadding<detail::Max<1, desiredCapacity>::value>::value;
public:
StaticJsonDocument() : JsonDocument(_buffer, _capacity) {}
StaticJsonDocument(const StaticJsonDocument& src)
: JsonDocument(_buffer, _capacity) {
set(src);
}
template <typename T>
StaticJsonDocument(
const T& src,
typename detail::enable_if<
detail::is_convertible<T, JsonVariantConst>::value>::type* = 0)
: JsonDocument(_buffer, _capacity) {
set(src);
}
// disambiguate
StaticJsonDocument(JsonVariant src) : JsonDocument(_buffer, _capacity) {
set(src);
}
StaticJsonDocument& operator=(const StaticJsonDocument& src) {
set(src);
return *this;
}
template <typename T>
StaticJsonDocument& operator=(const T& src) {
set(src);
return *this;
}
// Reclaims the memory leaked when removing and replacing values.
// https://arduinojson.org/v6/api/jsondocument/garbagecollect/
void garbageCollect() {
StaticJsonDocument tmp(*this);
set(tmp);
}
private:
char _buffer[_capacity];
};
ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -9,7 +9,7 @@
#include <ArduinoJson/Json/Latch.hpp>
#include <ArduinoJson/Json/Utf16.hpp>
#include <ArduinoJson/Json/Utf8.hpp>
#include <ArduinoJson/Memory/MemoryPool.hpp>
#include <ArduinoJson/Memory/ResourceManager.hpp>
#include <ArduinoJson/Numbers/parseNumber.hpp>
#include <ArduinoJson/Polyfills/assert.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp>
@@ -18,15 +18,14 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename TReader, typename TStringStorage>
template <typename TReader>
class JsonDeserializer {
public:
JsonDeserializer(MemoryPool* pool, TReader reader,
TStringStorage stringStorage)
: _stringStorage(stringStorage),
_foundSomething(false),
_latch(reader),
_pool(pool) {}
JsonDeserializer(ResourceManager* resources, TReader reader)
: stringBuilder_(resources),
foundSomething_(false),
latch_(reader),
resources_(resources) {}
template <typename TFilter>
DeserializationError parse(VariantData& variant, TFilter filter,
@@ -35,7 +34,7 @@ class JsonDeserializer {
err = parseVariant(variant, filter, nestingLimit);
if (!err && _latch.last() != 0 && !variant.isEnclosed()) {
if (!err && latch_.last() != 0 && variant.isFloat()) {
// We don't detect trailing characters earlier, so we need to check now
return DeserializationError::InvalidInput;
}
@@ -45,11 +44,11 @@ class JsonDeserializer {
private:
char current() {
return _latch.current();
return latch_.current();
}
void move() {
_latch.clear();
latch_.clear();
}
bool eat(char charToSkip) {
@@ -147,7 +146,7 @@ class JsonDeserializer {
template <typename TFilter>
DeserializationError::Code parseArray(
CollectionData& array, TFilter filter,
ArrayData& array, TFilter filter,
DeserializationOption::NestingLimit nestingLimit) {
DeserializationError::Code err;
@@ -167,18 +166,18 @@ class JsonDeserializer {
if (eat(']'))
return DeserializationError::Ok;
TFilter memberFilter = filter[0UL];
TFilter elementFilter = filter[0UL];
// Read each value
for (;;) {
if (memberFilter.allow()) {
if (elementFilter.allow()) {
// Allocate slot in array
VariantData* value = array.addElement(_pool);
VariantData* value = array.addElement(resources_);
if (!value)
return DeserializationError::NoMemory;
// 1 - Parse value
err = parseVariant(*value, memberFilter, nestingLimit.decrement());
err = parseVariant(*value, elementFilter, nestingLimit.decrement());
if (err)
return err;
} else {
@@ -233,7 +232,7 @@ class JsonDeserializer {
template <typename TFilter>
DeserializationError::Code parseObject(
CollectionData& object, TFilter filter,
ObjectData& object, TFilter filter,
DeserializationOption::NestingLimit nestingLimit) {
DeserializationError::Code err;
@@ -269,29 +268,26 @@ class JsonDeserializer {
if (!eat(':'))
return DeserializationError::InvalidInput;
JsonString key = _stringStorage.str();
JsonString key = stringBuilder_.str();
TFilter memberFilter = filter[key.c_str()];
if (memberFilter.allow()) {
VariantData* variant = object.getMember(adaptString(key.c_str()));
if (!variant) {
auto member = object.getMember(adaptString(key.c_str()), resources_);
if (!member) {
// Save key in memory pool.
// This MUST be done before adding the slot.
key = _stringStorage.save();
auto savedKey = stringBuilder_.save();
// Allocate slot in object
VariantSlot* slot = object.addSlot(_pool);
if (!slot)
member = object.addMember(savedKey, resources_);
if (!member)
return DeserializationError::NoMemory;
slot->setKey(key);
variant = slot->data();
} else {
member->setNull(resources_);
}
// Parse value
err = parseVariant(*variant, memberFilter, nestingLimit.decrement());
err = parseVariant(*member, memberFilter, nestingLimit.decrement());
if (err)
return err;
} else {
@@ -377,7 +373,7 @@ class JsonDeserializer {
}
DeserializationError::Code parseKey() {
_stringStorage.startString();
stringBuilder_.startString();
if (isQuote(current())) {
return parseQuotedString();
} else {
@@ -388,13 +384,13 @@ class JsonDeserializer {
DeserializationError::Code parseStringValue(VariantData& variant) {
DeserializationError::Code err;
_stringStorage.startString();
stringBuilder_.startString();
err = parseQuotedString();
if (err)
return err;
variant.setString(_stringStorage.save());
variant.setOwnedString(stringBuilder_.save());
return DeserializationError::Ok;
}
@@ -430,9 +426,9 @@ class JsonDeserializer {
if (err)
return err;
if (codepoint.append(codeunit))
Utf8::encodeCodepoint(codepoint.value(), _stringStorage);
Utf8::encodeCodepoint(codepoint.value(), stringBuilder_);
#else
_stringStorage.append('\\');
stringBuilder_.append('\\');
#endif
continue;
}
@@ -444,10 +440,10 @@ class JsonDeserializer {
move();
}
_stringStorage.append(c);
stringBuilder_.append(c);
}
if (!_stringStorage.isValid())
if (!stringBuilder_.isValid())
return DeserializationError::NoMemory;
return DeserializationError::Ok;
@@ -460,14 +456,14 @@ class JsonDeserializer {
if (canBeInNonQuotedString(c)) { // no quotes
do {
move();
_stringStorage.append(c);
stringBuilder_.append(c);
c = current();
} while (canBeInNonQuotedString(c));
} else {
return DeserializationError::InvalidInput;
}
if (!_stringStorage.isValid())
if (!stringBuilder_.isValid())
return DeserializationError::NoMemory;
return DeserializationError::Ok;
@@ -516,12 +512,12 @@ class JsonDeserializer {
char c = current();
while (canBeInNumber(c) && n < 63) {
move();
_buffer[n++] = c;
buffer_[n++] = c;
c = current();
}
_buffer[n] = 0;
buffer_[n] = 0;
if (!parseNumber(_buffer, result))
if (!parseNumber(buffer_, result))
return DeserializationError::InvalidInput;
return DeserializationError::Ok;
@@ -585,7 +581,7 @@ class JsonDeserializer {
switch (current()) {
// end of string
case '\0':
return _foundSomething ? DeserializationError::IncompleteInput
return foundSomething_ ? DeserializationError::IncompleteInput
: DeserializationError::EmptyInput;
// spaces
@@ -640,7 +636,7 @@ class JsonDeserializer {
#endif
default:
_foundSomething = true;
foundSomething_ = true;
return DeserializationError::Ok;
}
}
@@ -659,11 +655,11 @@ class JsonDeserializer {
return DeserializationError::Ok;
}
TStringStorage _stringStorage;
bool _foundSomething;
Latch<TReader> _latch;
MemoryPool* _pool;
char _buffer[64]; // using a member instead of a local variable because it
StringBuilder stringBuilder_;
bool foundSomething_;
Latch<TReader> latch_;
ResourceManager* resources_;
char buffer_[64]; // using a member instead of a local variable because it
// ended in the recursive path after compiler inlined the
// code
};
@@ -673,21 +669,27 @@ ARDUINOJSON_END_PRIVATE_NAMESPACE
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
// Parses a JSON input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/json/deserializejson/
template <typename... Args>
DeserializationError deserializeJson(JsonDocument& doc, Args&&... args) {
// https://arduinojson.org/v7/api/json/deserializejson/
template <typename TDestination, typename... Args>
typename detail::enable_if<
detail::is_deserialize_destination<TDestination>::value,
DeserializationError>::type
deserializeJson(TDestination&& dst, Args&&... args) {
using namespace detail;
return deserialize<JsonDeserializer>(doc, detail::forward<Args>(args)...);
}
// Parses a JSON input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/json/deserializejson/
template <typename TChar, typename... Args>
DeserializationError deserializeJson(JsonDocument& doc, TChar* input,
Args&&... args) {
using namespace detail;
return deserialize<JsonDeserializer>(doc, input,
return deserialize<JsonDeserializer>(detail::forward<TDestination>(dst),
detail::forward<Args>(args)...);
}
// Parses a JSON input, filters, and puts the result in a JsonDocument.
// https://arduinojson.org/v7/api/json/deserializejson/
template <typename TDestination, typename TChar, typename... Args>
typename detail::enable_if<
detail::is_deserialize_destination<TDestination>::value,
DeserializationError>::type
deserializeJson(TDestination&& dst, TChar* input, Args&&... args) {
using namespace detail;
return deserialize<JsonDeserializer>(detail::forward<TDestination>(dst),
input, detail::forward<Args>(args)...);
}
ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -7,112 +7,118 @@
#include <ArduinoJson/Json/TextFormatter.hpp>
#include <ArduinoJson/Serialization/measure.hpp>
#include <ArduinoJson/Serialization/serialize.hpp>
#include <ArduinoJson/Variant/Visitor.hpp>
#include <ArduinoJson/Variant/VariantDataVisitor.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename TWriter>
class JsonSerializer : public Visitor<size_t> {
class JsonSerializer : public VariantDataVisitor<size_t> {
public:
static const bool producesText = true;
JsonSerializer(TWriter writer) : _formatter(writer) {}
JsonSerializer(TWriter writer, const ResourceManager* resources)
: formatter_(writer), resources_(resources) {}
FORCE_INLINE size_t visitArray(const CollectionData& array) {
size_t visit(const ArrayData& array) {
write('[');
const VariantSlot* slot = array.head();
auto slotId = array.head();
while (slotId != NULL_SLOT) {
auto slot = resources_->getSlot(slotId);
while (slot != 0) {
slot->data()->accept(*this);
slot = slot->next();
if (slot == 0)
break;
slotId = slot->next();
write(',');
if (slotId != NULL_SLOT)
write(',');
}
write(']');
return bytesWritten();
}
size_t visitObject(const CollectionData& object) {
size_t visit(const ObjectData& object) {
write('{');
const VariantSlot* slot = object.head();
auto slotId = object.head();
while (slot != 0) {
_formatter.writeString(slot->key());
while (slotId != NULL_SLOT) {
auto slot = resources_->getSlot(slotId);
formatter_.writeString(slot->key());
write(':');
slot->data()->accept(*this);
slot = slot->next();
if (slot == 0)
break;
slotId = slot->next();
write(',');
if (slotId != NULL_SLOT)
write(',');
}
write('}');
return bytesWritten();
}
size_t visitFloat(JsonFloat value) {
_formatter.writeFloat(value);
size_t visit(JsonFloat value) {
formatter_.writeFloat(value);
return bytesWritten();
}
size_t visitString(const char* value) {
_formatter.writeString(value);
size_t visit(const char* value) {
formatter_.writeString(value);
return bytesWritten();
}
size_t visitString(const char* value, size_t n) {
_formatter.writeString(value, n);
size_t visit(JsonString value) {
formatter_.writeString(value.c_str(), value.size());
return bytesWritten();
}
size_t visitRawJson(const char* data, size_t n) {
_formatter.writeRaw(data, n);
size_t visit(RawString value) {
formatter_.writeRaw(value.data(), value.size());
return bytesWritten();
}
size_t visitSignedInteger(JsonInteger value) {
_formatter.writeInteger(value);
size_t visit(JsonInteger value) {
formatter_.writeInteger(value);
return bytesWritten();
}
size_t visitUnsignedInteger(JsonUInt value) {
_formatter.writeInteger(value);
size_t visit(JsonUInt value) {
formatter_.writeInteger(value);
return bytesWritten();
}
size_t visitBoolean(bool value) {
_formatter.writeBoolean(value);
size_t visit(bool value) {
formatter_.writeBoolean(value);
return bytesWritten();
}
size_t visitNull() {
_formatter.writeRaw("null");
size_t visit(nullptr_t) {
formatter_.writeRaw("null");
return bytesWritten();
}
protected:
size_t bytesWritten() const {
return _formatter.bytesWritten();
return formatter_.bytesWritten();
}
void write(char c) {
_formatter.writeRaw(c);
formatter_.writeRaw(c);
}
void write(const char* s) {
_formatter.writeRaw(s);
formatter_.writeRaw(s);
}
private:
TextFormatter<TWriter> _formatter;
TextFormatter<TWriter> formatter_;
protected:
const ResourceManager* resources_;
};
ARDUINOJSON_END_PRIVATE_NAMESPACE
@@ -120,7 +126,7 @@ ARDUINOJSON_END_PRIVATE_NAMESPACE
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
// Produces a minified JSON document.
// https://arduinojson.org/v6/api/json/serializejson/
// https://arduinojson.org/v7/api/json/serializejson/
template <typename TDestination>
size_t serializeJson(JsonVariantConst source, TDestination& destination) {
using namespace detail;
@@ -128,7 +134,7 @@ size_t serializeJson(JsonVariantConst source, TDestination& destination) {
}
// Produces a minified JSON document.
// https://arduinojson.org/v6/api/json/serializejson/
// https://arduinojson.org/v7/api/json/serializejson/
inline size_t serializeJson(JsonVariantConst source, void* buffer,
size_t bufferSize) {
using namespace detail;
@@ -136,7 +142,7 @@ inline size_t serializeJson(JsonVariantConst source, void* buffer,
}
// Computes the length of the document that serializeJson() produces.
// https://arduinojson.org/v6/api/json/measurejson/
// https://arduinojson.org/v7/api/json/measurejson/
inline size_t measureJson(JsonVariantConst source) {
using namespace detail;
return measure<JsonSerializer>(source);

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -11,45 +11,45 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename TReader>
class Latch {
public:
Latch(TReader reader) : _reader(reader), _loaded(false) {
Latch(TReader reader) : reader_(reader), loaded_(false) {
#if ARDUINOJSON_DEBUG
_ended = false;
ended_ = false;
#endif
}
void clear() {
_loaded = false;
loaded_ = false;
}
int last() const {
return _current;
return current_;
}
FORCE_INLINE char current() {
if (!_loaded) {
if (!loaded_) {
load();
}
return _current;
return current_;
}
private:
void load() {
ARDUINOJSON_ASSERT(!_ended);
int c = _reader.read();
ARDUINOJSON_ASSERT(!ended_);
int c = reader_.read();
#if ARDUINOJSON_DEBUG
if (c <= 0)
_ended = true;
ended_ = true;
#endif
_current = static_cast<char>(c > 0 ? c : 0);
_loaded = true;
current_ = static_cast<char>(c > 0 ? c : 0);
loaded_ = true;
}
TReader _reader;
char _current; // NOLINT(clang-analyzer-optin.cplusplus.UninitializedObject)
TReader reader_;
char current_; // NOLINT(clang-analyzer-optin.cplusplus.UninitializedObject)
// Not initialized in constructor (+10 bytes on AVR)
bool _loaded;
bool loaded_;
#if ARDUINOJSON_DEBUG
bool _ended;
bool ended_;
#endif
};

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -16,21 +16,22 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
typedef JsonSerializer<TWriter> base;
public:
PrettyJsonSerializer(TWriter writer) : base(writer), _nesting(0) {}
PrettyJsonSerializer(TWriter writer, const ResourceManager* resources)
: base(writer, resources), nesting_(0) {}
size_t visitArray(const CollectionData& array) {
const VariantSlot* slot = array.head();
if (slot) {
size_t visit(const ArrayData& array) {
auto it = array.createIterator(base::resources_);
if (!it.done()) {
base::write("[\r\n");
_nesting++;
while (slot != 0) {
nesting_++;
while (!it.done()) {
indent();
slot->data()->accept(*this);
it->accept(*this);
slot = slot->next();
base::write(slot ? ",\r\n" : "\r\n");
it.next(base::resources_);
base::write(it.done() ? "\r\n" : ",\r\n");
}
_nesting--;
nesting_--;
indent();
base::write("]");
} else {
@@ -39,21 +40,21 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
return this->bytesWritten();
}
size_t visitObject(const CollectionData& object) {
const VariantSlot* slot = object.head();
if (slot) {
size_t visit(const ObjectData& object) {
auto it = object.createIterator(base::resources_);
if (!it.done()) {
base::write("{\r\n");
_nesting++;
while (slot != 0) {
nesting_++;
while (!it.done()) {
indent();
base::visitString(slot->key());
base::visit(it.key());
base::write(": ");
slot->data()->accept(*this);
it->accept(*this);
slot = slot->next();
base::write(slot ? ",\r\n" : "\r\n");
it.next(base::resources_);
base::write(it.done() ? "\r\n" : ",\r\n");
}
_nesting--;
nesting_--;
indent();
base::write("}");
} else {
@@ -62,13 +63,15 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
return this->bytesWritten();
}
using base::visit;
private:
void indent() {
for (uint8_t i = 0; i < _nesting; i++)
for (uint8_t i = 0; i < nesting_; i++)
base::write(ARDUINOJSON_TAB);
}
uint8_t _nesting;
uint8_t nesting_;
};
ARDUINOJSON_END_PRIVATE_NAMESPACE
@@ -76,7 +79,7 @@ ARDUINOJSON_END_PRIVATE_NAMESPACE
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
// Produces JsonDocument to create a prettified JSON document.
// https://arduinojson.org/v6/api/json/serializejsonpretty/
// https://arduinojson.org/v7/api/json/serializejsonpretty/
template <typename TDestination>
size_t serializeJsonPretty(JsonVariantConst source, TDestination& destination) {
using namespace ArduinoJson::detail;
@@ -84,7 +87,7 @@ size_t serializeJsonPretty(JsonVariantConst source, TDestination& destination) {
}
// Produces JsonDocument to create a prettified JSON document.
// https://arduinojson.org/v6/api/json/serializejsonpretty/
// https://arduinojson.org/v7/api/json/serializejsonpretty/
inline size_t serializeJsonPretty(JsonVariantConst source, void* buffer,
size_t bufferSize) {
using namespace ArduinoJson::detail;
@@ -92,7 +95,7 @@ inline size_t serializeJsonPretty(JsonVariantConst source, void* buffer,
}
// Computes the length of the document that serializeJsonPretty() produces.
// https://arduinojson.org/v6/api/json/measurejsonpretty/
// https://arduinojson.org/v7/api/json/measurejsonpretty/
inline size_t measureJsonPretty(JsonVariantConst source) {
using namespace ArduinoJson::detail;
return measure<PrettyJsonSerializer>(source);

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -20,13 +20,13 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename TWriter>
class TextFormatter {
public:
explicit TextFormatter(TWriter writer) : _writer(writer) {}
explicit TextFormatter(TWriter writer) : writer_(writer) {}
TextFormatter& operator=(const TextFormatter&) = delete;
// Returns the number of bytes sent to the TWriter implementation.
size_t bytesWritten() const {
return _writer.count();
return writer_.count();
}
void writeBoolean(bool value) {
@@ -146,28 +146,28 @@ class TextFormatter {
}
void writeRaw(const char* s) {
_writer.write(reinterpret_cast<const uint8_t*>(s), strlen(s));
writer_.write(reinterpret_cast<const uint8_t*>(s), strlen(s));
}
void writeRaw(const char* s, size_t n) {
_writer.write(reinterpret_cast<const uint8_t*>(s), n);
writer_.write(reinterpret_cast<const uint8_t*>(s), n);
}
void writeRaw(const char* begin, const char* end) {
_writer.write(reinterpret_cast<const uint8_t*>(begin),
writer_.write(reinterpret_cast<const uint8_t*>(begin),
static_cast<size_t>(end - begin));
}
template <size_t N>
void writeRaw(const char (&s)[N]) {
_writer.write(reinterpret_cast<const uint8_t*>(s), N - 1);
writer_.write(reinterpret_cast<const uint8_t*>(s), N - 1);
}
void writeRaw(char c) {
_writer.write(static_cast<uint8_t>(c));
writer_.write(static_cast<uint8_t>(c));
}
protected:
CountingDecorator<TWriter> _writer;
CountingDecorator<TWriter> writer_;
};
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -31,31 +31,31 @@ inline bool isLowSurrogate(uint16_t codeunit) {
class Codepoint {
public:
Codepoint() : _highSurrogate(0), _codepoint(0) {}
Codepoint() : highSurrogate_(0), codepoint_(0) {}
bool append(uint16_t codeunit) {
if (isHighSurrogate(codeunit)) {
_highSurrogate = codeunit & 0x3FF;
highSurrogate_ = codeunit & 0x3FF;
return false;
}
if (isLowSurrogate(codeunit)) {
_codepoint =
uint32_t(0x10000 + ((_highSurrogate << 10) | (codeunit & 0x3FF)));
codepoint_ =
uint32_t(0x10000 + ((highSurrogate_ << 10) | (codeunit & 0x3FF)));
return true;
}
_codepoint = codeunit;
codepoint_ = codeunit;
return true;
}
uint32_t value() const {
return _codepoint;
return codepoint_;
}
private:
uint16_t _highSurrogate;
uint32_t _codepoint;
uint16_t highSurrogate_;
uint32_t codepoint_;
};
} // namespace Utf16
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -0,0 +1,49 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Namespace.hpp>
#include <stdlib.h> // malloc, free
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
class Allocator {
public:
virtual void* allocate(size_t size) = 0;
virtual void deallocate(void* ptr) = 0;
virtual void* reallocate(void* ptr, size_t new_size) = 0;
protected:
~Allocator() = default;
};
namespace detail {
class DefaultAllocator : public Allocator {
public:
void* allocate(size_t size) override {
return malloc(size);
}
void deallocate(void* ptr) override {
free(ptr);
}
void* reallocate(void* ptr, size_t new_size) override {
return realloc(ptr, new_size);
}
static Allocator* instance() {
static DefaultAllocator allocator;
return &allocator;
}
private:
DefaultAllocator() = default;
~DefaultAllocator() = default;
};
} // namespace detail
ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@@ -1,253 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Memory/Alignment.hpp>
#include <ArduinoJson/Polyfills/assert.hpp>
#include <ArduinoJson/Polyfills/mpl/max.hpp>
#include <ArduinoJson/Strings/StringAdapters.hpp>
#include <ArduinoJson/Variant/VariantSlot.hpp>
#include <string.h> // memmove
#define JSON_STRING_SIZE(SIZE) (SIZE + 1)
// Computes the size required to store an array in a JsonDocument.
// https://arduinojson.org/v6/how-to/determine-the-capacity-of-the-jsondocument/
#define JSON_ARRAY_SIZE(NUMBER_OF_ELEMENTS) \
((NUMBER_OF_ELEMENTS) * sizeof(ArduinoJson::detail::VariantSlot))
// Returns the size (in bytes) of an object with n elements.
// Can be very handy to determine the size of a StaticMemoryPool.
#define JSON_OBJECT_SIZE(NUMBER_OF_ELEMENTS) \
((NUMBER_OF_ELEMENTS) * sizeof(ArduinoJson::detail::VariantSlot))
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
// _begin _end
// v v
// +-------------+--------------+--------------+
// | strings... | (free) | ...variants |
// +-------------+--------------+--------------+
// ^ ^
// _left _right
class MemoryPool {
public:
MemoryPool(char* buf, size_t capa)
: _begin(buf),
_left(buf),
_right(buf ? buf + capa : 0),
_end(buf ? buf + capa : 0),
_overflowed(false) {
ARDUINOJSON_ASSERT(isAligned(_begin));
ARDUINOJSON_ASSERT(isAligned(_right));
ARDUINOJSON_ASSERT(isAligned(_end));
}
void* buffer() {
return _begin; // NOLINT(clang-analyzer-unix.Malloc)
// movePointers() alters this pointer
}
// Gets the capacity of the memoryPool in bytes
size_t capacity() const {
return size_t(_end - _begin);
}
size_t size() const {
return size_t(_left - _begin + _end - _right);
}
bool overflowed() const {
return _overflowed;
}
VariantSlot* allocVariant() {
return allocRight<VariantSlot>();
}
template <typename TAdaptedString>
const char* saveString(TAdaptedString str) {
if (str.isNull())
return 0;
#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
const char* existingCopy = findString(str);
if (existingCopy)
return existingCopy;
#endif
size_t n = str.size();
char* newCopy = allocString(n + 1);
if (newCopy) {
stringGetChars(str, newCopy, n);
newCopy[n] = 0; // force null-terminator
}
return newCopy;
}
void getFreeZone(char** zoneStart, size_t* zoneSize) const {
*zoneStart = _left;
*zoneSize = size_t(_right - _left);
}
const char* saveStringFromFreeZone(size_t len) {
#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
const char* dup = findString(adaptString(_left, len));
if (dup)
return dup;
#endif
const char* str = _left;
_left += len;
*_left++ = 0;
checkInvariants();
return str;
}
void markAsOverflowed() {
_overflowed = true;
}
void clear() {
_left = _begin;
_right = _end;
_overflowed = false;
}
bool canAlloc(size_t bytes) const {
return _left + bytes <= _right;
}
bool owns(void* p) const {
return _begin <= p && p < _end;
}
// Workaround for missing placement new
void* operator new(size_t, void* p) {
return p;
}
// Squash the free space between strings and variants
//
// _begin _end
// v v
// +-------------+--------------+
// | strings... | ...variants |
// +-------------+--------------+
// ^
// _left _right
//
// This funcion is called before a realloc.
ptrdiff_t squash() {
char* new_right = addPadding(_left);
if (new_right >= _right)
return 0;
size_t right_size = static_cast<size_t>(_end - _right);
memmove(new_right, _right, right_size);
ptrdiff_t bytes_reclaimed = _right - new_right;
_right = new_right;
_end = new_right + right_size;
return bytes_reclaimed;
}
// Move all pointers together
// This funcion is called after a realloc.
void movePointers(ptrdiff_t offset) {
_begin += offset;
_left += offset;
_right += offset;
_end += offset;
}
private:
void checkInvariants() {
ARDUINOJSON_ASSERT(_begin <= _left);
ARDUINOJSON_ASSERT(_left <= _right);
ARDUINOJSON_ASSERT(_right <= _end);
ARDUINOJSON_ASSERT(isAligned(_right));
}
#if ARDUINOJSON_ENABLE_STRING_DEDUPLICATION
template <typename TAdaptedString>
const char* findString(const TAdaptedString& str) const {
size_t n = str.size();
for (char* next = _begin; next + n < _left; ++next) {
if (next[n] == '\0' && stringEquals(str, adaptString(next, n)))
return next;
// jump to next terminator
while (*next)
++next;
}
return 0;
}
#endif
char* allocString(size_t n) {
if (!canAlloc(n)) {
_overflowed = true;
return 0;
}
char* s = _left;
_left += n;
checkInvariants();
return s;
}
template <typename T>
T* allocRight() {
return reinterpret_cast<T*>(allocRight(sizeof(T)));
}
void* allocRight(size_t bytes) {
if (!canAlloc(bytes)) {
_overflowed = true;
return 0;
}
_right -= bytes;
return _right;
}
char *_begin, *_left, *_right, *_end;
bool _overflowed;
};
template <typename TAdaptedString, typename TCallback>
bool storeString(MemoryPool* pool, TAdaptedString str,
StringStoragePolicy::Copy, TCallback callback) {
const char* copy = pool->saveString(str);
JsonString storedString(copy, str.size(), JsonString::Copied);
callback(storedString);
return copy != 0;
}
template <typename TAdaptedString, typename TCallback>
bool storeString(MemoryPool*, TAdaptedString str, StringStoragePolicy::Link,
TCallback callback) {
JsonString storedString(str.data(), str.size(), JsonString::Linked);
callback(storedString);
return !str.isNull();
}
template <typename TAdaptedString, typename TCallback>
bool storeString(MemoryPool* pool, TAdaptedString str,
StringStoragePolicy::LinkOrCopy policy, TCallback callback) {
if (policy.link)
return storeString(pool, str, StringStoragePolicy::Link(), callback);
else
return storeString(pool, str, StringStoragePolicy::Copy(), callback);
}
template <typename TAdaptedString, typename TCallback>
bool storeString(MemoryPool* pool, TAdaptedString str, TCallback callback) {
return storeString(pool, str, str.storagePolicy(), callback);
}
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -0,0 +1,127 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Memory/Allocator.hpp>
#include <ArduinoJson/Memory/StringPool.hpp>
#include <ArduinoJson/Memory/VariantPoolList.hpp>
#include <ArduinoJson/Polyfills/assert.hpp>
#include <ArduinoJson/Polyfills/utility.hpp>
#include <ArduinoJson/Strings/StringAdapters.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
class VariantSlot;
class VariantPool;
class ResourceManager {
public:
ResourceManager(Allocator* allocator = DefaultAllocator::instance())
: allocator_(allocator), overflowed_(false) {}
~ResourceManager() {
stringPool_.clear(allocator_);
variantPools_.clear(allocator_);
}
ResourceManager(const ResourceManager&) = delete;
ResourceManager& operator=(const ResourceManager& src) = delete;
friend void swap(ResourceManager& a, ResourceManager& b) {
swap(a.stringPool_, b.stringPool_);
swap(a.variantPools_, b.variantPools_);
swap_(a.allocator_, b.allocator_);
swap_(a.overflowed_, b.overflowed_);
}
Allocator* allocator() const {
return allocator_;
}
size_t size() const {
return VariantPool::slotsToBytes(variantPools_.usage()) +
stringPool_.size();
}
bool overflowed() const {
return overflowed_;
}
SlotWithId allocSlot() {
auto p = variantPools_.allocSlot(allocator_);
if (!p)
overflowed_ = true;
return p;
}
void freeSlot(SlotWithId id) {
variantPools_.freeSlot(id);
}
VariantSlot* getSlot(SlotId id) const {
return variantPools_.getSlot(id);
}
template <typename TAdaptedString>
StringNode* saveString(TAdaptedString str) {
if (str.isNull())
return 0;
auto node = stringPool_.add(str, allocator_);
if (!node)
overflowed_ = true;
return node;
}
void saveString(StringNode* node) {
stringPool_.add(node);
}
template <typename TAdaptedString>
StringNode* getString(const TAdaptedString& str) const {
return stringPool_.get(str);
}
StringNode* createString(size_t length) {
auto node = StringNode::create(length, allocator_);
if (!node)
overflowed_ = true;
return node;
}
StringNode* resizeString(StringNode* node, size_t length) {
node = StringNode::resize(node, length, allocator_);
if (!node)
overflowed_ = true;
return node;
}
void destroyString(StringNode* node) {
StringNode::destroy(node, allocator_);
}
void dereferenceString(const char* s) {
stringPool_.dereference(s, allocator_);
}
void clear() {
variantPools_.clear(allocator_);
overflowed_ = false;
stringPool_.clear(allocator_);
}
void shrinkToFit() {
variantPools_.shrinkToFit(allocator_);
}
private:
Allocator* allocator_;
bool overflowed_;
StringPool stringPool_;
VariantPoolList variantPools_;
};
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -0,0 +1,80 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Memory/ResourceManager.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
class StringBuilder {
public:
static const size_t initialCapacity = 31;
StringBuilder(ResourceManager* resources) : resources_(resources) {}
~StringBuilder() {
if (node_)
resources_->destroyString(node_);
}
void startString() {
size_ = 0;
if (!node_)
node_ = resources_->createString(initialCapacity);
}
StringNode* save() {
ARDUINOJSON_ASSERT(node_ != nullptr);
node_->data[size_] = 0;
StringNode* node = resources_->getString(adaptString(node_->data, size_));
if (!node) {
node = resources_->resizeString(node_, size_);
ARDUINOJSON_ASSERT(node != nullptr); // realloc to smaller can't fail
resources_->saveString(node);
node_ = nullptr; // next time we need a new string
} else {
node->references++;
}
return node;
}
void append(const char* s) {
while (*s)
append(*s++);
}
void append(const char* s, size_t n) {
while (n-- > 0) // TODO: memcpy
append(*s++);
}
void append(char c) {
if (node_ && size_ == node_->length)
node_ = resources_->resizeString(node_, size_ * 2U + 1);
if (node_)
node_->data[size_++] = c;
}
bool isValid() const {
return node_ != nullptr;
}
size_t size() const {
return size_;
}
JsonString str() const {
ARDUINOJSON_ASSERT(node_ != nullptr);
node_->data[size_] = 0;
return JsonString(node_->data, size_, JsonString::Copied);
}
private:
ResourceManager* resources_;
StringNode* node_ = nullptr;
size_t size_ = 0;
};
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -0,0 +1,73 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Memory/Allocator.hpp>
#include <ArduinoJson/Namespace.hpp>
#include <ArduinoJson/Polyfills/assert.hpp>
#include <ArduinoJson/Polyfills/integer.hpp>
#include <ArduinoJson/Polyfills/limits.hpp>
#include <stddef.h> // offsetof
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
struct StringNode {
// Use the same type as SlotId to store the reference count
// (there can never be more references than slots)
using references_type = uint_t<ARDUINOJSON_SLOT_ID_SIZE * 8>::type;
using length_type = uint_t<ARDUINOJSON_STRING_LENGTH_SIZE * 8>::type;
struct StringNode* next;
references_type references;
length_type length;
char data[1];
static constexpr size_t maxLength = numeric_limits<length_type>::highest();
static constexpr size_t sizeForLength(size_t n) {
return n + 1 + offsetof(StringNode, data);
}
static StringNode* create(size_t length, Allocator* allocator) {
if (length > maxLength)
return nullptr;
auto node = reinterpret_cast<StringNode*>(
allocator->allocate(sizeForLength(length)));
if (node) {
node->length = length_type(length);
node->references = 1;
}
return node;
}
static StringNode* resize(StringNode* node, size_t length,
Allocator* allocator) {
ARDUINOJSON_ASSERT(node != nullptr);
StringNode* newNode;
if (length <= maxLength)
newNode = reinterpret_cast<StringNode*>(
allocator->reallocate(node, sizeForLength(length)));
else
newNode = nullptr;
if (newNode)
newNode->length = length_type(length);
else
allocator->deallocate(node);
return newNode;
}
static void destroy(StringNode* node, Allocator* allocator) {
allocator->deallocate(node);
}
};
// Returns the size (in bytes) of an string with n characters.
constexpr size_t sizeofString(size_t n) {
return StringNode::sizeForLength(n);
}
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -0,0 +1,105 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Memory/Allocator.hpp>
#include <ArduinoJson/Memory/StringNode.hpp>
#include <ArduinoJson/Polyfills/assert.hpp>
#include <ArduinoJson/Polyfills/utility.hpp>
#include <ArduinoJson/Strings/StringAdapters.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
class VariantSlot;
class VariantPool;
class StringPool {
public:
StringPool() = default;
StringPool(const StringPool&) = delete;
void operator=(StringPool&& src) = delete;
~StringPool() {
ARDUINOJSON_ASSERT(strings_ == nullptr);
}
friend void swap(StringPool& a, StringPool& b) {
swap_(a.strings_, b.strings_);
}
void clear(Allocator* allocator) {
while (strings_) {
auto node = strings_;
strings_ = node->next;
StringNode::destroy(node, allocator);
}
}
size_t size() const {
size_t total = 0;
for (auto node = strings_; node; node = node->next)
total += sizeofString(node->length);
return total;
}
template <typename TAdaptedString>
StringNode* add(TAdaptedString str, Allocator* allocator) {
ARDUINOJSON_ASSERT(str.isNull() == false);
auto node = get(str);
if (node) {
node->references++;
return node;
}
size_t n = str.size();
node = StringNode::create(n, allocator);
if (!node)
return nullptr;
stringGetChars(str, node->data, n);
node->data[n] = 0; // force NUL terminator
add(node);
return node;
}
void add(StringNode* node) {
ARDUINOJSON_ASSERT(node != nullptr);
node->next = strings_;
strings_ = node;
}
template <typename TAdaptedString>
StringNode* get(const TAdaptedString& str) const {
for (auto node = strings_; node; node = node->next) {
if (stringEquals(str, adaptString(node->data, node->length)))
return node;
}
return nullptr;
}
void dereference(const char* s, Allocator* allocator) {
StringNode* prev = nullptr;
for (auto node = strings_; node; node = node->next) {
if (node->data == s) {
if (--node->references == 0) {
if (prev)
prev->next = node->next;
else
strings_ = node->next;
StringNode::destroy(node, allocator);
}
return;
}
prev = node;
}
}
private:
StringNode* strings_ = nullptr;
};
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -0,0 +1,63 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Memory/ResourceManager.hpp>
#include <ArduinoJson/Polyfills/assert.hpp>
#include <ArduinoJson/Polyfills/integer.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
class VariantSlot;
using SlotId = uint_t<ARDUINOJSON_SLOT_ID_SIZE * 8>::type;
using SlotCount = SlotId;
const SlotId NULL_SLOT = SlotId(-1);
class SlotWithId {
public:
SlotWithId() : slot_(nullptr), id_(NULL_SLOT) {}
SlotWithId(VariantSlot* slot, SlotId id) : slot_(slot), id_(id) {
ARDUINOJSON_ASSERT((slot == nullptr) == (id == NULL_SLOT));
}
SlotId id() const {
return id_;
}
operator VariantSlot*() {
return slot_;
}
VariantSlot* operator->() {
ARDUINOJSON_ASSERT(slot_ != nullptr);
return slot_;
}
private:
VariantSlot* slot_;
SlotId id_;
};
class VariantPool {
public:
void create(SlotCount cap, Allocator* allocator);
void destroy(Allocator* allocator);
SlotWithId allocSlot();
VariantSlot* getSlot(SlotId id) const;
void clear();
void shrinkToFit(Allocator*);
SlotCount usage() const;
static SlotCount bytesToSlots(size_t);
static size_t slotsToBytes(SlotCount);
private:
SlotCount capacity_;
SlotCount usage_;
VariantSlot* slots_;
};
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -0,0 +1,81 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Memory/VariantPool.hpp>
#include <ArduinoJson/Variant/VariantSlot.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
inline void VariantPool::create(SlotCount cap, Allocator* allocator) {
ARDUINOJSON_ASSERT(cap > 0);
slots_ =
reinterpret_cast<VariantSlot*>(allocator->allocate(slotsToBytes(cap)));
capacity_ = slots_ ? cap : 0;
usage_ = 0;
}
inline void VariantPool::destroy(Allocator* allocator) {
if (slots_)
allocator->deallocate(slots_);
slots_ = nullptr;
capacity_ = 0;
usage_ = 0;
}
inline void VariantPool::shrinkToFit(Allocator* allocator) {
auto newSlots = reinterpret_cast<VariantSlot*>(
allocator->reallocate(slots_, slotsToBytes(usage_)));
if (newSlots) {
slots_ = newSlots;
capacity_ = usage_;
}
}
inline SlotWithId VariantPool::allocSlot() {
if (!slots_)
return {};
if (usage_ >= capacity_)
return {};
auto index = usage_++;
auto slot = &slots_[index];
return {new (slot) VariantSlot, SlotId(index)};
}
inline VariantSlot* VariantPool::getSlot(SlotId id) const {
ARDUINOJSON_ASSERT(id < usage_);
return &slots_[id];
}
inline SlotCount VariantPool::usage() const {
return usage_;
}
inline void VariantPool::clear() {
usage_ = 0;
}
inline SlotCount VariantPool::bytesToSlots(size_t n) {
return static_cast<SlotCount>(n / sizeof(VariantSlot));
}
inline size_t VariantPool::slotsToBytes(SlotCount n) {
return n * sizeof(VariantSlot);
}
inline SlotWithId VariantPoolList::allocFromFreeList() {
ARDUINOJSON_ASSERT(freeList_ != NULL_SLOT);
auto id = freeList_;
auto slot = getSlot(freeList_);
freeList_ = slot->next();
return {new (slot) VariantSlot, id};
}
inline void VariantPoolList::freeSlot(SlotWithId slot) {
slot->setNext(freeList_);
freeList_ = slot.id();
}
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -0,0 +1,189 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Memory/VariantPool.hpp>
#include <ArduinoJson/Polyfills/assert.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
using PoolCount = SlotId;
class VariantPoolList {
public:
VariantPoolList() = default;
~VariantPoolList() {
ARDUINOJSON_ASSERT(count_ == 0);
}
friend void swap(VariantPoolList& a, VariantPoolList& b) {
bool aUsedPreallocated = a.pools_ == a.preallocatedPools_;
bool bUsedPreallocated = b.pools_ == b.preallocatedPools_;
// Who is using preallocated pools?
if (aUsedPreallocated && bUsedPreallocated) {
// both of us => swap preallocated pools
for (PoolCount i = 0; i < ARDUINOJSON_INITIAL_POOL_COUNT; i++)
swap_(a.preallocatedPools_[i], b.preallocatedPools_[i]);
} else if (bUsedPreallocated) {
// only b => copy b's preallocated pools and give him a's pointer
for (PoolCount i = 0; i < b.count_; i++)
a.preallocatedPools_[i] = b.preallocatedPools_[i];
b.pools_ = a.pools_;
a.pools_ = a.preallocatedPools_;
} else if (aUsedPreallocated) {
// only a => copy a's preallocated pools and give him b's pointer
for (PoolCount i = 0; i < a.count_; i++)
b.preallocatedPools_[i] = a.preallocatedPools_[i];
a.pools_ = b.pools_;
b.pools_ = b.preallocatedPools_;
} else {
// neither => swap pointers
swap_(a.pools_, b.pools_);
}
swap_(a.count_, b.count_);
swap_(a.capacity_, b.capacity_);
swap_(a.freeList_, b.freeList_);
}
VariantPoolList& operator=(VariantPoolList&& src) {
ARDUINOJSON_ASSERT(count_ == 0);
if (src.pools_ == src.preallocatedPools_) {
memcpy(preallocatedPools_, src.preallocatedPools_,
sizeof(preallocatedPools_));
pools_ = preallocatedPools_;
} else {
pools_ = src.pools_;
src.pools_ = nullptr;
}
count_ = src.count_;
capacity_ = src.capacity_;
src.count_ = 0;
src.capacity_ = 0;
return *this;
}
SlotWithId allocSlot(Allocator* allocator) {
// try to allocate from free list
if (freeList_ != NULL_SLOT) {
return allocFromFreeList();
}
// try to allocate from last pool (other pools are full)
if (count_) {
auto slot = allocFromLastPool();
if (slot)
return slot;
}
// create a new pool and try again
auto pool = addPool(allocator);
if (!pool)
return {};
return allocFromLastPool();
}
void freeSlot(SlotWithId slot);
VariantSlot* getSlot(SlotId id) const {
if (id == NULL_SLOT)
return nullptr;
auto poolIndex = SlotId(id / ARDUINOJSON_POOL_CAPACITY);
auto indexInPool = SlotId(id % ARDUINOJSON_POOL_CAPACITY);
ARDUINOJSON_ASSERT(poolIndex < count_);
return pools_[poolIndex].getSlot(indexInPool);
}
void clear(Allocator* allocator) {
for (PoolCount i = 0; i < count_; i++)
pools_[i].destroy(allocator);
count_ = 0;
freeList_ = NULL_SLOT;
if (pools_ != preallocatedPools_) {
allocator->deallocate(pools_);
pools_ = preallocatedPools_;
capacity_ = ARDUINOJSON_INITIAL_POOL_COUNT;
}
}
SlotCount usage() const {
SlotCount total = 0;
for (PoolCount i = 0; i < count_; i++)
total = SlotCount(total + pools_[i].usage());
return total;
}
void shrinkToFit(Allocator* allocator) {
if (count_ > 0)
pools_[count_ - 1].shrinkToFit(allocator);
if (pools_ != preallocatedPools_ && count_ != capacity_) {
pools_ = static_cast<VariantPool*>(
allocator->reallocate(pools_, count_ * sizeof(VariantPool)));
ARDUINOJSON_ASSERT(pools_ != nullptr); // realloc to smaller can't fail
capacity_ = count_;
}
}
private:
SlotWithId allocFromFreeList();
SlotWithId allocFromLastPool() {
ARDUINOJSON_ASSERT(count_ > 0);
auto poolIndex = SlotId(count_ - 1);
auto slot = pools_[poolIndex].allocSlot();
if (!slot)
return {};
return {slot, SlotId(poolIndex * ARDUINOJSON_POOL_CAPACITY + slot.id())};
}
VariantPool* addPool(Allocator* allocator) {
if (count_ == capacity_ && !increaseCapacity(allocator))
return nullptr;
auto pool = &pools_[count_++];
SlotCount poolCapacity = ARDUINOJSON_POOL_CAPACITY;
if (count_ == maxPools) // last pool is smaller because of NULL_SLOT
poolCapacity--;
pool->create(poolCapacity, allocator);
return pool;
}
bool increaseCapacity(Allocator* allocator) {
if (capacity_ == maxPools)
return false;
void* newPools;
auto newCapacity = PoolCount(capacity_ * 2);
if (pools_ == preallocatedPools_) {
newPools = allocator->allocate(newCapacity * sizeof(VariantPool));
if (!newPools)
return false;
memcpy(newPools, preallocatedPools_, sizeof(preallocatedPools_));
} else {
newPools =
allocator->reallocate(pools_, newCapacity * sizeof(VariantPool));
if (!newPools)
return false;
}
pools_ = static_cast<VariantPool*>(newPools);
capacity_ = newCapacity;
return true;
}
VariantPool preallocatedPools_[ARDUINOJSON_INITIAL_POOL_COUNT];
VariantPool* pools_ = preallocatedPools_;
PoolCount count_ = 0;
PoolCount capacity_ = ARDUINOJSON_INITIAL_POOL_COUNT;
SlotId freeList_ = NULL_SLOT;
public:
static const PoolCount maxPools =
PoolCount(NULL_SLOT / ARDUINOJSON_POOL_CAPACITY + 1);
};
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -12,45 +12,47 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
template <typename T>
class SerializedValue {
public:
explicit SerializedValue(T str) : _str(str) {}
explicit SerializedValue(T str) : str_(str) {}
operator T() const {
return _str;
return str_;
}
const char* data() const {
return _str.c_str();
return str_.c_str();
}
size_t size() const {
// CAUTION: the old Arduino String doesn't have size()
return _str.length();
return str_.length();
}
private:
T _str;
T str_;
};
template <typename TChar>
class SerializedValue<TChar*> {
public:
explicit SerializedValue(TChar* p, size_t n) : _data(p), _size(n) {}
explicit SerializedValue(TChar* p, size_t n) : data_(p), size_(n) {}
operator TChar*() const {
return _data;
return data_;
}
TChar* data() const {
return _data;
return data_;
}
size_t size() const {
return _size;
return size_;
}
private:
TChar* _data;
size_t _size;
TChar* data_;
size_t size_;
};
using RawString = SerializedValue<const char*>;
template <typename T>
inline SerializedValue<T> serialized(T str) {
return SerializedValue<T>(str);

View File

@@ -1,11 +1,11 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Deserialization/deserialize.hpp>
#include <ArduinoJson/Memory/MemoryPool.hpp>
#include <ArduinoJson/Memory/ResourceManager.hpp>
#include <ArduinoJson/MsgPack/endianess.hpp>
#include <ArduinoJson/MsgPack/ieee754.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp>
@@ -13,22 +13,21 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename TReader, typename TStringStorage>
template <typename TReader>
class MsgPackDeserializer {
public:
MsgPackDeserializer(MemoryPool* pool, TReader reader,
TStringStorage stringStorage)
: _pool(pool),
_reader(reader),
_stringStorage(stringStorage),
_foundSomething(false) {}
MsgPackDeserializer(ResourceManager* resources, TReader reader)
: resources_(resources),
reader_(reader),
stringBuilder_(resources),
foundSomething_(false) {}
template <typename TFilter>
DeserializationError parse(VariantData& variant, TFilter filter,
DeserializationOption::NestingLimit nestingLimit) {
DeserializationError::Code err;
err = parseVariant(&variant, filter, nestingLimit);
return _foundSomething ? err : DeserializationError::EmptyInput;
return foundSomething_ ? err : DeserializationError::EmptyInput;
}
private:
@@ -43,7 +42,7 @@ class MsgPackDeserializer {
if (err)
return err;
_foundSomething = true;
foundSomething_ = true;
bool allowValue = filter.allowValue();
@@ -224,7 +223,7 @@ class MsgPackDeserializer {
}
DeserializationError::Code readByte(uint8_t& value) {
int c = _reader.read();
int c = reader_.read();
if (c < 0)
return DeserializationError::IncompleteInput;
value = static_cast<uint8_t>(c);
@@ -232,7 +231,7 @@ class MsgPackDeserializer {
}
DeserializationError::Code readBytes(uint8_t* p, size_t n) {
if (_reader.readBytes(reinterpret_cast<char*>(p), n) == n)
if (reader_.readBytes(reinterpret_cast<char*>(p), n) == n)
return DeserializationError::Ok;
return DeserializationError::IncompleteInput;
}
@@ -244,7 +243,7 @@ class MsgPackDeserializer {
DeserializationError::Code skipBytes(size_t n) {
for (; n; --n) {
if (_reader.read() < 0)
if (reader_.read() < 0)
return DeserializationError::IncompleteInput;
}
return DeserializationError::Ok;
@@ -371,14 +370,14 @@ class MsgPackDeserializer {
if (err)
return err;
variant->setString(_stringStorage.save());
variant->setOwnedString(stringBuilder_.save());
return DeserializationError::Ok;
}
DeserializationError::Code readString(size_t n) {
DeserializationError::Code err;
_stringStorage.startString();
stringBuilder_.startString();
for (; n; --n) {
uint8_t c;
@@ -386,10 +385,10 @@ class MsgPackDeserializer {
if (err)
return err;
_stringStorage.append(static_cast<char>(c));
stringBuilder_.append(static_cast<char>(c));
}
if (!_stringStorage.isValid())
if (!stringBuilder_.isValid())
return DeserializationError::NoMemory;
return DeserializationError::Ok;
@@ -420,7 +419,7 @@ class MsgPackDeserializer {
bool allowArray = filter.allowArray();
CollectionData* array;
ArrayData* array;
if (allowArray) {
ARDUINOJSON_ASSERT(variant != 0);
array = &variant->toArray();
@@ -428,21 +427,21 @@ class MsgPackDeserializer {
array = 0;
}
TFilter memberFilter = filter[0U];
TFilter elementFilter = filter[0U];
for (; n; --n) {
VariantData* value;
if (memberFilter.allow()) {
if (elementFilter.allow()) {
ARDUINOJSON_ASSERT(array != 0);
value = array->addElement(_pool);
value = array->addElement(resources_);
if (!value)
return DeserializationError::NoMemory;
} else {
value = 0;
}
err = parseVariant(value, memberFilter, nestingLimit.decrement());
err = parseVariant(value, elementFilter, nestingLimit.decrement());
if (err)
return err;
}
@@ -473,7 +472,7 @@ class MsgPackDeserializer {
if (nestingLimit.reached())
return DeserializationError::TooDeep;
CollectionData* object;
ObjectData* object;
if (filter.allowObject()) {
ARDUINOJSON_ASSERT(variant != 0);
object = &variant->toObject();
@@ -486,7 +485,7 @@ class MsgPackDeserializer {
if (err)
return err;
JsonString key = _stringStorage.str();
JsonString key = stringBuilder_.str();
TFilter memberFilter = filter[key.c_str()];
VariantData* member;
@@ -494,16 +493,11 @@ class MsgPackDeserializer {
ARDUINOJSON_ASSERT(object != 0);
// Save key in memory pool.
// This MUST be done before adding the slot.
key = _stringStorage.save();
auto savedKey = stringBuilder_.save();
VariantSlot* slot = object->addSlot(_pool);
if (!slot)
member = object->addMember(savedKey, resources_);
if (!member)
return DeserializationError::NoMemory;
slot->setKey(key);
member = slot->data();
} else {
member = 0;
}
@@ -554,10 +548,10 @@ class MsgPackDeserializer {
return skipBytes(size + 1U);
}
MemoryPool* _pool;
TReader _reader;
TStringStorage _stringStorage;
bool _foundSomething;
ResourceManager* resources_;
TReader reader_;
StringBuilder stringBuilder_;
bool foundSomething_;
};
ARDUINOJSON_END_PRIVATE_NAMESPACE
@@ -565,20 +559,27 @@ ARDUINOJSON_END_PRIVATE_NAMESPACE
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
// Parses a MessagePack input and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
template <typename... Args>
DeserializationError deserializeMsgPack(JsonDocument& doc, Args&&... args) {
// https://arduinojson.org/v7/api/msgpack/deserializemsgpack/
template <typename TDestination, typename... Args>
typename detail::enable_if<
detail::is_deserialize_destination<TDestination>::value,
DeserializationError>::type
deserializeMsgPack(TDestination&& dst, Args&&... args) {
using namespace detail;
return deserialize<MsgPackDeserializer>(doc, detail::forward<Args>(args)...);
return deserialize<MsgPackDeserializer>(detail::forward<TDestination>(dst),
detail::forward<Args>(args)...);
}
// Parses a MessagePack input and puts the result in a JsonDocument.
// https://arduinojson.org/v6/api/msgpack/deserializemsgpack/
template <typename TChar, typename... Args>
DeserializationError deserializeMsgPack(JsonDocument& doc, TChar* input,
Args&&... args) {
// https://arduinojson.org/v7/api/msgpack/deserializemsgpack/
template <typename TDestination, typename TChar, typename... Args>
typename detail::enable_if<
detail::is_deserialize_destination<TDestination>::value,
DeserializationError>::type
deserializeMsgPack(TDestination&& dst, TChar* input, Args&&... args) {
using namespace detail;
return deserialize<MsgPackDeserializer>(doc, input,
return deserialize<MsgPackDeserializer>(detail::forward<TDestination>(dst),
input,
detail::forward<Args>(args)...);
}

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -15,18 +15,21 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename TWriter>
class MsgPackSerializer : public Visitor<size_t> {
class MsgPackSerializer : public VariantDataVisitor<size_t> {
public:
static const bool producesText = false;
MsgPackSerializer(TWriter writer) : _writer(writer) {}
MsgPackSerializer(TWriter writer, const ResourceManager* resources)
: writer_(writer), resources_(resources) {}
template <typename T>
typename enable_if<sizeof(T) == 4, size_t>::type visitFloat(T value32) {
typename enable_if<is_floating_point<T>::value && sizeof(T) == 4,
size_t>::type
visit(T value32) {
if (canConvertNumber<JsonInteger>(value32)) {
JsonInteger truncatedValue = JsonInteger(value32);
if (value32 == T(truncatedValue))
return visitSignedInteger(truncatedValue);
return visit(truncatedValue);
}
writeByte(0xCA);
writeInteger(value32);
@@ -35,19 +38,20 @@ class MsgPackSerializer : public Visitor<size_t> {
template <typename T>
ARDUINOJSON_NO_SANITIZE("float-cast-overflow")
typename enable_if<sizeof(T) == 8, size_t>::type visitFloat(T value64) {
typename enable_if<is_floating_point<T>::value && sizeof(T) == 8,
size_t>::type visit(T value64) {
float value32 = float(value64);
if (value32 == value64)
return visitFloat(value32);
return visit(value32);
writeByte(0xCB);
writeInteger(value64);
return bytesWritten();
}
size_t visitArray(const CollectionData& array) {
size_t n = array.size();
size_t visit(const ArrayData& array) {
size_t n = array.size(resources_);
if (n < 0x10) {
writeByte(uint8_t(0x90 + array.size()));
writeByte(uint8_t(0x90 + n));
} else if (n < 0x10000) {
writeByte(0xDC);
writeInteger(uint16_t(n));
@@ -55,14 +59,19 @@ class MsgPackSerializer : public Visitor<size_t> {
writeByte(0xDD);
writeInteger(uint32_t(n));
}
for (const VariantSlot* slot = array.head(); slot; slot = slot->next()) {
auto slotId = array.head();
while (slotId != NULL_SLOT) {
auto slot = resources_->getSlot(slotId);
slot->data()->accept(*this);
slotId = slot->next();
}
return bytesWritten();
}
size_t visitObject(const CollectionData& object) {
size_t n = object.size();
size_t visit(const ObjectData& object) {
size_t n = object.size(resources_);
if (n < 0x10) {
writeByte(uint8_t(0x80 + n));
} else if (n < 0x10000) {
@@ -72,20 +81,27 @@ class MsgPackSerializer : public Visitor<size_t> {
writeByte(0xDF);
writeInteger(uint32_t(n));
}
for (const VariantSlot* slot = object.head(); slot; slot = slot->next()) {
visitString(slot->key());
auto slotId = object.head();
while (slotId != NULL_SLOT) {
auto slot = resources_->getSlot(slotId);
visit(slot->key());
slot->data()->accept(*this);
slotId = slot->next();
}
return bytesWritten();
}
size_t visitString(const char* value) {
return visitString(value, strlen(value));
size_t visit(const char* value) {
return visit(JsonString(value));
}
size_t visitString(const char* value, size_t n) {
size_t visit(JsonString value) {
ARDUINOJSON_ASSERT(value != NULL);
auto n = value.size();
if (n < 0x20) {
writeByte(uint8_t(0xA0 + n));
} else if (n < 0x100) {
@@ -98,18 +114,18 @@ class MsgPackSerializer : public Visitor<size_t> {
writeByte(0xDB);
writeInteger(uint32_t(n));
}
writeBytes(reinterpret_cast<const uint8_t*>(value), n);
writeBytes(reinterpret_cast<const uint8_t*>(value.c_str()), n);
return bytesWritten();
}
size_t visitRawJson(const char* data, size_t size) {
writeBytes(reinterpret_cast<const uint8_t*>(data), size);
size_t visit(RawString value) {
writeBytes(reinterpret_cast<const uint8_t*>(value.data()), value.size());
return bytesWritten();
}
size_t visitSignedInteger(JsonInteger value) {
size_t visit(JsonInteger value) {
if (value > 0) {
visitUnsignedInteger(static_cast<JsonUInt>(value));
visit(static_cast<JsonUInt>(value));
} else if (value >= -0x20) {
writeInteger(int8_t(value));
} else if (value >= -0x80) {
@@ -137,7 +153,7 @@ class MsgPackSerializer : public Visitor<size_t> {
return bytesWritten();
}
size_t visitUnsignedInteger(JsonUInt value) {
size_t visit(JsonUInt value) {
if (value <= 0x7F) {
writeInteger(uint8_t(value));
} else if (value <= 0xFF) {
@@ -165,27 +181,27 @@ class MsgPackSerializer : public Visitor<size_t> {
return bytesWritten();
}
size_t visitBoolean(bool value) {
size_t visit(bool value) {
writeByte(value ? 0xC3 : 0xC2);
return bytesWritten();
}
size_t visitNull() {
size_t visit(nullptr_t) {
writeByte(0xC0);
return bytesWritten();
}
private:
size_t bytesWritten() const {
return _writer.count();
return writer_.count();
}
void writeByte(uint8_t c) {
_writer.write(c);
writer_.write(c);
}
void writeBytes(const uint8_t* p, size_t n) {
_writer.write(p, n);
writer_.write(p, n);
}
template <typename T>
@@ -194,7 +210,8 @@ class MsgPackSerializer : public Visitor<size_t> {
writeBytes(reinterpret_cast<uint8_t*>(&value), sizeof(value));
}
CountingDecorator<TWriter> _writer;
CountingDecorator<TWriter> writer_;
const ResourceManager* resources_;
};
ARDUINOJSON_END_PRIVATE_NAMESPACE
@@ -202,7 +219,7 @@ ARDUINOJSON_END_PRIVATE_NAMESPACE
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
// Produces a MessagePack document.
// https://arduinojson.org/v6/api/msgpack/serializemsgpack/
// https://arduinojson.org/v7/api/msgpack/serializemsgpack/
template <typename TDestination>
inline size_t serializeMsgPack(JsonVariantConst source, TDestination& output) {
using namespace ArduinoJson::detail;
@@ -210,7 +227,7 @@ inline size_t serializeMsgPack(JsonVariantConst source, TDestination& output) {
}
// Produces a MessagePack document.
// https://arduinojson.org/v6/api/msgpack/serializemsgpack/
// https://arduinojson.org/v7/api/msgpack/serializemsgpack/
inline size_t serializeMsgPack(JsonVariantConst source, void* output,
size_t size) {
using namespace ArduinoJson::detail;
@@ -218,7 +235,7 @@ inline size_t serializeMsgPack(JsonVariantConst source, void* output,
}
// Computes the length of the document that serializeMsgPack() produces.
// https://arduinojson.org/v6/api/msgpack/measuremsgpack/
// https://arduinojson.org/v7/api/msgpack/measuremsgpack/
inline size_t measureMsgPack(JsonVariantConst source) {
using namespace ArduinoJson::detail;
return measure<MsgPackSerializer>(source);

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -10,17 +10,16 @@
#ifndef ARDUINOJSON_VERSION_NAMESPACE
# define ARDUINOJSON_VERSION_NAMESPACE \
ARDUINOJSON_CONCAT3( \
ARDUINOJSON_CONCAT4(V, ARDUINOJSON_VERSION_MAJOR, \
ARDUINOJSON_VERSION_MINOR, \
ARDUINOJSON_VERSION_REVISION), \
ARDUINOJSON_BIN2ALPHA( \
ARDUINOJSON_ENABLE_PROGMEM, ARDUINOJSON_USE_LONG_LONG, \
ARDUINOJSON_USE_DOUBLE, ARDUINOJSON_ENABLE_STRING_DEDUPLICATION), \
ARDUINOJSON_BIN2ALPHA( \
ARDUINOJSON_ENABLE_NAN, ARDUINOJSON_ENABLE_INFINITY, \
ARDUINOJSON_ENABLE_COMMENTS, ARDUINOJSON_DECODE_UNICODE))
# define ARDUINOJSON_VERSION_NAMESPACE \
ARDUINOJSON_CONCAT4(ARDUINOJSON_VERSION_MACRO, \
ARDUINOJSON_BIN2ALPHA(ARDUINOJSON_ENABLE_PROGMEM, \
ARDUINOJSON_USE_LONG_LONG, \
ARDUINOJSON_USE_DOUBLE, 1), \
ARDUINOJSON_BIN2ALPHA(ARDUINOJSON_ENABLE_NAN, \
ARDUINOJSON_ENABLE_INFINITY, \
ARDUINOJSON_ENABLE_COMMENTS, \
ARDUINOJSON_DECODE_UNICODE), \
ARDUINOJSON_SLOT_ID_SIZE)
#endif

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -25,4 +25,4 @@ ARDUINOJSON_END_PUBLIC_NAMESPACE
static_assert(sizeof(T) <= sizeof(ArduinoJson::JsonInteger), \
"To use 64-bit integers with ArduinoJson, you must set " \
"ARDUINOJSON_USE_LONG_LONG to 1. See " \
"https://arduinojson.org/v6/api/config/use_long_long/");
"https://arduinojson.org/v7/api/config/use_long_long/");

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -146,8 +146,7 @@ inline bool parseNumber(const char* s, VariantData& result) {
template <typename T>
inline T parseNumber(const char* s) {
VariantData value;
value.init(); // VariantData is a POD, so it has no constructor
parseNumber(s, value);
return Converter<T>::fromJson(JsonVariantConst(&value));
return Converter<T>::fromJson(JsonVariantConst(&value, nullptr));
}
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -12,7 +12,7 @@ ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
class JsonArray;
// A reference to an object in a JsonDocument.
// https://arduinojson.org/v6/api/jsonobject/
// https://arduinojson.org/v7/api/jsonobject/
class JsonObject : public detail::VariantOperators<JsonObject> {
friend class detail::VariantAttorney;
@@ -20,232 +20,196 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
typedef JsonObjectIterator iterator;
// Creates an unbound reference.
FORCE_INLINE JsonObject() : _data(0), _pool(0) {}
JsonObject() : data_(0), resources_(0) {}
// INTERNAL USE ONLY
FORCE_INLINE JsonObject(detail::MemoryPool* buf, detail::CollectionData* data)
: _data(data), _pool(buf) {}
JsonObject(detail::ObjectData* data, detail::ResourceManager* resource)
: data_(data), resources_(resource) {}
operator JsonVariant() const {
void* data = _data; // prevent warning cast-align
return JsonVariant(_pool, reinterpret_cast<detail::VariantData*>(data));
void* data = data_; // prevent warning cast-align
return JsonVariant(reinterpret_cast<detail::VariantData*>(data),
resources_);
}
operator JsonObjectConst() const {
return JsonObjectConst(_data);
return JsonObjectConst(data_, resources_);
}
operator JsonVariantConst() const {
return JsonVariantConst(collectionToVariant(_data));
return JsonVariantConst(collectionToVariant(data_), resources_);
}
// Returns true if the reference is unbound.
// https://arduinojson.org/v6/api/jsonobject/isnull/
FORCE_INLINE bool isNull() const {
return _data == 0;
// https://arduinojson.org/v7/api/jsonobject/isnull/
bool isNull() const {
return data_ == 0;
}
// Returns true if the reference is bound.
// https://arduinojson.org/v6/api/jsonobject/isnull/
FORCE_INLINE operator bool() const {
return _data != 0;
}
// Returns the number of bytes occupied by the object.
// https://arduinojson.org/v6/api/jsonobject/memoryusage/
FORCE_INLINE size_t memoryUsage() const {
return _data ? _data->memoryUsage() : 0;
// https://arduinojson.org/v7/api/jsonobject/isnull/
operator bool() const {
return data_ != 0;
}
// Returns the depth (nesting level) of the object.
// https://arduinojson.org/v6/api/jsonobject/nesting/
FORCE_INLINE size_t nesting() const {
return variantNesting(collectionToVariant(_data));
// https://arduinojson.org/v7/api/jsonobject/nesting/
size_t nesting() const {
return detail::VariantData::nesting(collectionToVariant(data_), resources_);
}
// Returns the number of members in the object.
// https://arduinojson.org/v6/api/jsonobject/size/
FORCE_INLINE size_t size() const {
return _data ? _data->size() : 0;
// https://arduinojson.org/v7/api/jsonobject/size/
size_t size() const {
return data_ ? data_->size(resources_) : 0;
}
// Returns an iterator to the first key-value pair of the object.
// https://arduinojson.org/v6/api/jsonobject/begin/
FORCE_INLINE iterator begin() const {
if (!_data)
// https://arduinojson.org/v7/api/jsonobject/begin/
iterator begin() const {
if (!data_)
return iterator();
return iterator(_pool, _data->head());
return iterator(data_->createIterator(resources_), resources_);
}
// Returns an iterator following the last key-value pair of the object.
// https://arduinojson.org/v6/api/jsonobject/end/
FORCE_INLINE iterator end() const {
// https://arduinojson.org/v7/api/jsonobject/end/
iterator end() const {
return iterator();
}
// Removes all the members of the object.
// ⚠️ Doesn't release the memory associated with the removed members.
// https://arduinojson.org/v6/api/jsonobject/clear/
// https://arduinojson.org/v7/api/jsonobject/clear/
void clear() const {
if (!_data)
return;
_data->clear();
detail::ObjectData::clear(data_, resources_);
}
// Copies an object.
// https://arduinojson.org/v6/api/jsonobject/set/
FORCE_INLINE bool set(JsonObjectConst src) {
if (!_data || !src._data)
// https://arduinojson.org/v7/api/jsonobject/set/
bool set(JsonObjectConst src) {
if (!data_ || !src.data_)
return false;
return _data->copyFrom(*src._data, _pool);
}
// Compares the content of two objects.
FORCE_INLINE bool operator==(JsonObject rhs) const {
return JsonObjectConst(_data) == JsonObjectConst(rhs._data);
clear();
for (auto kvp : src) {
if (!operator[](kvp.key()).set(kvp.value()))
return false;
}
return true;
}
// Gets or sets the member with specified key.
// https://arduinojson.org/v6/api/jsonobject/subscript/
// https://arduinojson.org/v7/api/jsonobject/subscript/
template <typename TString>
FORCE_INLINE
typename detail::enable_if<detail::IsString<TString>::value,
detail::MemberProxy<JsonObject, TString>>::type
operator[](const TString& key) const {
typename detail::enable_if<detail::IsString<TString>::value,
detail::MemberProxy<JsonObject, TString>>::type
operator[](const TString& key) const {
return {*this, key};
}
// Gets or sets the member with specified key.
// https://arduinojson.org/v6/api/jsonobject/subscript/
// https://arduinojson.org/v7/api/jsonobject/subscript/
template <typename TChar>
FORCE_INLINE
typename detail::enable_if<detail::IsString<TChar*>::value,
detail::MemberProxy<JsonObject, TChar*>>::type
operator[](TChar* key) const {
typename detail::enable_if<detail::IsString<TChar*>::value,
detail::MemberProxy<JsonObject, TChar*>>::type
operator[](TChar* key) const {
return {*this, key};
}
// Removes the member at the specified iterator.
// ⚠️ Doesn't release the memory associated with the removed member.
// https://arduinojson.org/v6/api/jsonobject/remove/
// https://arduinojson.org/v7/api/jsonobject/remove/
FORCE_INLINE void remove(iterator it) const {
if (!_data)
return;
_data->removeSlot(it._slot);
detail::ObjectData::remove(data_, it.iterator_, resources_);
}
// Removes the member with the specified key.
// ⚠️ Doesn't release the memory associated with the removed member.
// https://arduinojson.org/v6/api/jsonobject/remove/
// https://arduinojson.org/v7/api/jsonobject/remove/
template <typename TString>
FORCE_INLINE void remove(const TString& key) const {
removeMember(detail::adaptString(key));
detail::ObjectData::removeMember(data_, detail::adaptString(key),
resources_);
}
// Removes the member with the specified key.
// ⚠️ Doesn't release the memory associated with the removed member.
// https://arduinojson.org/v6/api/jsonobject/remove/
// https://arduinojson.org/v7/api/jsonobject/remove/
template <typename TChar>
FORCE_INLINE void remove(TChar* key) const {
removeMember(detail::adaptString(key));
detail::ObjectData::removeMember(data_, detail::adaptString(key),
resources_);
}
// Returns true if the object contains the specified key.
// https://arduinojson.org/v6/api/jsonobject/containskey/
// https://arduinojson.org/v7/api/jsonobject/containskey/
template <typename TString>
FORCE_INLINE
typename detail::enable_if<detail::IsString<TString>::value, bool>::type
containsKey(const TString& key) const {
return getMember(detail::adaptString(key)) != 0;
typename detail::enable_if<detail::IsString<TString>::value, bool>::type
containsKey(const TString& key) const {
return detail::ObjectData::getMember(data_, detail::adaptString(key),
resources_) != 0;
}
// Returns true if the object contains the specified key.
// https://arduinojson.org/v6/api/jsonobject/containskey/
// https://arduinojson.org/v7/api/jsonobject/containskey/
template <typename TChar>
FORCE_INLINE
typename detail::enable_if<detail::IsString<TChar*>::value, bool>::type
containsKey(TChar* key) const {
return getMember(detail::adaptString(key)) != 0;
typename detail::enable_if<detail::IsString<TChar*>::value, bool>::type
containsKey(TChar* key) const {
return detail::ObjectData::getMember(data_, detail::adaptString(key),
resources_) != 0;
}
// Creates an array and adds it to the object.
// https://arduinojson.org/v6/api/jsonobject/createnestedarray/
template <typename TString>
FORCE_INLINE JsonArray createNestedArray(const TString& key) const;
// Creates an array and adds it to the object.
// https://arduinojson.org/v6/api/jsonobject/createnestedarray/
// DEPRECATED: use obj[key].to<JsonArray>() instead
template <typename TChar>
FORCE_INLINE JsonArray createNestedArray(TChar* key) const;
ARDUINOJSON_DEPRECATED("use obj[key].to<JsonArray>() instead")
JsonArray createNestedArray(TChar* key) const {
return operator[](key).template to<JsonArray>();
}
// Creates an object and adds it to the object.
// https://arduinojson.org/v6/api/jsonobject/createnestedobject/
// DEPRECATED: use obj[key].to<JsonArray>() instead
template <typename TString>
JsonObject createNestedObject(const TString& key) const {
ARDUINOJSON_DEPRECATED("use obj[key].to<JsonArray>() instead")
JsonArray createNestedArray(const TString& key) const {
return operator[](key).template to<JsonArray>();
}
// DEPRECATED: use obj[key].to<JsonObject>() instead
template <typename TChar>
ARDUINOJSON_DEPRECATED("use obj[key].to<JsonObject>() instead")
JsonObject createNestedObject(TChar* key) {
return operator[](key).template to<JsonObject>();
}
// Creates an object and adds it to the object.
// https://arduinojson.org/v6/api/jsonobject/createnestedobject/
template <typename TChar>
JsonObject createNestedObject(TChar* key) const {
// DEPRECATED: use obj[key].to<JsonObject>() instead
template <typename TString>
ARDUINOJSON_DEPRECATED("use obj[key].to<JsonObject>() instead")
JsonObject createNestedObject(const TString& key) {
return operator[](key).template to<JsonObject>();
}
// DEPRECATED: always returns zero
ARDUINOJSON_DEPRECATED("always returns zero")
size_t memoryUsage() const {
return 0;
}
private:
detail::MemoryPool* getPool() const {
return _pool;
detail::ResourceManager* getResourceManager() const {
return resources_;
}
detail::VariantData* getData() const {
return detail::collectionToVariant(_data);
return detail::collectionToVariant(data_);
}
detail::VariantData* getOrCreateData() const {
return detail::collectionToVariant(_data);
return detail::collectionToVariant(data_);
}
template <typename TAdaptedString>
inline detail::VariantData* getMember(TAdaptedString key) const {
if (!_data)
return 0;
return _data->getMember(key);
}
template <typename TAdaptedString>
void removeMember(TAdaptedString key) const {
if (!_data)
return;
_data->removeMember(key);
}
detail::CollectionData* _data;
detail::MemoryPool* _pool;
};
template <>
struct Converter<JsonObject> : private detail::VariantAttorney {
static void toJson(JsonVariantConst src, JsonVariant dst) {
variantCopyFrom(getData(dst), getData(src), getPool(dst));
}
static JsonObject fromJson(JsonVariant src) {
auto data = getData(src);
auto pool = getPool(src);
return JsonObject(pool, data != 0 ? data->asObject() : 0);
}
static detail::InvalidConversion<JsonVariantConst, JsonObject> fromJson(
JsonVariantConst);
static bool checkJson(JsonVariantConst) {
return false;
}
static bool checkJson(JsonVariant src) {
auto data = getData(src);
return data && data->isObject();
}
detail::ObjectData* data_;
detail::ResourceManager* resources_;
};
ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -10,7 +10,7 @@
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
// A read-only reference to an object in a JsonDocument.
// https://arduinojson.org/v6/api/jsonobjectconst/
// https://arduinojson.org/v7/api/jsonobjectconst/
class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
friend class JsonObject;
friend class detail::VariantAttorney;
@@ -19,138 +19,125 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
typedef JsonObjectConstIterator iterator;
// Creates an unbound reference.
JsonObjectConst() : _data(0) {}
JsonObjectConst() : data_(0) {}
// INTERNAL USE ONLY
JsonObjectConst(const detail::CollectionData* data) : _data(data) {}
JsonObjectConst(const detail::ObjectData* data,
const detail::ResourceManager* resources)
: data_(data), resources_(resources) {}
operator JsonVariantConst() const {
return JsonVariantConst(collectionToVariant(_data));
return JsonVariantConst(getData(), resources_);
}
// Returns true if the reference is unbound.
// https://arduinojson.org/v6/api/jsonobjectconst/isnull/
FORCE_INLINE bool isNull() const {
return _data == 0;
// https://arduinojson.org/v7/api/jsonobjectconst/isnull/
bool isNull() const {
return data_ == 0;
}
// Returns true if the reference is bound.
// https://arduinojson.org/v6/api/jsonobjectconst/isnull/
FORCE_INLINE operator bool() const {
return _data != 0;
}
// Returns the number of bytes occupied by the object.
// https://arduinojson.org/v6/api/jsonobjectconst/memoryusage/
FORCE_INLINE size_t memoryUsage() const {
return _data ? _data->memoryUsage() : 0;
// https://arduinojson.org/v7/api/jsonobjectconst/isnull/
operator bool() const {
return data_ != 0;
}
// Returns the depth (nesting level) of the object.
// https://arduinojson.org/v6/api/jsonobjectconst/nesting/
FORCE_INLINE size_t nesting() const {
return variantNesting(collectionToVariant(_data));
// https://arduinojson.org/v7/api/jsonobjectconst/nesting/
size_t nesting() const {
return detail::VariantData::nesting(getData(), resources_);
}
// Returns the number of members in the object.
// https://arduinojson.org/v6/api/jsonobjectconst/size/
FORCE_INLINE size_t size() const {
return _data ? _data->size() : 0;
// https://arduinojson.org/v7/api/jsonobjectconst/size/
size_t size() const {
return data_ ? data_->size(resources_) : 0;
}
// Returns an iterator to the first key-value pair of the object.
// https://arduinojson.org/v6/api/jsonobjectconst/begin/
FORCE_INLINE iterator begin() const {
if (!_data)
// https://arduinojson.org/v7/api/jsonobjectconst/begin/
iterator begin() const {
if (!data_)
return iterator();
return iterator(_data->head());
return iterator(data_->createIterator(resources_), resources_);
}
// Returns an iterator following the last key-value pair of the object.
// https://arduinojson.org/v6/api/jsonobjectconst/end/
FORCE_INLINE iterator end() const {
// https://arduinojson.org/v7/api/jsonobjectconst/end/
iterator end() const {
return iterator();
}
// Returns true if the object contains the specified key.
// https://arduinojson.org/v6/api/jsonobjectconst/containskey/
// https://arduinojson.org/v7/api/jsonobjectconst/containskey/
template <typename TString>
FORCE_INLINE bool containsKey(const TString& key) const {
return getMember(detail::adaptString(key)) != 0;
bool containsKey(const TString& key) const {
return detail::ObjectData::getMember(data_, detail::adaptString(key),
resources_) != 0;
}
// Returns true if the object contains the specified key.
// https://arduinojson.org/v6/api/jsonobjectconst/containskey/
// https://arduinojson.org/v7/api/jsonobjectconst/containskey/
template <typename TChar>
FORCE_INLINE bool containsKey(TChar* key) const {
return getMember(detail::adaptString(key)) != 0;
bool containsKey(TChar* key) const {
return detail::ObjectData::getMember(data_, detail::adaptString(key),
resources_) != 0;
}
// Gets the member with specified key.
// https://arduinojson.org/v6/api/jsonobjectconst/subscript/
// https://arduinojson.org/v7/api/jsonobjectconst/subscript/
template <typename TString>
FORCE_INLINE typename detail::enable_if<detail::IsString<TString>::value,
JsonVariantConst>::type
typename detail::enable_if<detail::IsString<TString>::value,
JsonVariantConst>::type
operator[](const TString& key) const {
return JsonVariantConst(getMember(detail::adaptString(key)));
return JsonVariantConst(detail::ObjectData::getMember(
data_, detail::adaptString(key), resources_),
resources_);
}
// Gets the member with specified key.
// https://arduinojson.org/v6/api/jsonobjectconst/subscript/
// https://arduinojson.org/v7/api/jsonobjectconst/subscript/
template <typename TChar>
FORCE_INLINE typename detail::enable_if<detail::IsString<TChar*>::value,
JsonVariantConst>::type
typename detail::enable_if<detail::IsString<TChar*>::value,
JsonVariantConst>::type
operator[](TChar* key) const {
return JsonVariantConst(getMember(detail::adaptString(key)));
return JsonVariantConst(detail::ObjectData::getMember(
data_, detail::adaptString(key), resources_),
resources_);
}
// Compares objects.
FORCE_INLINE bool operator==(JsonObjectConst rhs) const {
if (_data == rhs._data)
return true;
if (!_data || !rhs._data)
return false;
size_t count = 0;
for (iterator it = begin(); it != end(); ++it) {
if (it->value() != rhs[it->key()])
return false;
count++;
}
return count == rhs.size();
// DEPRECATED: always returns zero
ARDUINOJSON_DEPRECATED("always returns zero")
size_t memoryUsage() const {
return 0;
}
private:
const detail::VariantData* getData() const {
return collectionToVariant(_data);
return collectionToVariant(data_);
}
template <typename TAdaptedString>
const detail::VariantData* getMember(TAdaptedString key) const {
if (!_data)
return 0;
return _data->getMember(key);
}
const detail::CollectionData* _data;
const detail::ObjectData* data_;
const detail::ResourceManager* resources_;
};
template <>
struct Converter<JsonObjectConst> : private detail::VariantAttorney {
static void toJson(JsonVariantConst src, JsonVariant dst) {
variantCopyFrom(getData(dst), getData(src), getPool(dst));
}
inline bool operator==(JsonObjectConst lhs, JsonObjectConst rhs) {
if (!lhs && !rhs) // both are null
return true;
static JsonObjectConst fromJson(JsonVariantConst src) {
auto data = getData(src);
return data != 0 ? data->asObject() : 0;
}
if (!lhs || !rhs) // only one is null
return false;
static bool checkJson(JsonVariantConst src) {
auto data = getData(src);
return data && data->isObject();
size_t count = 0;
for (auto kvp : lhs) {
auto rhsValue = rhs[kvp.key()];
if (rhsValue.isUnbound())
return false;
if (kvp.value() != rhsValue)
return false;
count++;
}
};
return count == rhs.size();
}
ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@@ -1,85 +0,0 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Array/JsonArray.hpp>
#include <ArduinoJson/Object/JsonObject.hpp>
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
template <typename TString>
inline JsonArray JsonObject::createNestedArray(const TString& key) const {
return operator[](key).template to<JsonArray>();
}
template <typename TChar>
inline JsonArray JsonObject::createNestedArray(TChar* key) const {
return operator[](key).template to<JsonArray>();
}
ARDUINOJSON_END_PUBLIC_NAMESPACE
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename TDerived>
template <typename TString>
inline JsonArray VariantRefBase<TDerived>::createNestedArray(
const TString& key) const {
return operator[](key).template to<JsonArray>();
}
template <typename TDerived>
template <typename TChar>
inline JsonArray VariantRefBase<TDerived>::createNestedArray(TChar* key) const {
return operator[](key).template to<JsonArray>();
}
template <typename TDerived>
template <typename TString>
inline JsonObject VariantRefBase<TDerived>::createNestedObject(
const TString& key) const {
return operator[](key).template to<JsonObject>();
}
template <typename TDerived>
template <typename TChar>
inline JsonObject VariantRefBase<TDerived>::createNestedObject(
TChar* key) const {
return operator[](key).template to<JsonObject>();
}
template <typename TDerived>
template <typename TString>
inline typename enable_if<IsString<TString>::value, bool>::type
VariantRefBase<TDerived>::containsKey(const TString& key) const {
return variantGetMember(VariantAttorney::getData(derived()),
adaptString(key)) != 0;
}
template <typename TDerived>
template <typename TChar>
inline typename enable_if<IsString<TChar*>::value, bool>::type
VariantRefBase<TDerived>::containsKey(TChar* key) const {
return variantGetMember(VariantAttorney::getData(derived()),
adaptString(key)) != 0;
}
template <typename TDerived>
template <typename TString>
inline typename enable_if<IsString<TString*>::value,
MemberProxy<TDerived, TString*>>::type
VariantRefBase<TDerived>::operator[](TString* key) const {
return MemberProxy<TDerived, TString*>(derived(), key);
}
template <typename TDerived>
template <typename TString>
inline typename enable_if<IsString<TString>::value,
MemberProxy<TDerived, TString>>::type
VariantRefBase<TDerived>::operator[](const TString& key) const {
return MemberProxy<TDerived, TString>(derived(), key);
}
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -1,123 +1,81 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Object/JsonPair.hpp>
#include <ArduinoJson/Variant/SlotFunctions.hpp>
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
class JsonPairPtr {
public:
JsonPairPtr(detail::MemoryPool* pool, detail::VariantSlot* slot)
: _pair(pool, slot) {}
const JsonPair* operator->() const {
return &_pair;
}
const JsonPair& operator*() const {
return _pair;
}
private:
JsonPair _pair;
};
class JsonObjectIterator {
friend class JsonObject;
public:
JsonObjectIterator() : _slot(0) {}
JsonObjectIterator() {}
explicit JsonObjectIterator(detail::MemoryPool* pool,
detail::VariantSlot* slot)
: _pool(pool), _slot(slot) {}
explicit JsonObjectIterator(detail::ObjectData::iterator iterator,
detail::ResourceManager* resources)
: iterator_(iterator), resources_(resources) {}
JsonPair operator*() const {
return JsonPair(_pool, _slot);
return JsonPair(iterator_, resources_);
}
JsonPairPtr operator->() {
return JsonPairPtr(_pool, _slot);
Ptr<JsonPair> operator->() {
return operator*();
}
bool operator==(const JsonObjectIterator& other) const {
return _slot == other._slot;
return iterator_ == other.iterator_;
}
bool operator!=(const JsonObjectIterator& other) const {
return _slot != other._slot;
return iterator_ != other.iterator_;
}
JsonObjectIterator& operator++() {
_slot = _slot->next();
return *this;
}
JsonObjectIterator& operator+=(size_t distance) {
_slot = _slot->next(distance);
iterator_.next(resources_);
return *this;
}
private:
detail::MemoryPool* _pool;
detail::VariantSlot* _slot;
};
class JsonPairConstPtr {
public:
JsonPairConstPtr(const detail::VariantSlot* slot) : _pair(slot) {}
const JsonPairConst* operator->() const {
return &_pair;
}
const JsonPairConst& operator*() const {
return _pair;
}
private:
JsonPairConst _pair;
detail::ObjectData::iterator iterator_;
detail::ResourceManager* resources_;
};
class JsonObjectConstIterator {
friend class JsonObject;
public:
JsonObjectConstIterator() : _slot(0) {}
JsonObjectConstIterator() {}
explicit JsonObjectConstIterator(const detail::VariantSlot* slot)
: _slot(slot) {}
explicit JsonObjectConstIterator(detail::ObjectData::iterator iterator,
const detail::ResourceManager* resources)
: iterator_(iterator), resources_(resources) {}
JsonPairConst operator*() const {
return JsonPairConst(_slot);
return JsonPairConst(iterator_, resources_);
}
JsonPairConstPtr operator->() {
return JsonPairConstPtr(_slot);
Ptr<JsonPairConst> operator->() {
return operator*();
}
bool operator==(const JsonObjectConstIterator& other) const {
return _slot == other._slot;
return iterator_ == other.iterator_;
}
bool operator!=(const JsonObjectConstIterator& other) const {
return _slot != other._slot;
return iterator_ != other.iterator_;
}
JsonObjectConstIterator& operator++() {
_slot = _slot->next();
return *this;
}
JsonObjectConstIterator& operator+=(size_t distance) {
_slot = _slot->next(distance);
iterator_.next(resources_);
return *this;
}
private:
const detail::VariantSlot* _slot;
detail::ObjectData::iterator iterator_;
const detail::ResourceManager* resources_;
};
ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -11,58 +11,60 @@
ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE
// A key-value pair.
// https://arduinojson.org/v6/api/jsonobject/begin_end/
// https://arduinojson.org/v7/api/jsonobject/begin_end/
class JsonPair {
public:
// INTERNAL USE ONLY
JsonPair(detail::MemoryPool* pool, detail::VariantSlot* slot) {
if (slot) {
_key = JsonString(slot->key(), slot->ownsKey() ? JsonString::Copied
: JsonString::Linked);
_value = JsonVariant(pool, slot->data());
}
}
JsonPair(detail::ObjectData::iterator iterator,
detail::ResourceManager* resources)
: iterator_(iterator), resources_(resources) {}
// Returns the key.
JsonString key() const {
return _key;
if (!iterator_.done())
return JsonString(iterator_.key(), iterator_.ownsKey()
? JsonString::Copied
: JsonString::Linked);
else
return JsonString();
}
// Returns the value.
JsonVariant value() const {
return _value;
JsonVariant value() {
return JsonVariant(iterator_.data(), resources_);
}
private:
JsonString _key;
JsonVariant _value;
detail::ObjectData::iterator iterator_;
detail::ResourceManager* resources_;
};
// A read-only key-value pair.
// https://arduinojson.org/v6/api/jsonobjectconst/begin_end/
// https://arduinojson.org/v7/api/jsonobjectconst/begin_end/
class JsonPairConst {
public:
JsonPairConst(const detail::VariantSlot* slot) {
if (slot) {
_key = JsonString(slot->key(), slot->ownsKey() ? JsonString::Copied
: JsonString::Linked);
_value = JsonVariantConst(slot->data());
}
}
JsonPairConst(detail::ObjectData::iterator iterator,
const detail::ResourceManager* resources)
: iterator_(iterator), resources_(resources) {}
// Returns the key.
JsonString key() const {
return _key;
if (!iterator_.done())
return JsonString(iterator_.key(), iterator_.ownsKey()
? JsonString::Copied
: JsonString::Linked);
else
return JsonString();
}
// Returns the value.
JsonVariantConst value() const {
return _value;
return JsonVariantConst(iterator_.data(), resources_);
}
private:
JsonString _key;
JsonVariantConst _value;
detail::ObjectData::iterator iterator_;
const detail::ResourceManager* resources_;
};
ARDUINOJSON_END_PUBLIC_NAMESPACE

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -9,7 +9,7 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
// A proxy class to get or set a member of an object.
// https://arduinojson.org/v6/api/jsonobject/subscript/
// https://arduinojson.org/v7/api/jsonobject/subscript/
template <typename TUpstream, typename TStringRef>
class MemberProxy
: public VariantRefBase<MemberProxy<TUpstream, TStringRef>>,
@@ -17,48 +17,51 @@ class MemberProxy
friend class VariantAttorney;
public:
FORCE_INLINE MemberProxy(TUpstream upstream, TStringRef key)
: _upstream(upstream), _key(key) {}
MemberProxy(TUpstream upstream, TStringRef key)
: upstream_(upstream), key_(key) {}
MemberProxy(const MemberProxy& src)
: _upstream(src._upstream), _key(src._key) {}
: upstream_(src.upstream_), key_(src.key_) {}
FORCE_INLINE MemberProxy& operator=(const MemberProxy& src) {
MemberProxy& operator=(const MemberProxy& src) {
this->set(src);
return *this;
}
template <typename T>
FORCE_INLINE MemberProxy& operator=(const T& src) {
MemberProxy& operator=(const T& src) {
this->set(src);
return *this;
}
template <typename T>
FORCE_INLINE MemberProxy& operator=(T* src) {
MemberProxy& operator=(T* src) {
this->set(src);
return *this;
}
private:
FORCE_INLINE MemoryPool* getPool() const {
return VariantAttorney::getPool(_upstream);
ResourceManager* getResourceManager() const {
return VariantAttorney::getResourceManager(upstream_);
}
FORCE_INLINE VariantData* getData() const {
return variantGetMember(VariantAttorney::getData(_upstream),
adaptString(_key));
VariantData* getData() const {
return VariantData::getMember(
VariantAttorney::getData(upstream_), adaptString(key_),
VariantAttorney::getResourceManager(upstream_));
}
FORCE_INLINE VariantData* getOrCreateData() const {
return variantGetOrAddMember(VariantAttorney::getOrCreateData(_upstream),
adaptString(_key),
VariantAttorney::getPool(_upstream));
VariantData* getOrCreateData() const {
auto data = VariantAttorney::getOrCreateData(upstream_);
if (!data)
return nullptr;
return data->getOrAddMember(adaptString(key_),
VariantAttorney::getResourceManager(upstream_));
}
private:
TUpstream _upstream;
TStringRef _key;
TUpstream upstream_;
TStringRef key_;
};
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -0,0 +1,73 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Collection/CollectionData.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
class ObjectData : public CollectionData {
public:
VariantData* addMember(StringNode* key, ResourceManager* resources) {
ARDUINOJSON_ASSERT(key != nullptr);
auto it = addSlot(resources);
if (it.done())
return nullptr;
it.setKey(key);
return it.data();
}
template <typename TAdaptedString>
VariantData* addMember(TAdaptedString key, ResourceManager* resources) {
ARDUINOJSON_ASSERT(!key.isNull());
if (key.isLinked()) {
auto it = addSlot(resources);
if (!it.done())
it.setKey(key.data());
return it.data();
} else {
auto storedKey = resources->saveString(key);
if (!storedKey)
return nullptr;
auto it = addSlot(resources);
if (!it.done())
it.setKey(storedKey);
return it.data();
}
}
template <typename TAdaptedString>
VariantData* getOrAddMember(TAdaptedString key, ResourceManager* resources);
template <typename TAdaptedString>
VariantData* getMember(TAdaptedString key,
const ResourceManager* resources) const;
template <typename TAdaptedString>
static VariantData* getMember(const ObjectData* object, TAdaptedString key,
const ResourceManager* resources) {
if (!object)
return nullptr;
return object->getMember(key, resources);
}
template <typename TAdaptedString>
void removeMember(TAdaptedString key, ResourceManager* resources);
template <typename TAdaptedString>
static void removeMember(ObjectData* obj, TAdaptedString key,
ResourceManager* resources) {
if (!obj)
return;
obj->removeMember(key, resources);
}
private:
template <typename TAdaptedString>
iterator findKey(TAdaptedString key, const ResourceManager* resources) const;
};
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -0,0 +1,45 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Object/ObjectData.hpp>
#include <ArduinoJson/Variant/VariantCompare.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename TAdaptedString>
inline VariantData* ObjectData::getMember(
TAdaptedString key, const ResourceManager* resources) const {
return findKey(key, resources).data();
}
template <typename TAdaptedString>
VariantData* ObjectData::getOrAddMember(TAdaptedString key,
ResourceManager* resources) {
auto it = findKey(key, resources);
if (!it.done())
return it.data();
return addMember(key, resources);
}
template <typename TAdaptedString>
inline ObjectData::iterator ObjectData::findKey(
TAdaptedString key, const ResourceManager* resources) const {
if (key.isNull())
return iterator();
for (auto it = createIterator(resources); !it.done(); it.next(resources)) {
if (stringEquals(key, adaptString(it.key())))
return it;
}
return iterator();
}
template <typename TAdaptedString>
inline void ObjectData::removeMember(TAdaptedString key,
ResourceManager* resources) {
remove(findKey(key, resources), resources);
}
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -7,17 +7,30 @@
#ifdef _MSC_VER // Visual Studio
# define FORCE_INLINE // __forceinline causes C4714 when returning std::string
# define NO_INLINE __declspec(noinline)
# ifndef ARDUINOJSON_DEPRECATED
# define ARDUINOJSON_DEPRECATED(msg) __declspec(deprecated(msg))
# endif
#elif defined(__GNUC__) // GCC or Clang
# define FORCE_INLINE __attribute__((always_inline))
# define NO_INLINE __attribute__((noinline))
# ifndef ARDUINOJSON_DEPRECATED
# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
# define ARDUINOJSON_DEPRECATED(msg) __attribute__((deprecated(msg)))
# else
# define ARDUINOJSON_DEPRECATED(msg) __attribute__((deprecated))
# endif
# endif
#else // Other compilers
# define FORCE_INLINE
# define NO_INLINE
# ifndef ARDUINOJSON_DEPRECATED
# define ARDUINOJSON_DEPRECATED(msg)
# endif
#endif

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -11,21 +11,21 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <int Bits>
struct int_t;
struct uint_t;
template <>
struct int_t<8> {
typedef int8_t type;
struct uint_t<8> {
typedef uint8_t type;
};
template <>
struct int_t<16> {
typedef int16_t type;
struct uint_t<16> {
typedef uint16_t type;
};
template <>
struct int_t<32> {
typedef int32_t type;
struct uint_t<32> {
typedef uint32_t type;
};
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -19,10 +19,10 @@ struct numeric_limits;
template <typename T>
struct numeric_limits<T, typename enable_if<is_unsigned<T>::value>::type> {
static T lowest() {
static constexpr T lowest() {
return 0;
}
static T highest() {
static constexpr T highest() {
return T(-1);
}
};
@@ -30,10 +30,10 @@ struct numeric_limits<T, typename enable_if<is_unsigned<T>::value>::type> {
template <typename T>
struct numeric_limits<
T, typename enable_if<is_integral<T>::value && is_signed<T>::value>::type> {
static T lowest() {
static constexpr T lowest() {
return T(T(1) << (sizeof(T) * 8 - 1));
}
static T highest() {
static constexpr T highest() {
return T(~lowest());
}
};

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,10 +1,16 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#include <Arduino.h>
#ifdef ARDUINO
# include <Arduino.h>
#else
// Allow using PROGMEM outside of Arduino (issue #1903)
class __FlashStringHelper;
# include <avr/pgmspace.h>
#endif
#include <ArduinoJson/Configuration.hpp>
#include <ArduinoJson/Namespace.hpp>

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -54,14 +54,14 @@ inline T pgm_read(const T* p) {
template <typename T>
class pgm_ptr {
public:
explicit pgm_ptr(const T* ptr) : _ptr(ptr) {}
explicit pgm_ptr(const T* ptr) : ptr_(ptr) {}
T operator[](intptr_t index) const {
return pgm_read(_ptr + index);
return pgm_read(ptr_ + index);
}
private:
const T* _ptr;
const T* ptr_;
};
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -1,13 +1,11 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
#define ARDUINOJSON_CONCAT_(A, B) A##B
#define ARDUINOJSON_CONCAT2(A, B) ARDUINOJSON_CONCAT_(A, B)
#define ARDUINOJSON_CONCAT3(A, B, C) \
ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT2(A, B), C)
#define ARDUINOJSON_CONCAT4(A, B, C, D) \
ARDUINOJSON_CONCAT2(ARDUINOJSON_CONCAT2(A, B), ARDUINOJSON_CONCAT2(C, D))
@@ -17,7 +15,7 @@
#define ARDUINOJSON_BIN2ALPHA_0011() D
#define ARDUINOJSON_BIN2ALPHA_0100() E
#define ARDUINOJSON_BIN2ALPHA_0101() F
#define ARDUINOJSON_BIN2ALPHA_0110() F
#define ARDUINOJSON_BIN2ALPHA_0110() G
#define ARDUINOJSON_BIN2ALPHA_0111() H
#define ARDUINOJSON_BIN2ALPHA_1000() I
#define ARDUINOJSON_BIN2ALPHA_1001() J

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -9,6 +9,6 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename T>
T declval();
T&& declval();
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once
@@ -27,10 +27,10 @@ struct is_convertible {
static int probe(To);
static char probe(...);
static From& _from;
static From& from_;
public:
static const bool value = sizeof(probe(_from)) == sizeof(int);
static const bool value = sizeof(probe(from_)) == sizeof(int);
};
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

View File

@@ -1,5 +1,5 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// Copyright © 2014-2024, Benoit BLANCHON
// MIT License
#pragma once

Some files were not shown because too many files have changed in this diff Show More