mirror of
https://github.com/bblanchon/ArduinoJson.git
synced 2025-07-29 18:27:37 +02:00
Store 64-bit numbers (double
and long long
) in an additional slot
This change allows slots to be twices maller on 32-bit architectures. See #1650 and #2103
This commit is contained in:
@ -5,6 +5,14 @@ HEAD
|
||||
----
|
||||
|
||||
* Store object members with two slots: one for the key and one for the value
|
||||
* Store 64-bit numbers (`double` and `long long`) in an additional slot
|
||||
* Reduce the slot size (see table below)
|
||||
|
||||
| Architecture | before | after |
|
||||
|--------------|----------|----------|
|
||||
| 8-bit | 8 bytes | 6 bytes |
|
||||
| 32-bit | 16 bytes | 8 bytes |
|
||||
| 64-bit | 24 bytes | 16 bytes |
|
||||
|
||||
v7.1.0 (2024-06-27)
|
||||
------
|
||||
|
@ -8,7 +8,7 @@ static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN");
|
||||
|
||||
static_assert(ARDUINOJSON_USE_DOUBLE == 1, "ARDUINOJSON_USE_DOUBLE");
|
||||
|
||||
static_assert(sizeof(ArduinoJson::detail::VariantData) == 16,
|
||||
static_assert(sizeof(ArduinoJson::detail::VariantData) == 8,
|
||||
"sizeof(VariantData)");
|
||||
|
||||
void setup() {}
|
||||
|
@ -8,7 +8,7 @@ static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN");
|
||||
|
||||
static_assert(ARDUINOJSON_USE_DOUBLE == 1, "ARDUINOJSON_USE_DOUBLE");
|
||||
|
||||
static_assert(sizeof(ArduinoJson::detail::VariantData) == 12,
|
||||
static_assert(sizeof(ArduinoJson::detail::VariantData) == 8,
|
||||
"sizeof(VariantData)");
|
||||
|
||||
int main() {}
|
||||
|
@ -8,7 +8,7 @@ static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN");
|
||||
|
||||
static_assert(ARDUINOJSON_USE_DOUBLE == 1, "ARDUINOJSON_USE_DOUBLE");
|
||||
|
||||
static_assert(sizeof(ArduinoJson::detail::VariantData) == 16,
|
||||
static_assert(sizeof(ArduinoJson::detail::VariantData) == 8,
|
||||
"sizeof(VariantData)");
|
||||
|
||||
int main() {}
|
||||
|
@ -32,11 +32,7 @@ TEST_CASE("ARDUINOJSON_USE_LONG_LONG == 0") {
|
||||
deserializeMsgPack(doc, "\xcf\x00\x00\x00\x01\x00\x00\x00\x00"_s);
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
#if defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ >= 8
|
||||
REQUIRE(doc.as<JsonInteger>() == 0x100000000);
|
||||
#else
|
||||
REQUIRE(doc.isNull());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -107,11 +107,11 @@
|
||||
// Capacity of each variant pool (in slots)
|
||||
#ifndef ARDUINOJSON_POOL_CAPACITY
|
||||
# if ARDUINOJSON_SIZEOF_POINTER <= 2
|
||||
# define ARDUINOJSON_POOL_CAPACITY 16 // 128 bytes
|
||||
# define ARDUINOJSON_POOL_CAPACITY 16 // 96 bytes
|
||||
# elif ARDUINOJSON_SIZEOF_POINTER == 4
|
||||
# define ARDUINOJSON_POOL_CAPACITY 64 // 1024 bytes
|
||||
# define ARDUINOJSON_POOL_CAPACITY 128 // 1024 bytes
|
||||
# else
|
||||
# define ARDUINOJSON_POOL_CAPACITY 128 // 3072 bytes
|
||||
# define ARDUINOJSON_POOL_CAPACITY 256 // 4096 bytes
|
||||
# endif
|
||||
#endif
|
||||
|
||||
@ -269,6 +269,12 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_DOUBLE
|
||||
# define ARDUINOJSON_USE_EXTENSIONS 1
|
||||
#else
|
||||
# define ARDUINOJSON_USE_EXTENSIONS 0
|
||||
#endif
|
||||
|
||||
#if defined(nullptr)
|
||||
# error nullptr is defined as a macro. Remove the faulty #define or #undef nullptr
|
||||
// See https://github.com/bblanchon/ArduinoJson/issues/1355
|
||||
|
@ -520,15 +520,15 @@ class JsonDeserializer {
|
||||
auto number = parseNumber(buffer_);
|
||||
switch (number.type()) {
|
||||
case NumberType::UnsignedInteger:
|
||||
result.setInteger(number.asUnsignedInteger());
|
||||
result.setInteger(number.asUnsignedInteger(), resources_);
|
||||
return DeserializationError::Ok;
|
||||
|
||||
case NumberType::SignedInteger:
|
||||
result.setInteger(number.asSignedInteger());
|
||||
result.setInteger(number.asSignedInteger(), resources_);
|
||||
return DeserializationError::Ok;
|
||||
|
||||
case NumberType::Float:
|
||||
result.setFloat(number.asFloat());
|
||||
result.setFloat(number.asFloat(), resources_);
|
||||
return DeserializationError::Ok;
|
||||
|
||||
default:
|
||||
|
@ -27,7 +27,7 @@ class JsonSerializer : public VariantDataVisitor<size_t> {
|
||||
while (slotId != NULL_SLOT) {
|
||||
auto slot = resources_->getVariant(slotId);
|
||||
|
||||
slot->accept(*this);
|
||||
slot->accept(*this, resources_);
|
||||
|
||||
slotId = slot->next();
|
||||
|
||||
@ -48,7 +48,7 @@ class JsonSerializer : public VariantDataVisitor<size_t> {
|
||||
|
||||
while (slotId != NULL_SLOT) {
|
||||
auto slot = resources_->getVariant(slotId);
|
||||
slot->accept(*this);
|
||||
slot->accept(*this, resources_);
|
||||
|
||||
slotId = slot->next();
|
||||
|
||||
|
@ -26,7 +26,7 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
|
||||
nesting_++;
|
||||
while (!it.done()) {
|
||||
indent();
|
||||
it->accept(*this);
|
||||
it->accept(*this, base::resources_);
|
||||
|
||||
it.next(base::resources_);
|
||||
base::write(it.done() ? "\r\n" : ",\r\n");
|
||||
@ -49,7 +49,7 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
|
||||
while (!it.done()) {
|
||||
if (isKey)
|
||||
indent();
|
||||
it->accept(*this);
|
||||
it->accept(*this, base::resources_);
|
||||
it.next(base::resources_);
|
||||
if (isKey)
|
||||
base::write(": ");
|
||||
|
@ -18,6 +18,13 @@ class VariantData;
|
||||
class VariantWithId;
|
||||
|
||||
class ResourceManager {
|
||||
union SlotData {
|
||||
VariantData variant;
|
||||
#if ARDUINOJSON_USE_EXTENSIONS
|
||||
VariantExtension extension;
|
||||
#endif
|
||||
};
|
||||
|
||||
public:
|
||||
ResourceManager(Allocator* allocator = DefaultAllocator::instance())
|
||||
: allocator_(allocator), overflowed_(false) {}
|
||||
@ -50,11 +57,15 @@ class ResourceManager {
|
||||
}
|
||||
|
||||
Slot<VariantData> allocVariant();
|
||||
|
||||
void freeVariant(Slot<VariantData> slot);
|
||||
|
||||
VariantData* getVariant(SlotId id) const;
|
||||
|
||||
#if ARDUINOJSON_USE_EXTENSIONS
|
||||
Slot<VariantExtension> allocExtension();
|
||||
void freeExtension(SlotId slot);
|
||||
VariantExtension* getExtension(SlotId id) const;
|
||||
#endif
|
||||
|
||||
template <typename TAdaptedString>
|
||||
StringNode* saveString(TAdaptedString str) {
|
||||
if (str.isNull())
|
||||
@ -112,7 +123,7 @@ class ResourceManager {
|
||||
Allocator* allocator_;
|
||||
bool overflowed_;
|
||||
StringPool stringPool_;
|
||||
MemoryPoolList<VariantData> variantPools_;
|
||||
MemoryPoolList<SlotData> variantPools_;
|
||||
};
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include <ArduinoJson/Collection/CollectionData.hpp>
|
||||
#include <ArduinoJson/Memory/ResourceManager.hpp>
|
||||
#include <ArduinoJson/Polyfills/alias_cast.hpp>
|
||||
#include <ArduinoJson/Variant/VariantData.hpp>
|
||||
|
||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
@ -16,16 +17,36 @@ inline Slot<VariantData> ResourceManager::allocVariant() {
|
||||
overflowed_ = true;
|
||||
return {};
|
||||
}
|
||||
return {new (p.ptr()) VariantData, p.id()};
|
||||
return {new (&p->variant) VariantData, p.id()};
|
||||
}
|
||||
|
||||
inline void ResourceManager::freeVariant(Slot<VariantData> variant) {
|
||||
variant->clear(this);
|
||||
variantPools_.freeSlot(variant);
|
||||
variantPools_.freeSlot({alias_cast<SlotData*>(variant.ptr()), variant.id()});
|
||||
}
|
||||
|
||||
inline VariantData* ResourceManager::getVariant(SlotId id) const {
|
||||
return reinterpret_cast<VariantData*>(variantPools_.getSlot(id));
|
||||
}
|
||||
|
||||
#if ARDUINOJSON_USE_EXTENSIONS
|
||||
inline Slot<VariantExtension> ResourceManager::allocExtension() {
|
||||
auto p = variantPools_.allocSlot(allocator_);
|
||||
if (!p) {
|
||||
overflowed_ = true;
|
||||
return {};
|
||||
}
|
||||
return {&p->extension, p.id()};
|
||||
}
|
||||
|
||||
inline void ResourceManager::freeExtension(SlotId id) {
|
||||
auto p = getExtension(id);
|
||||
variantPools_.freeSlot({reinterpret_cast<SlotData*>(p), id});
|
||||
}
|
||||
|
||||
inline VariantExtension* ResourceManager::getExtension(SlotId id) const {
|
||||
return &variantPools_.getSlot(id)->extension;
|
||||
}
|
||||
#endif
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
@ -91,7 +91,7 @@ class MsgPackDeserializer {
|
||||
|
||||
if (code <= 0x7f || code >= 0xe0) { // fixint
|
||||
if (allowValue)
|
||||
variant->setInteger(static_cast<int8_t>(code));
|
||||
variant->setInteger(static_cast<int8_t>(code), resources_);
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
@ -231,12 +231,12 @@ class MsgPackDeserializer {
|
||||
if (isSigned) {
|
||||
auto truncatedValue = static_cast<JsonInteger>(signedValue);
|
||||
if (truncatedValue == signedValue)
|
||||
variant->setInteger(truncatedValue);
|
||||
variant->setInteger(truncatedValue, resources_);
|
||||
// else set null on overflow
|
||||
} else {
|
||||
auto truncatedValue = static_cast<JsonUInt>(unsignedValue);
|
||||
if (truncatedValue == unsignedValue)
|
||||
variant->setInteger(truncatedValue);
|
||||
variant->setInteger(truncatedValue, resources_);
|
||||
// else set null on overflow
|
||||
}
|
||||
|
||||
@ -254,7 +254,7 @@ class MsgPackDeserializer {
|
||||
return err;
|
||||
|
||||
fixEndianness(value);
|
||||
variant->setFloat(value);
|
||||
variant->setFloat(value, resources_);
|
||||
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
@ -270,7 +270,7 @@ class MsgPackDeserializer {
|
||||
return err;
|
||||
|
||||
fixEndianness(value);
|
||||
variant->setFloat(value);
|
||||
variant->setFloat(value, resources_);
|
||||
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
@ -289,7 +289,7 @@ class MsgPackDeserializer {
|
||||
|
||||
doubleToFloat(i, o);
|
||||
fixEndianness(value);
|
||||
variant->setFloat(value);
|
||||
variant->setFloat(value, resources_);
|
||||
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ class MsgPackSerializer : public VariantDataVisitor<size_t> {
|
||||
auto slotId = array.head();
|
||||
while (slotId != NULL_SLOT) {
|
||||
auto slot = resources_->getVariant(slotId);
|
||||
slot->accept(*this);
|
||||
slot->accept(*this, resources_);
|
||||
slotId = slot->next();
|
||||
}
|
||||
|
||||
@ -84,7 +84,7 @@ class MsgPackSerializer : public VariantDataVisitor<size_t> {
|
||||
auto slotId = object.head();
|
||||
while (slotId != NULL_SLOT) {
|
||||
auto slot = resources_->getVariant(slotId);
|
||||
slot->accept(*this);
|
||||
slot->accept(*this, resources_);
|
||||
slotId = slot->next();
|
||||
}
|
||||
|
||||
|
@ -11,9 +11,10 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
template <template <typename> class TSerializer>
|
||||
size_t measure(ArduinoJson::JsonVariantConst source) {
|
||||
DummyWriter dp;
|
||||
TSerializer<DummyWriter> serializer(
|
||||
dp, VariantAttorney::getResourceManager(source));
|
||||
return VariantData::accept(VariantAttorney::getData(source), serializer);
|
||||
auto data = VariantAttorney::getData(source);
|
||||
auto resources = VariantAttorney::getResourceManager(source);
|
||||
TSerializer<DummyWriter> serializer(dp, resources);
|
||||
return VariantData::accept(data, resources, serializer);
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
@ -10,9 +10,10 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||
|
||||
template <template <typename> class TSerializer, typename TWriter>
|
||||
size_t doSerialize(ArduinoJson::JsonVariantConst source, TWriter writer) {
|
||||
TSerializer<TWriter> serializer(writer,
|
||||
VariantAttorney::getResourceManager(source));
|
||||
return VariantData::accept(VariantAttorney::getData(source), serializer);
|
||||
auto data = VariantAttorney::getData(source);
|
||||
auto resources = VariantAttorney::getResourceManager(source);
|
||||
TSerializer<TWriter> serializer(writer, resources);
|
||||
return VariantData::accept(data, resources, serializer);
|
||||
}
|
||||
|
||||
template <template <typename> class TSerializer, typename TDestination>
|
||||
|
@ -65,19 +65,21 @@ struct Converter<T, detail::enable_if_t<detail::is_integral<T>::value &&
|
||||
return false;
|
||||
auto resources = getResourceManager(dst);
|
||||
data->clear(resources);
|
||||
data->setInteger(src);
|
||||
data->setInteger(src, resources);
|
||||
return true;
|
||||
}
|
||||
|
||||
static T fromJson(JsonVariantConst src) {
|
||||
ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T);
|
||||
auto data = getData(src);
|
||||
return data ? data->template asIntegral<T>() : T();
|
||||
auto resources = getResourceManager(src);
|
||||
return data ? data->template asIntegral<T>(resources) : T();
|
||||
}
|
||||
|
||||
static bool checkJson(JsonVariantConst src) {
|
||||
auto data = getData(src);
|
||||
return data && data->template isInteger<T>();
|
||||
auto resources = getResourceManager(src);
|
||||
return data && data->template isInteger<T>(resources);
|
||||
}
|
||||
};
|
||||
|
||||
@ -90,12 +92,15 @@ struct Converter<T, detail::enable_if_t<detail::is_enum<T>::value>>
|
||||
|
||||
static T fromJson(JsonVariantConst src) {
|
||||
auto data = getData(src);
|
||||
return data ? static_cast<T>(data->template asIntegral<int>()) : T();
|
||||
auto resources = getResourceManager(src);
|
||||
return data ? static_cast<T>(data->template asIntegral<int>(resources))
|
||||
: T();
|
||||
}
|
||||
|
||||
static bool checkJson(JsonVariantConst src) {
|
||||
auto data = getData(src);
|
||||
return data && data->template isInteger<int>();
|
||||
auto resources = getResourceManager(src);
|
||||
return data && data->template isInteger<int>(resources);
|
||||
}
|
||||
};
|
||||
|
||||
@ -113,7 +118,8 @@ struct Converter<bool> : private detail::VariantAttorney {
|
||||
|
||||
static bool fromJson(JsonVariantConst src) {
|
||||
auto data = getData(src);
|
||||
return data ? data->asBoolean() : false;
|
||||
auto resources = getResourceManager(src);
|
||||
return data ? data->asBoolean(resources) : false;
|
||||
}
|
||||
|
||||
static bool checkJson(JsonVariantConst src) {
|
||||
@ -131,13 +137,14 @@ struct Converter<T, detail::enable_if_t<detail::is_floating_point<T>::value>>
|
||||
return false;
|
||||
auto resources = getResourceManager(dst);
|
||||
data->clear(resources);
|
||||
data->setFloat(static_cast<JsonFloat>(src));
|
||||
data->setFloat(src, resources);
|
||||
return true;
|
||||
}
|
||||
|
||||
static T fromJson(JsonVariantConst src) {
|
||||
auto data = getData(src);
|
||||
return data ? data->template asFloat<T>() : 0;
|
||||
auto resources = getResourceManager(src);
|
||||
return data ? data->template asFloat<T>(resources) : 0;
|
||||
}
|
||||
|
||||
static bool checkJson(JsonVariantConst src) {
|
||||
|
@ -55,7 +55,7 @@ typename TVisitor::result_type accept(JsonVariantConst variant,
|
||||
return visit.visit(nullptr);
|
||||
auto resources = VariantAttorney::getResourceManager(variant);
|
||||
VisitorAdapter<TVisitor> adapter(visit, resources);
|
||||
return data->accept(adapter);
|
||||
return data->accept(adapter, resources);
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
@ -24,10 +24,21 @@ enum {
|
||||
|
||||
VALUE_IS_BOOLEAN = 0x06,
|
||||
|
||||
NUMBER_BIT = 0x08,
|
||||
VALUE_IS_UNSIGNED_INTEGER = 0x08,
|
||||
VALUE_IS_SIGNED_INTEGER = 0x0A,
|
||||
VALUE_IS_FLOAT = 0x0C,
|
||||
NUMBER_BIT = 0x08, // 0000 1000
|
||||
VALUE_IS_UINT32 = 0x0A, // 0000 1010
|
||||
VALUE_IS_INT32 = 0x0C, // 0000 1100
|
||||
VALUE_IS_FLOAT = 0x0E, // 0000 1110
|
||||
|
||||
#if ARDUINOJSON_USE_EXTENSIONS
|
||||
EXTENSION_BIT = 0x10, // 0001 0000
|
||||
#endif
|
||||
#if ARDUINOJSON_USE_LONG_LONG
|
||||
VALUE_IS_UINT64 = 0x1A, // 0001 1010
|
||||
VALUE_IS_INT64 = 0x1C, // 0001 1100
|
||||
#endif
|
||||
#if ARDUINOJSON_USE_DOUBLE
|
||||
VALUE_IS_DOUBLE = 0x1E, // 0001 1110
|
||||
#endif
|
||||
|
||||
COLLECTION_MASK = 0x60,
|
||||
VALUE_IS_OBJECT = 0x20,
|
||||
@ -37,10 +48,13 @@ enum {
|
||||
union VariantContent {
|
||||
VariantContent() {}
|
||||
|
||||
JsonFloat asFloat;
|
||||
float asFloat;
|
||||
bool asBoolean;
|
||||
JsonUInt asUnsignedInteger;
|
||||
JsonInteger asSignedInteger;
|
||||
uint32_t asUint32;
|
||||
int32_t asInt32;
|
||||
#if ARDUINOJSON_USE_EXTENSIONS
|
||||
SlotId asSlotId;
|
||||
#endif
|
||||
ArrayData asArray;
|
||||
ObjectData asObject;
|
||||
CollectionData asCollection;
|
||||
@ -48,4 +62,16 @@ union VariantContent {
|
||||
struct StringNode* asOwnedString;
|
||||
};
|
||||
|
||||
#if ARDUINOJSON_USE_EXTENSIONS
|
||||
union VariantExtension {
|
||||
# if ARDUINOJSON_USE_LONG_LONG
|
||||
uint64_t asUint64;
|
||||
int64_t asInt64;
|
||||
# endif
|
||||
# if ARDUINOJSON_USE_DOUBLE
|
||||
double asDouble;
|
||||
# endif
|
||||
};
|
||||
#endif
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
@ -41,10 +41,17 @@ class VariantData {
|
||||
}
|
||||
|
||||
template <typename TVisitor>
|
||||
typename TVisitor::result_type accept(TVisitor& visit) const {
|
||||
typename TVisitor::result_type accept(
|
||||
TVisitor& visit, const ResourceManager* resources) const {
|
||||
(void)resources; // silence warning
|
||||
switch (type_) {
|
||||
case VALUE_IS_FLOAT:
|
||||
return visit.visit(content_.asFloat);
|
||||
return visit.visit(static_cast<JsonFloat>(content_.asFloat));
|
||||
|
||||
#if ARDUINOJSON_USE_DOUBLE
|
||||
case VALUE_IS_DOUBLE:
|
||||
return visit.visit(getExtension(resources)->asDouble);
|
||||
#endif
|
||||
|
||||
case VALUE_IS_ARRAY:
|
||||
return visit.visit(content_.asArray);
|
||||
@ -64,11 +71,19 @@ class VariantData {
|
||||
return visit.visit(RawString(content_.asOwnedString->data,
|
||||
content_.asOwnedString->length));
|
||||
|
||||
case VALUE_IS_SIGNED_INTEGER:
|
||||
return visit.visit(content_.asSignedInteger);
|
||||
case VALUE_IS_INT32:
|
||||
return visit.visit(static_cast<JsonInteger>(content_.asInt32));
|
||||
|
||||
case VALUE_IS_UNSIGNED_INTEGER:
|
||||
return visit.visit(content_.asUnsignedInteger);
|
||||
case VALUE_IS_UINT32:
|
||||
return visit.visit(static_cast<JsonUInt>(content_.asUint32));
|
||||
|
||||
#if ARDUINOJSON_USE_LONG_LONG
|
||||
case VALUE_IS_INT64:
|
||||
return visit.visit(getExtension(resources)->asInt64);
|
||||
|
||||
case VALUE_IS_UINT64:
|
||||
return visit.visit(getExtension(resources)->asUint64);
|
||||
#endif
|
||||
|
||||
case VALUE_IS_BOOLEAN:
|
||||
return visit.visit(content_.asBoolean != 0);
|
||||
@ -80,9 +95,10 @@ class VariantData {
|
||||
|
||||
template <typename TVisitor>
|
||||
static typename TVisitor::result_type accept(const VariantData* var,
|
||||
const ResourceManager* resources,
|
||||
TVisitor& visit) {
|
||||
if (var != 0)
|
||||
return var->accept(visit);
|
||||
return var->accept(visit, resources);
|
||||
else
|
||||
return visit.visit(nullptr);
|
||||
}
|
||||
@ -113,17 +129,27 @@ class VariantData {
|
||||
return var->addValue(value, resources);
|
||||
}
|
||||
|
||||
bool asBoolean() const {
|
||||
bool asBoolean(const ResourceManager* resources) const {
|
||||
(void)resources; // silence warning
|
||||
switch (type_) {
|
||||
case VALUE_IS_BOOLEAN:
|
||||
return content_.asBoolean;
|
||||
case VALUE_IS_SIGNED_INTEGER:
|
||||
case VALUE_IS_UNSIGNED_INTEGER:
|
||||
return content_.asUnsignedInteger != 0;
|
||||
case VALUE_IS_UINT32:
|
||||
case VALUE_IS_INT32:
|
||||
return content_.asUint32 != 0;
|
||||
case VALUE_IS_FLOAT:
|
||||
return content_.asFloat != 0;
|
||||
#if ARDUINOJSON_USE_DOUBLE
|
||||
case VALUE_IS_DOUBLE:
|
||||
return getExtension(resources)->asDouble != 0;
|
||||
#endif
|
||||
case VALUE_IS_NULL:
|
||||
return false;
|
||||
#if ARDUINOJSON_USE_LONG_LONG
|
||||
case VALUE_IS_UINT64:
|
||||
case VALUE_IS_INT64:
|
||||
return getExtension(resources)->asUint64 != 0;
|
||||
#endif
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
@ -146,41 +172,63 @@ class VariantData {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T asFloat() const {
|
||||
T asFloat(const ResourceManager* resources) const {
|
||||
static_assert(is_floating_point<T>::value, "T must be a floating point");
|
||||
(void)resources; // silence warning
|
||||
switch (type_) {
|
||||
case VALUE_IS_BOOLEAN:
|
||||
return static_cast<T>(content_.asBoolean);
|
||||
case VALUE_IS_UNSIGNED_INTEGER:
|
||||
return static_cast<T>(content_.asUnsignedInteger);
|
||||
case VALUE_IS_SIGNED_INTEGER:
|
||||
return static_cast<T>(content_.asSignedInteger);
|
||||
case VALUE_IS_UINT32:
|
||||
return static_cast<T>(content_.asUint32);
|
||||
case VALUE_IS_INT32:
|
||||
return static_cast<T>(content_.asInt32);
|
||||
#if ARDUINOJSON_USE_LONG_LONG
|
||||
case VALUE_IS_UINT64:
|
||||
return static_cast<T>(getExtension(resources)->asUint64);
|
||||
case VALUE_IS_INT64:
|
||||
return static_cast<T>(getExtension(resources)->asInt64);
|
||||
#endif
|
||||
case VALUE_IS_LINKED_STRING:
|
||||
case VALUE_IS_OWNED_STRING:
|
||||
return parseNumber<T>(content_.asOwnedString->data);
|
||||
case VALUE_IS_FLOAT:
|
||||
return static_cast<T>(content_.asFloat);
|
||||
#if ARDUINOJSON_USE_DOUBLE
|
||||
case VALUE_IS_DOUBLE:
|
||||
return static_cast<T>(getExtension(resources)->asDouble);
|
||||
#endif
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T asIntegral() const {
|
||||
T asIntegral(const ResourceManager* resources) const {
|
||||
static_assert(is_integral<T>::value, "T must be an integral type");
|
||||
(void)resources; // silence warning
|
||||
switch (type_) {
|
||||
case VALUE_IS_BOOLEAN:
|
||||
return content_.asBoolean;
|
||||
case VALUE_IS_UNSIGNED_INTEGER:
|
||||
return convertNumber<T>(content_.asUnsignedInteger);
|
||||
case VALUE_IS_SIGNED_INTEGER:
|
||||
return convertNumber<T>(content_.asSignedInteger);
|
||||
case VALUE_IS_UINT32:
|
||||
return convertNumber<T>(content_.asUint32);
|
||||
case VALUE_IS_INT32:
|
||||
return convertNumber<T>(content_.asInt32);
|
||||
#if ARDUINOJSON_USE_LONG_LONG
|
||||
case VALUE_IS_UINT64:
|
||||
return convertNumber<T>(getExtension(resources)->asUint64);
|
||||
case VALUE_IS_INT64:
|
||||
return convertNumber<T>(getExtension(resources)->asInt64);
|
||||
#endif
|
||||
case VALUE_IS_LINKED_STRING:
|
||||
return parseNumber<T>(content_.asLinkedString);
|
||||
case VALUE_IS_OWNED_STRING:
|
||||
return parseNumber<T>(content_.asOwnedString->data);
|
||||
case VALUE_IS_FLOAT:
|
||||
return convertNumber<T>(content_.asFloat);
|
||||
#if ARDUINOJSON_USE_DOUBLE
|
||||
case VALUE_IS_DOUBLE:
|
||||
return convertNumber<T>(getExtension(resources)->asDouble);
|
||||
#endif
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -216,6 +264,10 @@ class VariantData {
|
||||
}
|
||||
}
|
||||
|
||||
#if ARDUINOJSON_USE_EXTENSIONS
|
||||
const VariantExtension* getExtension(const ResourceManager* resources) const;
|
||||
#endif
|
||||
|
||||
VariantData* getElement(size_t index,
|
||||
const ResourceManager* resources) const {
|
||||
return ArrayData::getElement(asArray(), index, resources);
|
||||
@ -274,13 +326,22 @@ class VariantData {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool isInteger() const {
|
||||
bool isInteger(const ResourceManager* resources) const {
|
||||
(void)resources; // silence warning
|
||||
switch (type_) {
|
||||
case VALUE_IS_UNSIGNED_INTEGER:
|
||||
return canConvertNumber<T>(content_.asUnsignedInteger);
|
||||
case VALUE_IS_UINT32:
|
||||
return canConvertNumber<T>(content_.asUint32);
|
||||
|
||||
case VALUE_IS_SIGNED_INTEGER:
|
||||
return canConvertNumber<T>(content_.asSignedInteger);
|
||||
case VALUE_IS_INT32:
|
||||
return canConvertNumber<T>(content_.asInt32);
|
||||
|
||||
#if ARDUINOJSON_USE_LONG_LONG
|
||||
case VALUE_IS_UINT64:
|
||||
return canConvertNumber<T>(getExtension(resources)->asUint64);
|
||||
|
||||
case VALUE_IS_INT64:
|
||||
return canConvertNumber<T>(getExtension(resources)->asInt64);
|
||||
#endif
|
||||
|
||||
default:
|
||||
return false;
|
||||
@ -354,25 +415,23 @@ class VariantData {
|
||||
content_.asBoolean = value;
|
||||
}
|
||||
|
||||
void setFloat(JsonFloat value) {
|
||||
template <typename T>
|
||||
typename enable_if<sizeof(T) == 4>::type setFloat(T value, ResourceManager*) {
|
||||
ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL); // must call clear() first
|
||||
type_ = VALUE_IS_FLOAT;
|
||||
content_.asFloat = value;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
enable_if_t<is_signed<T>::value> setInteger(T value) {
|
||||
ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL); // must call clear() first
|
||||
type_ = VALUE_IS_SIGNED_INTEGER;
|
||||
content_.asSignedInteger = value;
|
||||
}
|
||||
typename enable_if<sizeof(T) == 8>::type setFloat(T value, ResourceManager*);
|
||||
|
||||
template <typename T>
|
||||
enable_if_t<is_unsigned<T>::value> setInteger(T value) {
|
||||
ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL); // must call clear() first
|
||||
type_ = VALUE_IS_UNSIGNED_INTEGER;
|
||||
content_.asUnsignedInteger = static_cast<JsonUInt>(value);
|
||||
}
|
||||
enable_if_t<is_signed<T>::value> setInteger(T value,
|
||||
ResourceManager* resources);
|
||||
|
||||
template <typename T>
|
||||
enable_if_t<is_unsigned<T>::value> setInteger(T value,
|
||||
ResourceManager* resources);
|
||||
|
||||
void setRawString(StringNode* s) {
|
||||
ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL); // must call clear() first
|
||||
|
@ -44,6 +44,11 @@ inline void VariantData::clear(ResourceManager* resources) {
|
||||
if (type_ & OWNED_VALUE_BIT)
|
||||
resources->dereferenceString(content_.asOwnedString->data);
|
||||
|
||||
#if ARDUINOJSON_USE_EXTENSIONS
|
||||
if (type_ & EXTENSION_BIT)
|
||||
resources->freeExtension(content_.asSlotId);
|
||||
#endif
|
||||
|
||||
auto collection = asCollection();
|
||||
if (collection)
|
||||
collection->clear(resources);
|
||||
@ -51,4 +56,82 @@ inline void VariantData::clear(ResourceManager* resources) {
|
||||
type_ = VALUE_IS_NULL;
|
||||
}
|
||||
|
||||
#if ARDUINOJSON_USE_EXTENSIONS
|
||||
inline const VariantExtension* VariantData::getExtension(
|
||||
const ResourceManager* resources) const {
|
||||
ARDUINOJSON_ASSERT(type_ & EXTENSION_BIT);
|
||||
return resources->getExtension(content_.asSlotId);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
typename enable_if<sizeof(T) == 8>::type VariantData::setFloat(
|
||||
T value, ResourceManager* resources) {
|
||||
ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL); // must call clear() first
|
||||
(void)resources; // silence warning
|
||||
|
||||
float valueAsFloat = static_cast<float>(value);
|
||||
|
||||
#if ARDUINOJSON_USE_DOUBLE
|
||||
if (value == valueAsFloat) {
|
||||
type_ = VALUE_IS_FLOAT;
|
||||
content_.asFloat = valueAsFloat;
|
||||
} else {
|
||||
auto extension = resources->allocExtension();
|
||||
if (extension) {
|
||||
type_ = VALUE_IS_DOUBLE;
|
||||
content_.asSlotId = extension.id();
|
||||
extension->asDouble = value;
|
||||
}
|
||||
}
|
||||
#else
|
||||
type_ = VALUE_IS_FLOAT;
|
||||
content_.asFloat = valueAsFloat;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
enable_if_t<is_signed<T>::value> VariantData::setInteger(
|
||||
T value, ResourceManager* resources) {
|
||||
ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL); // must call clear() first
|
||||
(void)resources; // silence warning
|
||||
|
||||
if (canConvertNumber<int32_t>(value)) {
|
||||
type_ = VALUE_IS_INT32;
|
||||
content_.asInt32 = static_cast<int32_t>(value);
|
||||
}
|
||||
#if ARDUINOJSON_USE_LONG_LONG
|
||||
else {
|
||||
auto extension = resources->allocExtension();
|
||||
if (extension) {
|
||||
type_ = VALUE_IS_INT64;
|
||||
content_.asSlotId = extension.id();
|
||||
extension->asInt64 = value;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
enable_if_t<is_unsigned<T>::value> VariantData::setInteger(
|
||||
T value, ResourceManager* resources) {
|
||||
ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL); // must call clear() first
|
||||
(void)resources; // silence warning
|
||||
|
||||
if (canConvertNumber<uint32_t>(value)) {
|
||||
type_ = VALUE_IS_UINT32;
|
||||
content_.asUint32 = static_cast<uint32_t>(value);
|
||||
}
|
||||
#if ARDUINOJSON_USE_LONG_LONG
|
||||
else {
|
||||
auto extension = resources->allocExtension();
|
||||
if (extension) {
|
||||
type_ = VALUE_IS_UINT64;
|
||||
content_.asSlotId = extension.id();
|
||||
extension->asUint64 = value;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||
|
Reference in New Issue
Block a user