Compare commits

...

5 Commits

Author SHA1 Message Date
cc73fec1cf JsonObject: replace ObjectData* member with VariantData* 2025-06-15 12:55:13 +02:00
535a9b3e86 JsonArray: replace ArrayData* member with VariantData* 2025-06-15 12:35:31 +02:00
72075e9ad2 JsonObjectConst: replace ObjectData* member with VariantData* 2025-06-15 12:34:38 +02:00
56b269bea8 JsonArrayConst: replace ArrayData* member with VariantData* 2025-06-15 12:32:37 +02:00
817998d0fe Add a pool dedicated to 8-byte values (double/int64_t/uint64_t)
This new pool replaced the "extension" slot where a secondary variant slot was used to store 8-byte values.
2025-06-02 19:39:27 +02:00
23 changed files with 221 additions and 189 deletions

View File

@ -12,7 +12,7 @@ static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN");
static_assert(ARDUINOJSON_USE_DOUBLE == 0, "ARDUINOJSON_USE_DOUBLE"); static_assert(ARDUINOJSON_USE_DOUBLE == 0, "ARDUINOJSON_USE_DOUBLE");
static_assert(ArduinoJson::detail::ResourceManager::slotSize == 6, "slot size"); static_assert(sizeof(ArduinoJson::detail::VariantData) == 6, "slot size");
void setup() {} void setup() {}
void loop() {} void loop() {}

View File

@ -10,7 +10,7 @@ static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN");
static_assert(ARDUINOJSON_USE_DOUBLE == 1, "ARDUINOJSON_USE_DOUBLE"); static_assert(ARDUINOJSON_USE_DOUBLE == 1, "ARDUINOJSON_USE_DOUBLE");
static_assert(ArduinoJson::detail::ResourceManager::slotSize == 8, "slot size"); static_assert(sizeof(ArduinoJson::detail::VariantData) == 8, "slot size");
void setup() {} void setup() {}
void loop() {} void loop() {}

View File

@ -10,7 +10,6 @@ static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN");
static_assert(ARDUINOJSON_USE_DOUBLE == 1, "ARDUINOJSON_USE_DOUBLE"); static_assert(ARDUINOJSON_USE_DOUBLE == 1, "ARDUINOJSON_USE_DOUBLE");
static_assert(ArduinoJson::detail::ResourceManager::slotSize == 16, static_assert(sizeof(ArduinoJson::detail::VariantData) == 16, "slot size");
"slot size");
int main() {} int main() {}

View File

@ -10,6 +10,6 @@ static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN");
static_assert(ARDUINOJSON_USE_DOUBLE == 1, "ARDUINOJSON_USE_DOUBLE"); static_assert(ARDUINOJSON_USE_DOUBLE == 1, "ARDUINOJSON_USE_DOUBLE");
static_assert(ArduinoJson::detail::ResourceManager::slotSize == 8, "slot size"); static_assert(sizeof(ArduinoJson::detail::VariantData) == 8, "slot size");
int main() {} int main() {}

View File

@ -269,10 +269,10 @@ inline size_t sizeofPoolList(size_t n = ARDUINOJSON_INITIAL_POOL_COUNT) {
return sizeof(MemoryPool<VariantData>) * n; return sizeof(MemoryPool<VariantData>) * n;
} }
template <typename T = ArduinoJson::detail::VariantData>
inline size_t sizeofPool( inline size_t sizeofPool(
ArduinoJson::detail::SlotCount n = ARDUINOJSON_POOL_CAPACITY) { ArduinoJson::detail::SlotCount n = ARDUINOJSON_POOL_CAPACITY) {
using namespace ArduinoJson::detail; return ArduinoJson::detail::MemoryPool<T>::slotsToBytes(n);
return MemoryPool<VariantData>::slotsToBytes(n);
} }
inline size_t sizeofStaticStringPool( inline size_t sizeofStaticStringPool(

View File

@ -8,7 +8,7 @@
#include "Allocators.hpp" #include "Allocators.hpp"
#include "Literals.hpp" #include "Literals.hpp"
using ArduinoJson::detail::sizeofArray; using namespace ArduinoJson::detail;
TEST_CASE("JsonArray::add(T)") { TEST_CASE("JsonArray::add(T)") {
SpyingAllocator spy; SpyingAllocator spy;
@ -33,7 +33,8 @@ TEST_CASE("JsonArray::add(T)") {
REQUIRE(array[0].is<double>()); REQUIRE(array[0].is<double>());
REQUIRE_FALSE(array[0].is<bool>()); REQUIRE_FALSE(array[0].is<bool>());
REQUIRE(spy.log() == AllocatorLog{ REQUIRE(spy.log() == AllocatorLog{
Allocate(sizeofPool()), Allocate(sizeofPool<VariantData>()),
Allocate(sizeofPool<EightByteValue>()),
}); });
} }

View File

@ -7,7 +7,7 @@
#include "Allocators.hpp" #include "Allocators.hpp"
using ArduinoJson::detail::sizeofArray; using namespace ArduinoJson::detail;
TEST_CASE("deserialize JSON array") { TEST_CASE("deserialize JSON array") {
SpyingAllocator spy; SpyingAllocator spy;
@ -92,8 +92,12 @@ TEST_CASE("deserialize JSON array") {
REQUIRE(arr[0].as<double>() == Approx(4.2123456)); REQUIRE(arr[0].as<double>() == Approx(4.2123456));
REQUIRE(arr[1] == -7E89); REQUIRE(arr[1] == -7E89);
REQUIRE(spy.log() == AllocatorLog{ REQUIRE(spy.log() == AllocatorLog{
Allocate(sizeofPool()), Allocate(sizeofPool<VariantData>()),
Reallocate(sizeofPool(), sizeofPool(4)), Allocate(sizeofPool<EightByteValue>()),
Reallocate(sizeofPool<VariantData>(),
sizeofPool<VariantData>(2)),
Reallocate(sizeofPool<EightByteValue>(),
sizeofPool<EightByteValue>(2)),
}); });
} }

View File

@ -121,7 +121,7 @@ TEST_CASE("deserializeJson() returns NoMemory if string length overflows") {
} }
} }
TEST_CASE("deserializeJson() returns NoMemory if extension allocation fails") { TEST_CASE("deserializeJson() returns NoMemory if 8-bit slot allocation fails") {
JsonDocument doc(FailingAllocator::instance()); JsonDocument doc(FailingAllocator::instance());
SECTION("uint32_t should pass") { SECTION("uint32_t should pass") {

View File

@ -8,7 +8,7 @@
#include "Allocators.hpp" #include "Allocators.hpp"
#include "Literals.hpp" #include "Literals.hpp"
using ArduinoJson::detail::sizeofObject; using namespace ArduinoJson::detail;
enum ErrorCode { ERROR_01 = 1, ERROR_10 = 10 }; enum ErrorCode { ERROR_01 = 1, ERROR_10 = 10 };
@ -197,11 +197,11 @@ TEST_CASE("JsonVariant::set() when there is enough memory") {
REQUIRE(result == true); REQUIRE(result == true);
REQUIRE(variant.is<double>() == true); REQUIRE(variant.is<double>() == true);
REQUIRE(variant.as<double>() == 1.2); REQUIRE(variant.as<double>() == 1.2);
REQUIRE(spy.log() == REQUIRE(spy.log() == AllocatorLog{
AllocatorLog{ Allocate(sizeofPool<EightByteValue>()),
Allocate(sizeofPool()), Reallocate(sizeofPool<EightByteValue>(),
Reallocate(sizeofPool(), sizeofPool(1)), // one extension slot sizeofPool<EightByteValue>(1)),
}); });
} }
SECTION("int32_t") { SECTION("int32_t") {
@ -220,11 +220,11 @@ TEST_CASE("JsonVariant::set() when there is enough memory") {
REQUIRE(result == true); REQUIRE(result == true);
REQUIRE(variant.is<int64_t>() == true); REQUIRE(variant.is<int64_t>() == true);
REQUIRE(variant.as<int64_t>() == -2147483649LL); REQUIRE(variant.as<int64_t>() == -2147483649LL);
REQUIRE(spy.log() == REQUIRE(spy.log() == AllocatorLog{
AllocatorLog{ Allocate(sizeofPool<EightByteValue>()),
Allocate(sizeofPool()), Reallocate(sizeofPool<EightByteValue>(),
Reallocate(sizeofPool(), sizeofPool(1)), // one extension slot sizeofPool<EightByteValue>(1)),
}); });
} }
SECTION("uint32_t") { SECTION("uint32_t") {
@ -243,11 +243,11 @@ TEST_CASE("JsonVariant::set() when there is enough memory") {
REQUIRE(result == true); REQUIRE(result == true);
REQUIRE(variant.is<uint64_t>() == true); REQUIRE(variant.is<uint64_t>() == true);
REQUIRE(variant.as<uint64_t>() == 4294967296); REQUIRE(variant.as<uint64_t>() == 4294967296);
REQUIRE(spy.log() == REQUIRE(spy.log() == AllocatorLog{
AllocatorLog{ Allocate(sizeofPool<EightByteValue>()),
Allocate(sizeofPool()), Reallocate(sizeofPool<EightByteValue>(),
Reallocate(sizeofPool(), sizeofPool(1)), // one extension slot sizeofPool<EightByteValue>(1)),
}); });
} }
SECTION("JsonDocument") { SECTION("JsonDocument") {
@ -378,7 +378,7 @@ TEST_CASE("JsonVariant::set() releases the previous value") {
} }
SECTION("float") { SECTION("float") {
v.set(1.2); v.set(1.2f);
REQUIRE(spy.log() == AllocatorLog{ REQUIRE(spy.log() == AllocatorLog{
Deallocate(sizeofString("world")), Deallocate(sizeofString("world")),
}); });
@ -393,7 +393,7 @@ TEST_CASE("JsonVariant::set() releases the previous value") {
} }
} }
TEST_CASE("JsonVariant::set() reuses extension slot") { TEST_CASE("JsonVariant::set() reuses 8-bit slot") {
SpyingAllocator spy; SpyingAllocator spy;
JsonDocument doc(&spy); JsonDocument doc(&spy);
JsonVariant variant = doc.to<JsonVariant>(); JsonVariant variant = doc.to<JsonVariant>();

View File

@ -73,7 +73,7 @@ inline bool ArrayData::addValue(const T& value, ResourceManager* resources) {
// Returns the size (in bytes) of an array with n elements. // Returns the size (in bytes) of an array with n elements.
constexpr size_t sizeofArray(size_t n) { constexpr size_t sizeofArray(size_t n) {
return n * ResourceManager::slotSize; return n * sizeof(VariantData);
} }
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@ -23,7 +23,7 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
JsonArray() : data_(0), resources_(0) {} JsonArray() : data_(0), resources_(0) {}
// INTERNAL USE ONLY // INTERNAL USE ONLY
JsonArray(detail::ArrayData* data, detail::ResourceManager* resources) JsonArray(detail::VariantData* data, detail::ResourceManager* resources)
: data_(data), resources_(resources) {} : data_(data), resources_(resources) {}
// Returns a JsonVariant pointing to the array. // Returns a JsonVariant pointing to the array.
@ -37,7 +37,7 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
// Returns a read-only reference to the array. // Returns a read-only reference to the array.
// https://arduinojson.org/v7/api/jsonarrayconst/ // https://arduinojson.org/v7/api/jsonarrayconst/
operator JsonArrayConst() const { operator JsonArrayConst() const {
return JsonArrayConst(data_, resources_); return JsonArrayConst(getData(), resources_);
} }
// Appends a new (empty) element to the array. // Appends a new (empty) element to the array.
@ -55,7 +55,7 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
template <typename T, detail::enable_if_t< template <typename T, detail::enable_if_t<
detail::is_same<T, JsonVariant>::value, int> = 0> detail::is_same<T, JsonVariant>::value, int> = 0>
JsonVariant add() const { JsonVariant add() const {
return JsonVariant(detail::ArrayData::addElement(data_, resources_), return JsonVariant(detail::VariantData::addElement(data_, resources_),
resources_); resources_);
} }
@ -63,7 +63,7 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
// https://arduinojson.org/v7/api/jsonarray/add/ // https://arduinojson.org/v7/api/jsonarray/add/
template <typename T> template <typename T>
bool add(const T& value) const { bool add(const T& value) const {
return detail::ArrayData::addValue(data_, value, resources_); return detail::VariantData::addValue(data_, value, resources_);
} }
// Appends a value to the array. // Appends a value to the array.
@ -71,15 +71,16 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
template <typename T, template <typename T,
detail::enable_if_t<!detail::is_const<T>::value, int> = 0> detail::enable_if_t<!detail::is_const<T>::value, int> = 0>
bool add(T* value) const { bool add(T* value) const {
return detail::ArrayData::addValue(data_, value, resources_); return detail::VariantData::addValue(data_, value, resources_);
} }
// Returns an iterator to the first element of the array. // Returns an iterator to the first element of the array.
// https://arduinojson.org/v7/api/jsonarray/begin/ // https://arduinojson.org/v7/api/jsonarray/begin/
iterator begin() const { iterator begin() const {
if (!data_) auto array = detail::VariantData::asArray(data_);
if (!array)
return iterator(); return iterator();
return iterator(data_->createIterator(resources_), resources_); return iterator(array->createIterator(resources_), resources_);
} }
// Returns an iterator following the last element of the array. // Returns an iterator following the last element of the array.
@ -106,13 +107,14 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
// Removes the element at the specified iterator. // Removes the element at the specified iterator.
// https://arduinojson.org/v7/api/jsonarray/remove/ // https://arduinojson.org/v7/api/jsonarray/remove/
void remove(iterator it) const { void remove(iterator it) const {
detail::ArrayData::remove(data_, it.iterator_, resources_); detail::ArrayData::remove(detail::VariantData::asArray(data_), it.iterator_,
resources_);
} }
// Removes the element at the specified index. // Removes the element at the specified index.
// https://arduinojson.org/v7/api/jsonarray/remove/ // https://arduinojson.org/v7/api/jsonarray/remove/
void remove(size_t index) const { void remove(size_t index) const {
detail::ArrayData::removeElement(data_, index, resources_); detail::VariantData::removeElement(data_, index, resources_);
} }
// Removes the element at the specified index. // Removes the element at the specified index.
@ -127,7 +129,7 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
// Removes all the elements of the array. // Removes all the elements of the array.
// https://arduinojson.org/v7/api/jsonarray/clear/ // https://arduinojson.org/v7/api/jsonarray/clear/
void clear() const { void clear() const {
detail::ArrayData::clear(data_, resources_); detail::ArrayData::clear(detail::VariantData::asArray(data_), resources_);
} }
// Gets or sets the element at the specified index. // Gets or sets the element at the specified index.
@ -150,25 +152,25 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
} }
operator JsonVariantConst() const { operator JsonVariantConst() const {
return JsonVariantConst(collectionToVariant(data_), resources_); return JsonVariantConst(data_, resources_);
} }
// Returns true if the reference is unbound. // Returns true if the reference is unbound.
// https://arduinojson.org/v7/api/jsonarray/isnull/ // https://arduinojson.org/v7/api/jsonarray/isnull/
bool isNull() const { bool isNull() const {
return data_ == 0; return !data_ || !data_->isArray();
} }
// Returns true if the reference is bound. // Returns true if the reference is bound.
// https://arduinojson.org/v7/api/jsonarray/isnull/ // https://arduinojson.org/v7/api/jsonarray/isnull/
operator bool() const { operator bool() const {
return data_ != 0; return !isNull();
} }
// Returns the depth (nesting level) of the array. // Returns the depth (nesting level) of the array.
// https://arduinojson.org/v7/api/jsonarray/nesting/ // https://arduinojson.org/v7/api/jsonarray/nesting/
size_t nesting() const { size_t nesting() const {
return detail::VariantData::nesting(collectionToVariant(data_), resources_); return detail::VariantData::nesting(data_, resources_);
} }
// Returns the number of elements in the array. // Returns the number of elements in the array.
@ -205,14 +207,14 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
} }
detail::VariantData* getData() const { detail::VariantData* getData() const {
return collectionToVariant(data_); return data_;
} }
detail::VariantData* getOrCreateData() const { detail::VariantData* getOrCreateData() const {
return collectionToVariant(data_); return data_;
} }
detail::ArrayData* data_; detail::VariantData* data_;
detail::ResourceManager* resources_; detail::ResourceManager* resources_;
}; };

View File

@ -24,9 +24,10 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
// Returns an iterator to the first element of the array. // Returns an iterator to the first element of the array.
// https://arduinojson.org/v7/api/jsonarrayconst/begin/ // https://arduinojson.org/v7/api/jsonarrayconst/begin/
iterator begin() const { iterator begin() const {
if (!data_) auto array = detail::VariantData::asArray(data_);
if (!array)
return iterator(); return iterator();
return iterator(data_->createIterator(resources_), resources_); return iterator(array->createIterator(resources_), resources_);
} }
// Returns an iterator to the element following the last element of the array. // Returns an iterator to the element following the last element of the array.
@ -39,7 +40,7 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
JsonArrayConst() : data_(0), resources_(0) {} JsonArrayConst() : data_(0), resources_(0) {}
// INTERNAL USE ONLY // INTERNAL USE ONLY
JsonArrayConst(const detail::ArrayData* data, JsonArrayConst(const detail::VariantData* data,
const detail::ResourceManager* resources) const detail::ResourceManager* resources)
: data_(data), resources_(resources) {} : data_(data), resources_(resources) {}
@ -49,7 +50,7 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
detail::enable_if_t<detail::is_integral<T>::value, int> = 0> detail::enable_if_t<detail::is_integral<T>::value, int> = 0>
JsonVariantConst operator[](T index) const { JsonVariantConst operator[](T index) const {
return JsonVariantConst( return JsonVariantConst(
detail::ArrayData::getElement(data_, size_t(index), resources_), detail::VariantData::getElement(data_, size_t(index), resources_),
resources_); resources_);
} }
@ -71,13 +72,13 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
// Returns true if the reference is unbound. // Returns true if the reference is unbound.
// https://arduinojson.org/v7/api/jsonarrayconst/isnull/ // https://arduinojson.org/v7/api/jsonarrayconst/isnull/
bool isNull() const { bool isNull() const {
return data_ == 0; return !data_ || !data_->isArray();
} }
// Returns true if the reference is bound. // Returns true if the reference is bound.
// https://arduinojson.org/v7/api/jsonarrayconst/isnull/ // https://arduinojson.org/v7/api/jsonarrayconst/isnull/
operator bool() const { operator bool() const {
return data_ != 0; return !isNull();
} }
// Returns the depth (nesting level) of the array. // Returns the depth (nesting level) of the array.
@ -100,10 +101,10 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
private: private:
const detail::VariantData* getData() const { const detail::VariantData* getData() const {
return collectionToVariant(data_); return data_;
} }
const detail::ArrayData* data_; const detail::VariantData* data_;
const detail::ResourceManager* resources_; const detail::ResourceManager* resources_;
}; };

View File

@ -274,9 +274,9 @@
#endif #endif
#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_DOUBLE #if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_DOUBLE
# define ARDUINOJSON_USE_EXTENSIONS 1 # define ARDUINOJSON_USE_8_BYTE_POOL 1
#else #else
# define ARDUINOJSON_USE_EXTENSIONS 0 # define ARDUINOJSON_USE_8_BYTE_POOL 0
#endif #endif
#if defined(nullptr) #if defined(nullptr)

View File

@ -18,16 +18,7 @@ class VariantData;
class VariantWithId; class VariantWithId;
class ResourceManager { class ResourceManager {
union SlotData {
VariantData variant;
#if ARDUINOJSON_USE_EXTENSIONS
VariantExtension extension;
#endif
};
public: public:
constexpr static size_t slotSize = sizeof(SlotData);
ResourceManager(Allocator* allocator = DefaultAllocator::instance()) ResourceManager(Allocator* allocator = DefaultAllocator::instance())
: allocator_(allocator), overflowed_(false) {} : allocator_(allocator), overflowed_(false) {}
@ -35,6 +26,9 @@ class ResourceManager {
stringPool_.clear(allocator_); stringPool_.clear(allocator_);
variantPools_.clear(allocator_); variantPools_.clear(allocator_);
staticStringsPools_.clear(allocator_); staticStringsPools_.clear(allocator_);
#if ARDUINOJSON_USE_8_BYTE_POOL
eightBytePools_.clear(allocator_);
#endif
} }
ResourceManager(const ResourceManager&) = delete; ResourceManager(const ResourceManager&) = delete;
@ -44,6 +38,9 @@ class ResourceManager {
swap(a.stringPool_, b.stringPool_); swap(a.stringPool_, b.stringPool_);
swap(a.variantPools_, b.variantPools_); swap(a.variantPools_, b.variantPools_);
swap(a.staticStringsPools_, b.staticStringsPools_); swap(a.staticStringsPools_, b.staticStringsPools_);
#if ARDUINOJSON_USE_8_BYTE_POOL
swap(a.eightBytePools_, b.eightBytePools_);
#endif
swap_(a.allocator_, b.allocator_); swap_(a.allocator_, b.allocator_);
swap_(a.overflowed_, b.overflowed_); swap_(a.overflowed_, b.overflowed_);
} }
@ -64,10 +61,10 @@ class ResourceManager {
void freeVariant(Slot<VariantData> slot); void freeVariant(Slot<VariantData> slot);
VariantData* getVariant(SlotId id) const; VariantData* getVariant(SlotId id) const;
#if ARDUINOJSON_USE_EXTENSIONS #if ARDUINOJSON_USE_8_BYTE_POOL
Slot<VariantExtension> allocExtension(); Slot<EightByteValue> allocEightByte();
void freeExtension(SlotId slot); void freeEightByte(SlotId slot);
VariantExtension* getExtension(SlotId id) const; EightByteValue* getEightByte(SlotId id) const;
#endif #endif
template <typename TAdaptedString> template <typename TAdaptedString>
@ -136,19 +133,28 @@ class ResourceManager {
variantPools_.clear(allocator_); variantPools_.clear(allocator_);
stringPool_.clear(allocator_); stringPool_.clear(allocator_);
staticStringsPools_.clear(allocator_); staticStringsPools_.clear(allocator_);
#if ARDUINOJSON_USE_8_BYTE_POOL
eightBytePools_.clear(allocator_);
#endif
} }
void shrinkToFit() { void shrinkToFit() {
variantPools_.shrinkToFit(allocator_); variantPools_.shrinkToFit(allocator_);
staticStringsPools_.shrinkToFit(allocator_); staticStringsPools_.shrinkToFit(allocator_);
#if ARDUINOJSON_USE_8_BYTE_POOL
eightBytePools_.shrinkToFit(allocator_);
#endif
} }
private: private:
Allocator* allocator_; Allocator* allocator_;
bool overflowed_; bool overflowed_;
StringPool stringPool_; StringPool stringPool_;
MemoryPoolList<SlotData> variantPools_; MemoryPoolList<VariantData> variantPools_;
MemoryPoolList<const char*> staticStringsPools_; MemoryPoolList<const char*> staticStringsPools_;
#if ARDUINOJSON_USE_8_BYTE_POOL
MemoryPoolList<EightByteValue> eightBytePools_;
#endif
}; };
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@ -12,40 +12,41 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
inline Slot<VariantData> ResourceManager::allocVariant() { inline Slot<VariantData> ResourceManager::allocVariant() {
auto p = variantPools_.allocSlot(allocator_); auto slot = variantPools_.allocSlot(allocator_);
if (!p) { if (!slot) {
overflowed_ = true; overflowed_ = true;
return {}; return {};
} }
return {new (&p->variant) VariantData, p.id()}; new (slot.ptr()) VariantData();
return slot;
} }
inline void ResourceManager::freeVariant(Slot<VariantData> variant) { inline void ResourceManager::freeVariant(Slot<VariantData> slot) {
variant->clear(this); slot->clear(this);
variantPools_.freeSlot({alias_cast<SlotData*>(variant.ptr()), variant.id()}); variantPools_.freeSlot(slot);
} }
inline VariantData* ResourceManager::getVariant(SlotId id) const { inline VariantData* ResourceManager::getVariant(SlotId id) const {
return reinterpret_cast<VariantData*>(variantPools_.getSlot(id)); return reinterpret_cast<VariantData*>(variantPools_.getSlot(id));
} }
#if ARDUINOJSON_USE_EXTENSIONS #if ARDUINOJSON_USE_8_BYTE_POOL
inline Slot<VariantExtension> ResourceManager::allocExtension() { inline Slot<EightByteValue> ResourceManager::allocEightByte() {
auto p = variantPools_.allocSlot(allocator_); auto slot = eightBytePools_.allocSlot(allocator_);
if (!p) { if (!slot) {
overflowed_ = true; overflowed_ = true;
return {}; return {};
} }
return {&p->extension, p.id()}; return slot;
} }
inline void ResourceManager::freeExtension(SlotId id) { inline void ResourceManager::freeEightByte(SlotId id) {
auto p = getExtension(id); auto p = getEightByte(id);
variantPools_.freeSlot({reinterpret_cast<SlotData*>(p), id}); eightBytePools_.freeSlot({p, id});
} }
inline VariantExtension* ResourceManager::getExtension(SlotId id) const { inline EightByteValue* ResourceManager::getEightByte(SlotId id) const {
return &variantPools_.getSlot(id)->extension; return eightBytePools_.getSlot(id);
} }
#endif #endif

View File

@ -23,7 +23,7 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
JsonObject() : data_(0), resources_(0) {} JsonObject() : data_(0), resources_(0) {}
// INTERNAL USE ONLY // INTERNAL USE ONLY
JsonObject(detail::ObjectData* data, detail::ResourceManager* resource) JsonObject(detail::VariantData* data, detail::ResourceManager* resource)
: data_(data), resources_(resource) {} : data_(data), resources_(resource) {}
operator JsonVariant() const { operator JsonVariant() const {
@ -37,25 +37,25 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
} }
operator JsonVariantConst() const { operator JsonVariantConst() const {
return JsonVariantConst(collectionToVariant(data_), resources_); return JsonVariantConst(data_, resources_);
} }
// Returns true if the reference is unbound. // Returns true if the reference is unbound.
// https://arduinojson.org/v7/api/jsonobject/isnull/ // https://arduinojson.org/v7/api/jsonobject/isnull/
bool isNull() const { bool isNull() const {
return data_ == 0; return !data_ || !data_->isObject();
} }
// Returns true if the reference is bound. // Returns true if the reference is bound.
// https://arduinojson.org/v7/api/jsonobject/isnull/ // https://arduinojson.org/v7/api/jsonobject/isnull/
operator bool() const { operator bool() const {
return data_ != 0; return !isNull();
} }
// Returns the depth (nesting level) of the object. // Returns the depth (nesting level) of the object.
// https://arduinojson.org/v7/api/jsonobject/nesting/ // https://arduinojson.org/v7/api/jsonobject/nesting/
size_t nesting() const { size_t nesting() const {
return detail::VariantData::nesting(collectionToVariant(data_), resources_); return detail::VariantData::nesting(data_, resources_);
} }
// Returns the number of members in the object. // Returns the number of members in the object.
@ -67,9 +67,10 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
// Returns an iterator to the first key-value pair of the object. // Returns an iterator to the first key-value pair of the object.
// https://arduinojson.org/v7/api/jsonobject/begin/ // https://arduinojson.org/v7/api/jsonobject/begin/
iterator begin() const { iterator begin() const {
if (!data_) auto obj = detail::VariantData::asObject(data_);
if (!obj)
return iterator(); return iterator();
return iterator(data_->createIterator(resources_), resources_); return iterator(obj->createIterator(resources_), resources_);
} }
// Returns an iterator following the last key-value pair of the object. // Returns an iterator following the last key-value pair of the object.
@ -81,7 +82,7 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
// Removes all the members of the object. // Removes all the members of the object.
// https://arduinojson.org/v7/api/jsonobject/clear/ // https://arduinojson.org/v7/api/jsonobject/clear/
void clear() const { void clear() const {
detail::ObjectData::clear(data_, resources_); detail::ObjectData::clear(detail::VariantData::asObject(data_), resources_);
} }
// Copies an object. // Copies an object.
@ -131,7 +132,8 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
// Removes the member at the specified iterator. // Removes the member at the specified iterator.
// https://arduinojson.org/v7/api/jsonobject/remove/ // https://arduinojson.org/v7/api/jsonobject/remove/
FORCE_INLINE void remove(iterator it) const { FORCE_INLINE void remove(iterator it) const {
detail::ObjectData::remove(data_, it.iterator_, resources_); detail::ObjectData::remove(detail::VariantData::asObject(data_),
it.iterator_, resources_);
} }
// Removes the member with the specified key. // Removes the member with the specified key.
@ -139,8 +141,8 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
template <typename TString, template <typename TString,
detail::enable_if_t<detail::IsString<TString>::value, int> = 0> detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
void remove(const TString& key) const { void remove(const TString& key) const {
detail::ObjectData::removeMember(data_, detail::adaptString(key), detail::VariantData::removeMember(data_, detail::adaptString(key),
resources_); resources_);
} }
// Removes the member with the specified key. // Removes the member with the specified key.
@ -156,8 +158,8 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
// https://arduinojson.org/v7/api/jsonobject/remove/ // https://arduinojson.org/v7/api/jsonobject/remove/
template <typename TChar> template <typename TChar>
FORCE_INLINE void remove(TChar* key) const { FORCE_INLINE void remove(TChar* key) const {
detail::ObjectData::removeMember(data_, detail::adaptString(key), detail::VariantData::removeMember(data_, detail::adaptString(key),
resources_); resources_);
} }
// DEPRECATED: use obj[key].is<T>() instead // DEPRECATED: use obj[key].is<T>() instead
@ -166,8 +168,8 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
detail::enable_if_t<detail::IsString<TString>::value, int> = 0> detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
ARDUINOJSON_DEPRECATED("use obj[key].is<T>() instead") ARDUINOJSON_DEPRECATED("use obj[key].is<T>() instead")
bool containsKey(const TString& key) const { bool containsKey(const TString& key) const {
return detail::ObjectData::getMember(data_, detail::adaptString(key), return detail::VariantData::getMember(data_, detail::adaptString(key),
resources_) != 0; resources_) != 0;
} }
// DEPRECATED: use obj["key"].is<T>() instead // DEPRECATED: use obj["key"].is<T>() instead
@ -178,8 +180,8 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
int> = 0> int> = 0>
ARDUINOJSON_DEPRECATED("use obj[\"key\"].is<T>() instead") ARDUINOJSON_DEPRECATED("use obj[\"key\"].is<T>() instead")
bool containsKey(TChar* key) const { bool containsKey(TChar* key) const {
return detail::ObjectData::getMember(data_, detail::adaptString(key), return detail::VariantData::getMember(data_, detail::adaptString(key),
resources_) != 0; resources_) != 0;
} }
// DEPRECATED: use obj[key].is<T>() instead // DEPRECATED: use obj[key].is<T>() instead
@ -231,14 +233,14 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
} }
detail::VariantData* getData() const { detail::VariantData* getData() const {
return detail::collectionToVariant(data_); return data_;
} }
detail::VariantData* getOrCreateData() const { detail::VariantData* getOrCreateData() const {
return detail::collectionToVariant(data_); return data_;
} }
detail::ObjectData* data_; detail::VariantData* data_;
detail::ResourceManager* resources_; detail::ResourceManager* resources_;
}; };

View File

@ -22,7 +22,7 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
JsonObjectConst() : data_(0), resources_(0) {} JsonObjectConst() : data_(0), resources_(0) {}
// INTERNAL USE ONLY // INTERNAL USE ONLY
JsonObjectConst(const detail::ObjectData* data, JsonObjectConst(const detail::VariantData* data,
const detail::ResourceManager* resources) const detail::ResourceManager* resources)
: data_(data), resources_(resources) {} : data_(data), resources_(resources) {}
@ -33,13 +33,13 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
// Returns true if the reference is unbound. // Returns true if the reference is unbound.
// https://arduinojson.org/v7/api/jsonobjectconst/isnull/ // https://arduinojson.org/v7/api/jsonobjectconst/isnull/
bool isNull() const { bool isNull() const {
return data_ == 0; return !data_ || !data_->isObject();
} }
// Returns true if the reference is bound. // Returns true if the reference is bound.
// https://arduinojson.org/v7/api/jsonobjectconst/isnull/ // https://arduinojson.org/v7/api/jsonobjectconst/isnull/
operator bool() const { operator bool() const {
return data_ != 0; return !isNull();
} }
// Returns the depth (nesting level) of the object. // Returns the depth (nesting level) of the object.
@ -57,9 +57,10 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
// Returns an iterator to the first key-value pair of the object. // Returns an iterator to the first key-value pair of the object.
// https://arduinojson.org/v7/api/jsonobjectconst/begin/ // https://arduinojson.org/v7/api/jsonobjectconst/begin/
iterator begin() const { iterator begin() const {
if (!data_) auto obj = detail::VariantData::asObject(data_);
if (!obj)
return iterator(); return iterator();
return iterator(data_->createIterator(resources_), resources_); return iterator(obj->createIterator(resources_), resources_);
} }
// Returns an iterator following the last key-value pair of the object. // Returns an iterator following the last key-value pair of the object.
@ -74,8 +75,8 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
detail::enable_if_t<detail::IsString<TString>::value, int> = 0> detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
ARDUINOJSON_DEPRECATED("use obj[key].is<T>() instead") ARDUINOJSON_DEPRECATED("use obj[key].is<T>() instead")
bool containsKey(const TString& key) const { bool containsKey(const TString& key) const {
return detail::ObjectData::getMember(data_, detail::adaptString(key), return detail::VariantData::getMember(data_, detail::adaptString(key),
resources_) != 0; resources_) != 0;
} }
// DEPRECATED: use obj["key"].is<T>() instead // DEPRECATED: use obj["key"].is<T>() instead
@ -83,8 +84,8 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
template <typename TChar> template <typename TChar>
ARDUINOJSON_DEPRECATED("use obj[\"key\"].is<T>() instead") ARDUINOJSON_DEPRECATED("use obj[\"key\"].is<T>() instead")
bool containsKey(TChar* key) const { bool containsKey(TChar* key) const {
return detail::ObjectData::getMember(data_, detail::adaptString(key), return detail::VariantData::getMember(data_, detail::adaptString(key),
resources_) != 0; resources_) != 0;
} }
// DEPRECATED: use obj[key].is<T>() instead // DEPRECATED: use obj[key].is<T>() instead
@ -101,7 +102,7 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
template <typename TString, template <typename TString,
detail::enable_if_t<detail::IsString<TString>::value, int> = 0> detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
JsonVariantConst operator[](const TString& key) const { JsonVariantConst operator[](const TString& key) const {
return JsonVariantConst(detail::ObjectData::getMember( return JsonVariantConst(detail::VariantData::getMember(
data_, detail::adaptString(key), resources_), data_, detail::adaptString(key), resources_),
resources_); resources_);
} }
@ -113,7 +114,7 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
!detail::is_const<TChar>::value, !detail::is_const<TChar>::value,
int> = 0> int> = 0>
JsonVariantConst operator[](TChar* key) const { JsonVariantConst operator[](TChar* key) const {
return JsonVariantConst(detail::ObjectData::getMember( return JsonVariantConst(detail::VariantData::getMember(
data_, detail::adaptString(key), resources_), data_, detail::adaptString(key), resources_),
resources_); resources_);
} }
@ -137,10 +138,10 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
private: private:
const detail::VariantData* getData() const { const detail::VariantData* getData() const {
return collectionToVariant(data_); return data_;
} }
const detail::ObjectData* data_; const detail::VariantData* data_;
const detail::ResourceManager* resources_; const detail::ResourceManager* resources_;
}; };

View File

@ -86,7 +86,7 @@ inline VariantData* ObjectData::addPair(VariantData** value,
// Returns the size (in bytes) of an object with n members. // Returns the size (in bytes) of an object with n members.
constexpr size_t sizeofObject(size_t n) { constexpr size_t sizeofObject(size_t n) {
return 2 * n * ResourceManager::slotSize; return 2 * n * sizeof(VariantData);
} }
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@ -329,9 +329,7 @@ struct Converter<JsonArrayConst> : private detail::VariantAttorney {
} }
static JsonArrayConst fromJson(JsonVariantConst src) { static JsonArrayConst fromJson(JsonVariantConst src) {
auto data = getData(src); return JsonArrayConst(getData(src), getResourceManager(src));
auto array = data ? data->asArray() : nullptr;
return JsonArrayConst(array, getResourceManager(src));
} }
static bool checkJson(JsonVariantConst src) { static bool checkJson(JsonVariantConst src) {
@ -350,9 +348,7 @@ struct Converter<JsonArray> : private detail::VariantAttorney {
} }
static JsonArray fromJson(JsonVariant src) { static JsonArray fromJson(JsonVariant src) {
auto data = getData(src); return JsonArray(getData(src), getResourceManager(src));
auto resources = getResourceManager(src);
return JsonArray(data != 0 ? data->asArray() : 0, resources);
} }
static bool checkJson(JsonVariant src) { static bool checkJson(JsonVariant src) {
@ -371,9 +367,7 @@ struct Converter<JsonObjectConst> : private detail::VariantAttorney {
} }
static JsonObjectConst fromJson(JsonVariantConst src) { static JsonObjectConst fromJson(JsonVariantConst src) {
auto data = getData(src); return JsonObjectConst(getData(src), getResourceManager(src));
auto object = data != 0 ? data->asObject() : nullptr;
return JsonObjectConst(object, getResourceManager(src));
} }
static bool checkJson(JsonVariantConst src) { static bool checkJson(JsonVariantConst src) {
@ -392,9 +386,7 @@ struct Converter<JsonObject> : private detail::VariantAttorney {
} }
static JsonObject fromJson(JsonVariant src) { static JsonObject fromJson(JsonVariant src) {
auto data = getData(src); return JsonObject(getData(src), getResourceManager(src));
auto resources = getResourceManager(src);
return JsonObject(data != 0 ? data->asObject() : 0, resources);
} }
static bool checkJson(JsonVariant src) { static bool checkJson(JsonVariant src) {

View File

@ -30,11 +30,13 @@ class VisitorAdapter {
: visitor_(&visitor), resources_(resources) {} : visitor_(&visitor), resources_(resources) {}
result_type visit(const ArrayData& value) { result_type visit(const ArrayData& value) {
return visitor_->visit(JsonArrayConst(&value, resources_)); return visitor_->visit(
JsonArrayConst(collectionToVariant(&value), resources_));
} }
result_type visit(const ObjectData& value) { result_type visit(const ObjectData& value) {
return visitor_->visit(JsonObjectConst(&value, resources_)); return visitor_->visit(
JsonObjectConst(collectionToVariant(&value), resources_));
} }
template <typename T> template <typename T>

View File

@ -16,8 +16,8 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
enum class VariantTypeBits : uint8_t { enum class VariantTypeBits : uint8_t {
OwnedStringBit = 0x01, // 0000 0001 OwnedStringBit = 0x01, // 0000 0001
NumberBit = 0x08, // 0000 1000 NumberBit = 0x08, // 0000 1000
#if ARDUINOJSON_USE_EXTENSIONS #if ARDUINOJSON_USE_8_BYTE_POOL
ExtensionBit = 0x10, // 0001 0000 EightByteBit = 0x10, // 0001 0000
#endif #endif
CollectionMask = 0x60, CollectionMask = 0x60,
}; };
@ -64,8 +64,8 @@ union VariantContent {
char asTinyString[tinyStringMaxLength + 1]; char asTinyString[tinyStringMaxLength + 1];
}; };
#if ARDUINOJSON_USE_EXTENSIONS #if ARDUINOJSON_USE_8_BYTE_POOL
union VariantExtension { union EightByteValue {
# if ARDUINOJSON_USE_LONG_LONG # if ARDUINOJSON_USE_LONG_LONG
uint64_t asUint64; uint64_t asUint64;
int64_t asInt64; int64_t asInt64;
@ -74,6 +74,9 @@ union VariantExtension {
double asDouble; double asDouble;
# endif # endif
}; };
static_assert(sizeof(EightByteValue) == 8,
"sizeof(EightByteValue) must be 8 bytes");
#endif #endif
ARDUINOJSON_END_PRIVATE_NAMESPACE ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@ -53,8 +53,8 @@ class VariantData {
template <typename TVisitor> template <typename TVisitor>
typename TVisitor::result_type accept( typename TVisitor::result_type accept(
TVisitor& visit, const ResourceManager* resources) const { TVisitor& visit, const ResourceManager* resources) const {
#if ARDUINOJSON_USE_EXTENSIONS #if ARDUINOJSON_USE_8_BYTE_POOL
auto extension = getExtension(resources); auto eightByteValue = getEightByte(resources);
#else #else
(void)resources; // silence warning (void)resources; // silence warning
#endif #endif
@ -64,7 +64,7 @@ class VariantData {
#if ARDUINOJSON_USE_DOUBLE #if ARDUINOJSON_USE_DOUBLE
case VariantType::Double: case VariantType::Double:
return visit.visit(extension->asDouble); return visit.visit(eightByteValue->asDouble);
#endif #endif
case VariantType::Array: case VariantType::Array:
@ -95,10 +95,10 @@ class VariantData {
#if ARDUINOJSON_USE_LONG_LONG #if ARDUINOJSON_USE_LONG_LONG
case VariantType::Int64: case VariantType::Int64:
return visit.visit(extension->asInt64); return visit.visit(eightByteValue->asInt64);
case VariantType::Uint64: case VariantType::Uint64:
return visit.visit(extension->asUint64); return visit.visit(eightByteValue->asUint64);
#endif #endif
case VariantType::Boolean: case VariantType::Boolean:
@ -145,8 +145,8 @@ class VariantData {
} }
bool asBoolean(const ResourceManager* resources) const { bool asBoolean(const ResourceManager* resources) const {
#if ARDUINOJSON_USE_EXTENSIONS #if ARDUINOJSON_USE_8_BYTE_POOL
auto extension = getExtension(resources); auto eightByteValue = getEightByte(resources);
#else #else
(void)resources; // silence warning (void)resources; // silence warning
#endif #endif
@ -160,14 +160,14 @@ class VariantData {
return content_.asFloat != 0; return content_.asFloat != 0;
#if ARDUINOJSON_USE_DOUBLE #if ARDUINOJSON_USE_DOUBLE
case VariantType::Double: case VariantType::Double:
return extension->asDouble != 0; return eightByteValue->asDouble != 0;
#endif #endif
case VariantType::Null: case VariantType::Null:
return false; return false;
#if ARDUINOJSON_USE_LONG_LONG #if ARDUINOJSON_USE_LONG_LONG
case VariantType::Uint64: case VariantType::Uint64:
case VariantType::Int64: case VariantType::Int64:
return extension->asUint64 != 0; return eightByteValue->asUint64 != 0;
#endif #endif
default: default:
return true; return true;
@ -182,6 +182,14 @@ class VariantData {
return const_cast<VariantData*>(this)->asArray(); return const_cast<VariantData*>(this)->asArray();
} }
static ArrayData* asArray(VariantData* var) {
return var ? var->asArray() : 0;
}
static const ArrayData* asArray(const VariantData* var) {
return var ? var->asArray() : 0;
}
CollectionData* asCollection() { CollectionData* asCollection() {
return isCollection() ? &content_.asCollection : 0; return isCollection() ? &content_.asCollection : 0;
} }
@ -193,8 +201,8 @@ class VariantData {
template <typename T> template <typename T>
T asFloat(const ResourceManager* resources) const { T asFloat(const ResourceManager* resources) const {
static_assert(is_floating_point<T>::value, "T must be a floating point"); static_assert(is_floating_point<T>::value, "T must be a floating point");
#if ARDUINOJSON_USE_EXTENSIONS #if ARDUINOJSON_USE_8_BYTE_POOL
auto extension = getExtension(resources); auto eightByteValue = getEightByte(resources);
#else #else
(void)resources; // silence warning (void)resources; // silence warning
#endif #endif
@ -208,9 +216,9 @@ class VariantData {
return static_cast<T>(content_.asInt32); return static_cast<T>(content_.asInt32);
#if ARDUINOJSON_USE_LONG_LONG #if ARDUINOJSON_USE_LONG_LONG
case VariantType::Uint64: case VariantType::Uint64:
return static_cast<T>(extension->asUint64); return static_cast<T>(eightByteValue->asUint64);
case VariantType::Int64: case VariantType::Int64:
return static_cast<T>(extension->asInt64); return static_cast<T>(eightByteValue->asInt64);
#endif #endif
case VariantType::TinyString: case VariantType::TinyString:
str = content_.asTinyString; str = content_.asTinyString;
@ -225,7 +233,7 @@ class VariantData {
return static_cast<T>(content_.asFloat); return static_cast<T>(content_.asFloat);
#if ARDUINOJSON_USE_DOUBLE #if ARDUINOJSON_USE_DOUBLE
case VariantType::Double: case VariantType::Double:
return static_cast<T>(extension->asDouble); return static_cast<T>(eightByteValue->asDouble);
#endif #endif
default: default:
return 0.0; return 0.0;
@ -238,8 +246,8 @@ class VariantData {
template <typename T> template <typename T>
T asIntegral(const ResourceManager* resources) const { T asIntegral(const ResourceManager* resources) const {
static_assert(is_integral<T>::value, "T must be an integral type"); static_assert(is_integral<T>::value, "T must be an integral type");
#if ARDUINOJSON_USE_EXTENSIONS #if ARDUINOJSON_USE_8_BYTE_POOL
auto extension = getExtension(resources); auto eightByteValue = getEightByte(resources);
#else #else
(void)resources; // silence warning (void)resources; // silence warning
#endif #endif
@ -253,9 +261,9 @@ class VariantData {
return convertNumber<T>(content_.asInt32); return convertNumber<T>(content_.asInt32);
#if ARDUINOJSON_USE_LONG_LONG #if ARDUINOJSON_USE_LONG_LONG
case VariantType::Uint64: case VariantType::Uint64:
return convertNumber<T>(extension->asUint64); return convertNumber<T>(eightByteValue->asUint64);
case VariantType::Int64: case VariantType::Int64:
return convertNumber<T>(extension->asInt64); return convertNumber<T>(eightByteValue->asInt64);
#endif #endif
case VariantType::TinyString: case VariantType::TinyString:
str = content_.asTinyString; str = content_.asTinyString;
@ -270,7 +278,7 @@ class VariantData {
return convertNumber<T>(content_.asFloat); return convertNumber<T>(content_.asFloat);
#if ARDUINOJSON_USE_DOUBLE #if ARDUINOJSON_USE_DOUBLE
case VariantType::Double: case VariantType::Double:
return convertNumber<T>(extension->asDouble); return convertNumber<T>(eightByteValue->asDouble);
#endif #endif
default: default:
return 0; return 0;
@ -288,6 +296,14 @@ class VariantData {
return const_cast<VariantData*>(this)->asObject(); return const_cast<VariantData*>(this)->asObject();
} }
static ObjectData* asObject(VariantData* var) {
return var ? var->asObject() : 0;
}
static const ObjectData* asObject(const VariantData* var) {
return var ? var->asObject() : 0;
}
JsonString asRawString() const { JsonString asRawString() const {
switch (type_) { switch (type_) {
case VariantType::RawString: case VariantType::RawString:
@ -314,8 +330,8 @@ class VariantData {
} }
} }
#if ARDUINOJSON_USE_EXTENSIONS #if ARDUINOJSON_USE_8_BYTE_POOL
const VariantExtension* getExtension(const ResourceManager* resources) const; const EightByteValue* getEightByte(const ResourceManager* resources) const;
#endif #endif
VariantData* getElement(size_t index, VariantData* getElement(size_t index,
@ -378,7 +394,7 @@ class VariantData {
template <typename T> template <typename T>
bool isInteger(const ResourceManager* resources) const { bool isInteger(const ResourceManager* resources) const {
#if ARDUINOJSON_USE_LONG_LONG #if ARDUINOJSON_USE_LONG_LONG
auto extension = getExtension(resources); auto eightByteValue = getEightByte(resources);
#else #else
(void)resources; // silence warning (void)resources; // silence warning
#endif #endif
@ -391,10 +407,10 @@ class VariantData {
#if ARDUINOJSON_USE_LONG_LONG #if ARDUINOJSON_USE_LONG_LONG
case VariantType::Uint64: case VariantType::Uint64:
return canConvertNumber<T>(extension->asUint64); return canConvertNumber<T>(eightByteValue->asUint64);
case VariantType::Int64: case VariantType::Int64:
return canConvertNumber<T>(extension->asInt64); return canConvertNumber<T>(eightByteValue->asInt64);
#endif #endif
default: default:
@ -568,11 +584,12 @@ class VariantData {
return content_.asArray; return content_.asArray;
} }
static ArrayData* toArray(VariantData* var, ResourceManager* resources) { static VariantData* toArray(VariantData* var, ResourceManager* resources) {
if (!var) if (!var)
return 0; return 0;
var->clear(resources); var->clear(resources);
return &var->toArray(); var->toArray();
return var;
} }
ObjectData& toObject() { ObjectData& toObject() {
@ -582,11 +599,12 @@ class VariantData {
return content_.asObject; return content_.asObject;
} }
static ObjectData* toObject(VariantData* var, ResourceManager* resources) { static VariantData* toObject(VariantData* var, ResourceManager* resources) {
if (!var) if (!var)
return 0; return 0;
var->clear(resources); var->clear(resources);
return &var->toObject(); var->toObject();
return var;
} }
VariantType type() const { VariantType type() const {

View File

@ -61,9 +61,9 @@ inline void VariantData::clear(ResourceManager* resources) {
if (type_ & VariantTypeBits::OwnedStringBit) if (type_ & VariantTypeBits::OwnedStringBit)
resources->dereferenceString(content_.asOwnedString->data); resources->dereferenceString(content_.asOwnedString->data);
#if ARDUINOJSON_USE_EXTENSIONS #if ARDUINOJSON_USE_8_BYTE_POOL
if (type_ & VariantTypeBits::ExtensionBit) if (type_ & VariantTypeBits::EightByteBit)
resources->freeExtension(content_.asSlotId); resources->freeEightByte(content_.asSlotId);
#endif #endif
auto collection = asCollection(); auto collection = asCollection();
@ -73,12 +73,12 @@ inline void VariantData::clear(ResourceManager* resources) {
type_ = VariantType::Null; type_ = VariantType::Null;
} }
#if ARDUINOJSON_USE_EXTENSIONS #if ARDUINOJSON_USE_8_BYTE_POOL
inline const VariantExtension* VariantData::getExtension( inline const EightByteValue* VariantData::getEightByte(
const ResourceManager* resources) const { const ResourceManager* resources) const {
return type_ & VariantTypeBits::ExtensionBit return type_ & VariantTypeBits::EightByteBit
? resources->getExtension(content_.asSlotId) ? resources->getEightByte(content_.asSlotId)
: nullptr; : 0;
} }
#endif #endif
@ -101,12 +101,12 @@ enable_if_t<sizeof(T) == 8, bool> VariantData::setFloat(
type_ = VariantType::Float; type_ = VariantType::Float;
content_.asFloat = valueAsFloat; content_.asFloat = valueAsFloat;
} else { } else {
auto extension = resources->allocExtension(); auto slot = resources->allocEightByte();
if (!extension) if (!slot)
return false; return false;
type_ = VariantType::Double; type_ = VariantType::Double;
content_.asSlotId = extension.id(); content_.asSlotId = slot.id();
extension->asDouble = value; slot->asDouble = value;
} }
#else #else
type_ = VariantType::Float; type_ = VariantType::Float;
@ -127,12 +127,12 @@ enable_if_t<is_signed<T>::value, bool> VariantData::setInteger(
} }
#if ARDUINOJSON_USE_LONG_LONG #if ARDUINOJSON_USE_LONG_LONG
else { else {
auto extension = resources->allocExtension(); auto slot = resources->allocEightByte();
if (!extension) if (!slot)
return false; return false;
type_ = VariantType::Int64; type_ = VariantType::Int64;
content_.asSlotId = extension.id(); content_.asSlotId = slot.id();
extension->asInt64 = value; slot->asInt64 = value;
} }
#endif #endif
return true; return true;
@ -150,12 +150,12 @@ enable_if_t<is_unsigned<T>::value, bool> VariantData::setInteger(
} }
#if ARDUINOJSON_USE_LONG_LONG #if ARDUINOJSON_USE_LONG_LONG
else { else {
auto extension = resources->allocExtension(); auto slot = resources->allocEightByte();
if (!extension) if (!slot)
return false; return false;
type_ = VariantType::Uint64; type_ = VariantType::Uint64;
content_.asSlotId = extension.id(); content_.asSlotId = slot.id();
extension->asUint64 = value; slot->asUint64 = value;
} }
#endif #endif
return true; return true;