Add VariantType

This commit is contained in:
Benoit Blanchon
2024-09-02 17:56:19 +02:00
parent 33452c1f37
commit 65ba36622c
3 changed files with 115 additions and 113 deletions

View File

@ -13,38 +13,39 @@
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
enum {
OWNED_VALUE_BIT = 0x01,
VALUE_IS_NULL = 0,
VALUE_IS_RAW_STRING = 0x03,
VALUE_IS_LINKED_STRING = 0x04,
VALUE_IS_OWNED_STRING = 0x05,
// CAUTION: no OWNED_VALUE_BIT below
VALUE_IS_BOOLEAN = 0x06,
NUMBER_BIT = 0x08, // 0000 1000
VALUE_IS_UINT32 = 0x0A, // 0000 1010
VALUE_IS_INT32 = 0x0C, // 0000 1100
VALUE_IS_FLOAT = 0x0E, // 0000 1110
enum class VariantTypeBits : uint8_t {
OwnedStringBit = 0x01, // 0000 0001
NumberBit = 0x08, // 0000 1000
#if ARDUINOJSON_USE_EXTENSIONS
EXTENSION_BIT = 0x10, // 0001 0000
ExtensionBit = 0x10, // 0001 0000
#endif
CollectionMask = 0x60,
};
enum class VariantType : uint8_t {
Null = 0, // 0000 0000
RawString = 0x03, // 0000 0011
LinkedString = 0x04, // 0000 0100
OwnedString = 0x05, // 0000 0101
Boolean = 0x06, // 0000 0110
Uint32 = 0x0A, // 0000 1010
Int32 = 0x0C, // 0000 1100
Float = 0x0E, // 0000 1110
#if ARDUINOJSON_USE_LONG_LONG
VALUE_IS_UINT64 = 0x1A, // 0001 1010
VALUE_IS_INT64 = 0x1C, // 0001 1100
Uint64 = 0x1A, // 0001 1010
Int64 = 0x1C, // 0001 1100
#endif
#if ARDUINOJSON_USE_DOUBLE
VALUE_IS_DOUBLE = 0x1E, // 0001 1110
Double = 0x1E, // 0001 1110
#endif
COLLECTION_MASK = 0x60,
VALUE_IS_OBJECT = 0x20,
VALUE_IS_ARRAY = 0x40,
Object = 0x20,
Array = 0x40,
};
inline bool operator&(VariantType type, VariantTypeBits bit) {
return (uint8_t(type) & uint8_t(bit)) != 0;
}
union VariantContent {
VariantContent() {}

View File

@ -19,7 +19,7 @@ T parseNumber(const char* s);
class VariantData {
VariantContent content_; // must be first to allow cast from array to variant
uint8_t type_;
VariantType type_;
SlotId next_;
public:
@ -30,7 +30,7 @@ class VariantData {
static void operator delete(void*, void*) noexcept {}
VariantData() : type_(VALUE_IS_NULL), next_(NULL_SLOT) {}
VariantData() : type_(VariantType::Null), next_(NULL_SLOT) {}
SlotId next() const {
return next_;
@ -45,47 +45,47 @@ class VariantData {
TVisitor& visit, const ResourceManager* resources) const {
(void)resources; // silence warning
switch (type_) {
case VALUE_IS_FLOAT:
case VariantType::Float:
return visit.visit(static_cast<JsonFloat>(content_.asFloat));
#if ARDUINOJSON_USE_DOUBLE
case VALUE_IS_DOUBLE:
case VariantType::Double:
return visit.visit(getExtension(resources)->asDouble);
#endif
case VALUE_IS_ARRAY:
case VariantType::Array:
return visit.visit(content_.asArray);
case VALUE_IS_OBJECT:
case VariantType::Object:
return visit.visit(content_.asObject);
case VALUE_IS_LINKED_STRING:
case VariantType::LinkedString:
return visit.visit(JsonString(content_.asLinkedString));
case VALUE_IS_OWNED_STRING:
case VariantType::OwnedString:
return visit.visit(JsonString(content_.asOwnedString->data,
content_.asOwnedString->length,
JsonString::Copied));
case VALUE_IS_RAW_STRING:
case VariantType::RawString:
return visit.visit(RawString(content_.asOwnedString->data,
content_.asOwnedString->length));
case VALUE_IS_INT32:
case VariantType::Int32:
return visit.visit(static_cast<JsonInteger>(content_.asInt32));
case VALUE_IS_UINT32:
case VariantType::Uint32:
return visit.visit(static_cast<JsonUInt>(content_.asUint32));
#if ARDUINOJSON_USE_LONG_LONG
case VALUE_IS_INT64:
case VariantType::Int64:
return visit.visit(getExtension(resources)->asInt64);
case VALUE_IS_UINT64:
case VariantType::Uint64:
return visit.visit(getExtension(resources)->asUint64);
#endif
case VALUE_IS_BOOLEAN:
case VariantType::Boolean:
return visit.visit(content_.asBoolean != 0);
default:
@ -132,22 +132,22 @@ class VariantData {
bool asBoolean(const ResourceManager* resources) const {
(void)resources; // silence warning
switch (type_) {
case VALUE_IS_BOOLEAN:
case VariantType::Boolean:
return content_.asBoolean;
case VALUE_IS_UINT32:
case VALUE_IS_INT32:
case VariantType::Uint32:
case VariantType::Int32:
return content_.asUint32 != 0;
case VALUE_IS_FLOAT:
case VariantType::Float:
return content_.asFloat != 0;
#if ARDUINOJSON_USE_DOUBLE
case VALUE_IS_DOUBLE:
case VariantType::Double:
return getExtension(resources)->asDouble != 0;
#endif
case VALUE_IS_NULL:
case VariantType::Null:
return false;
#if ARDUINOJSON_USE_LONG_LONG
case VALUE_IS_UINT64:
case VALUE_IS_INT64:
case VariantType::Uint64:
case VariantType::Int64:
return getExtension(resources)->asUint64 != 0;
#endif
default:
@ -176,25 +176,25 @@ class VariantData {
static_assert(is_floating_point<T>::value, "T must be a floating point");
(void)resources; // silence warning
switch (type_) {
case VALUE_IS_BOOLEAN:
case VariantType::Boolean:
return static_cast<T>(content_.asBoolean);
case VALUE_IS_UINT32:
case VariantType::Uint32:
return static_cast<T>(content_.asUint32);
case VALUE_IS_INT32:
case VariantType::Int32:
return static_cast<T>(content_.asInt32);
#if ARDUINOJSON_USE_LONG_LONG
case VALUE_IS_UINT64:
case VariantType::Uint64:
return static_cast<T>(getExtension(resources)->asUint64);
case VALUE_IS_INT64:
case VariantType::Int64:
return static_cast<T>(getExtension(resources)->asInt64);
#endif
case VALUE_IS_LINKED_STRING:
case VALUE_IS_OWNED_STRING:
case VariantType::LinkedString:
case VariantType::OwnedString:
return parseNumber<T>(content_.asOwnedString->data);
case VALUE_IS_FLOAT:
case VariantType::Float:
return static_cast<T>(content_.asFloat);
#if ARDUINOJSON_USE_DOUBLE
case VALUE_IS_DOUBLE:
case VariantType::Double:
return static_cast<T>(getExtension(resources)->asDouble);
#endif
default:
@ -207,26 +207,26 @@ class VariantData {
static_assert(is_integral<T>::value, "T must be an integral type");
(void)resources; // silence warning
switch (type_) {
case VALUE_IS_BOOLEAN:
case VariantType::Boolean:
return content_.asBoolean;
case VALUE_IS_UINT32:
case VariantType::Uint32:
return convertNumber<T>(content_.asUint32);
case VALUE_IS_INT32:
case VariantType::Int32:
return convertNumber<T>(content_.asInt32);
#if ARDUINOJSON_USE_LONG_LONG
case VALUE_IS_UINT64:
case VariantType::Uint64:
return convertNumber<T>(getExtension(resources)->asUint64);
case VALUE_IS_INT64:
case VariantType::Int64:
return convertNumber<T>(getExtension(resources)->asInt64);
#endif
case VALUE_IS_LINKED_STRING:
case VariantType::LinkedString:
return parseNumber<T>(content_.asLinkedString);
case VALUE_IS_OWNED_STRING:
case VariantType::OwnedString:
return parseNumber<T>(content_.asOwnedString->data);
case VALUE_IS_FLOAT:
case VariantType::Float:
return convertNumber<T>(content_.asFloat);
#if ARDUINOJSON_USE_DOUBLE
case VALUE_IS_DOUBLE:
case VariantType::Double:
return convertNumber<T>(getExtension(resources)->asDouble);
#endif
default:
@ -244,7 +244,7 @@ class VariantData {
JsonString asRawString() const {
switch (type_) {
case VALUE_IS_RAW_STRING:
case VariantType::RawString:
return JsonString(content_.asOwnedString->data,
content_.asOwnedString->length, JsonString::Copied);
default:
@ -254,9 +254,9 @@ class VariantData {
JsonString asString() const {
switch (type_) {
case VALUE_IS_LINKED_STRING:
case VariantType::LinkedString:
return JsonString(content_.asLinkedString, JsonString::Linked);
case VALUE_IS_OWNED_STRING:
case VariantType::OwnedString:
return JsonString(content_.asOwnedString->data,
content_.asOwnedString->length, JsonString::Copied);
default:
@ -310,36 +310,36 @@ class VariantData {
}
bool isArray() const {
return type_ == VALUE_IS_ARRAY;
return type_ == VariantType::Array;
}
bool isBoolean() const {
return type_ == VALUE_IS_BOOLEAN;
return type_ == VariantType::Boolean;
}
bool isCollection() const {
return (type_ & COLLECTION_MASK) != 0;
return type_ & VariantTypeBits::CollectionMask;
}
bool isFloat() const {
return (type_ & NUMBER_BIT) != 0;
return type_ & VariantTypeBits::NumberBit;
}
template <typename T>
bool isInteger(const ResourceManager* resources) const {
(void)resources; // silence warning
switch (type_) {
case VALUE_IS_UINT32:
case VariantType::Uint32:
return canConvertNumber<T>(content_.asUint32);
case VALUE_IS_INT32:
case VariantType::Int32:
return canConvertNumber<T>(content_.asInt32);
#if ARDUINOJSON_USE_LONG_LONG
case VALUE_IS_UINT64:
case VariantType::Uint64:
return canConvertNumber<T>(getExtension(resources)->asUint64);
case VALUE_IS_INT64:
case VariantType::Int64:
return canConvertNumber<T>(getExtension(resources)->asInt64);
#endif
@ -349,7 +349,7 @@ class VariantData {
}
bool isNull() const {
return type_ == VALUE_IS_NULL;
return type_ == VariantType::Null;
}
static bool isNull(const VariantData* var) {
@ -359,11 +359,12 @@ class VariantData {
}
bool isObject() const {
return type_ == VALUE_IS_OBJECT;
return type_ == VariantType::Object;
}
bool isString() const {
return type_ == VALUE_IS_LINKED_STRING || type_ == VALUE_IS_OWNED_STRING;
return type_ == VariantType::LinkedString ||
type_ == VariantType::OwnedString;
}
size_t nesting(const ResourceManager* resources) const {
@ -406,19 +407,19 @@ class VariantData {
}
void reset() { // TODO: remove
type_ = VALUE_IS_NULL;
type_ = VariantType::Null;
}
void setBoolean(bool value) {
ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL); // must call clear() first
type_ = VALUE_IS_BOOLEAN;
ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first
type_ = VariantType::Boolean;
content_.asBoolean = value;
}
template <typename T>
enable_if_t<sizeof(T) == 4, bool> setFloat(T value, ResourceManager*) {
ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL); // must call clear() first
type_ = VALUE_IS_FLOAT;
ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first
type_ = VariantType::Float;
content_.asFloat = value;
return true;
}
@ -435,9 +436,9 @@ class VariantData {
T value, ResourceManager* resources);
void setRawString(StringNode* s) {
ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL); // must call clear() first
ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first
ARDUINOJSON_ASSERT(s);
type_ = VALUE_IS_RAW_STRING;
type_ = VariantType::RawString;
content_.asOwnedString = s;
}
@ -471,16 +472,16 @@ class VariantData {
}
void setLinkedString(const char* s) {
ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL); // must call clear() first
ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first
ARDUINOJSON_ASSERT(s);
type_ = VALUE_IS_LINKED_STRING;
type_ = VariantType::LinkedString;
content_.asLinkedString = s;
}
void setOwnedString(StringNode* s) {
ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL); // must call clear() first
ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first
ARDUINOJSON_ASSERT(s);
type_ = VALUE_IS_OWNED_STRING;
type_ = VariantType::OwnedString;
content_.asOwnedString = s;
}
@ -499,8 +500,8 @@ class VariantData {
}
ArrayData& toArray() {
ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL); // must call clear() first
type_ = VALUE_IS_ARRAY;
ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first
type_ = VariantType::Array;
new (&content_.asArray) ArrayData();
return content_.asArray;
}
@ -513,8 +514,8 @@ class VariantData {
}
ObjectData& toObject() {
ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL); // must call clear() first
type_ = VALUE_IS_OBJECT;
ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first
type_ = VariantType::Object;
new (&content_.asObject) ObjectData();
return content_.asObject;
}
@ -526,7 +527,7 @@ class VariantData {
return &var->toObject();
}
uint8_t type() const {
VariantType type() const {
return type_;
}

View File

@ -12,7 +12,7 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename T>
inline void VariantData::setRawString(SerializedValue<T> value,
ResourceManager* resources) {
ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL); // must call clear() first
ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first
auto dup = resources->saveString(adaptString(value.data(), value.size()));
if (dup)
setRawString(dup);
@ -21,7 +21,7 @@ inline void VariantData::setRawString(SerializedValue<T> value,
template <typename TAdaptedString>
inline bool VariantData::setString(TAdaptedString value,
ResourceManager* resources) {
ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL); // must call clear() first
ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first
if (value.isNull())
return false;
@ -41,11 +41,11 @@ inline bool VariantData::setString(TAdaptedString value,
}
inline void VariantData::clear(ResourceManager* resources) {
if (type_ & OWNED_VALUE_BIT)
if (type_ & VariantTypeBits::OwnedStringBit)
resources->dereferenceString(content_.asOwnedString->data);
#if ARDUINOJSON_USE_EXTENSIONS
if (type_ & EXTENSION_BIT)
if (type_ & VariantTypeBits::ExtensionBit)
resources->freeExtension(content_.asSlotId);
#endif
@ -53,13 +53,13 @@ inline void VariantData::clear(ResourceManager* resources) {
if (collection)
collection->clear(resources);
type_ = VALUE_IS_NULL;
type_ = VariantType::Null;
}
#if ARDUINOJSON_USE_EXTENSIONS
inline const VariantExtension* VariantData::getExtension(
const ResourceManager* resources) const {
ARDUINOJSON_ASSERT(type_ & EXTENSION_BIT);
ARDUINOJSON_ASSERT(type_ & VariantTypeBits::ExtensionBit);
return resources->getExtension(content_.asSlotId);
}
#endif
@ -67,25 +67,25 @@ inline const VariantExtension* VariantData::getExtension(
template <typename T>
enable_if_t<sizeof(T) == 8, bool> VariantData::setFloat(
T value, ResourceManager* resources) {
ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL); // must call clear() first
ARDUINOJSON_ASSERT(type_ == VariantType::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;
type_ = VariantType::Float;
content_.asFloat = valueAsFloat;
} else {
auto extension = resources->allocExtension();
if (!extension)
return false;
type_ = VALUE_IS_DOUBLE;
type_ = VariantType::Double;
content_.asSlotId = extension.id();
extension->asDouble = value;
}
#else
type_ = VALUE_IS_FLOAT;
type_ = VariantType::Float;
content_.asFloat = valueAsFloat;
#endif
return true;
@ -94,11 +94,11 @@ enable_if_t<sizeof(T) == 8, bool> VariantData::setFloat(
template <typename T>
enable_if_t<is_signed<T>::value, bool> VariantData::setInteger(
T value, ResourceManager* resources) {
ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL); // must call clear() first
ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first
(void)resources; // silence warning
if (canConvertNumber<int32_t>(value)) {
type_ = VALUE_IS_INT32;
type_ = VariantType::Int32;
content_.asInt32 = static_cast<int32_t>(value);
}
#if ARDUINOJSON_USE_LONG_LONG
@ -106,7 +106,7 @@ enable_if_t<is_signed<T>::value, bool> VariantData::setInteger(
auto extension = resources->allocExtension();
if (!extension)
return false;
type_ = VALUE_IS_INT64;
type_ = VariantType::Int64;
content_.asSlotId = extension.id();
extension->asInt64 = value;
}
@ -117,11 +117,11 @@ enable_if_t<is_signed<T>::value, bool> VariantData::setInteger(
template <typename T>
enable_if_t<is_unsigned<T>::value, bool> VariantData::setInteger(
T value, ResourceManager* resources) {
ARDUINOJSON_ASSERT(type_ == VALUE_IS_NULL); // must call clear() first
ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first
(void)resources; // silence warning
if (canConvertNumber<uint32_t>(value)) {
type_ = VALUE_IS_UINT32;
type_ = VariantType::Uint32;
content_.asUint32 = static_cast<uint32_t>(value);
}
#if ARDUINOJSON_USE_LONG_LONG
@ -129,7 +129,7 @@ enable_if_t<is_unsigned<T>::value, bool> VariantData::setInteger(
auto extension = resources->allocExtension();
if (!extension)
return false;
type_ = VALUE_IS_UINT64;
type_ = VariantType::Uint64;
content_.asSlotId = extension.id();
extension->asUint64 = value;
}