|
|
@@ -27,12 +27,11 @@ static bool isTinyString(const T& s, size_t n) {
|
|
|
return !containsNul;
|
|
|
}
|
|
|
|
|
|
-class VariantData {
|
|
|
- VariantContent content_; // must be first to allow cast from array to variant
|
|
|
- VariantType type_;
|
|
|
- SlotId next_;
|
|
|
+struct VariantData {
|
|
|
+ VariantContent content; // must be first to allow cast from array to variant
|
|
|
+ VariantType type = VariantType::Null;
|
|
|
+ SlotId next = NULL_SLOT;
|
|
|
|
|
|
- public:
|
|
|
// Placement new
|
|
|
static void* operator new(size_t, void* p) noexcept {
|
|
|
return p;
|
|
|
@@ -40,121 +39,175 @@ class VariantData {
|
|
|
|
|
|
static void operator delete(void*, void*) noexcept {}
|
|
|
|
|
|
- VariantData() : type_(VariantType::Null), next_(NULL_SLOT) {}
|
|
|
+ JsonString asRawString() const {
|
|
|
+ switch (type) {
|
|
|
+ case VariantType::RawString:
|
|
|
+ return JsonString(content.asStringNode->data,
|
|
|
+ content.asStringNode->length);
|
|
|
+ default:
|
|
|
+ return JsonString();
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- SlotId next() const {
|
|
|
- return next_;
|
|
|
+ JsonString asString() const {
|
|
|
+ switch (type) {
|
|
|
+ case VariantType::TinyString:
|
|
|
+ return JsonString(content.asTinyString);
|
|
|
+ case VariantType::LongString:
|
|
|
+ return JsonString(content.asStringNode->data,
|
|
|
+ content.asStringNode->length);
|
|
|
+ default:
|
|
|
+ return JsonString();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- void setNext(SlotId slot) {
|
|
|
- next_ = slot;
|
|
|
+ bool isArray() const {
|
|
|
+ return type == VariantType::Array;
|
|
|
}
|
|
|
|
|
|
- template <typename TVisitor>
|
|
|
- typename TVisitor::result_type accept(TVisitor& visit,
|
|
|
- ResourceManager* resources) {
|
|
|
-#if ARDUINOJSON_USE_8_BYTE_POOL
|
|
|
- auto eightByteValue = getEightByte(resources);
|
|
|
-#else
|
|
|
- (void)resources; // silence warning
|
|
|
-#endif
|
|
|
- switch (type_) {
|
|
|
- case VariantType::Float:
|
|
|
- return visit.visit(content_.asFloat);
|
|
|
+ bool isBoolean() const {
|
|
|
+ return type == VariantType::Boolean;
|
|
|
+ }
|
|
|
|
|
|
-#if ARDUINOJSON_USE_DOUBLE
|
|
|
- case VariantType::Double:
|
|
|
- return visit.visit(eightByteValue->asDouble);
|
|
|
-#endif
|
|
|
+ bool isFloat() const {
|
|
|
+ return type & VariantTypeBits::NumberBit;
|
|
|
+ }
|
|
|
|
|
|
- case VariantType::Array:
|
|
|
- return visit.visit(asArray(resources));
|
|
|
+ bool isNull() const {
|
|
|
+ return type == VariantType::Null;
|
|
|
+ }
|
|
|
|
|
|
- case VariantType::Object:
|
|
|
- return visit.visit(asObject(resources));
|
|
|
+ bool isObject() const {
|
|
|
+ return type == VariantType::Object;
|
|
|
+ }
|
|
|
|
|
|
- case VariantType::TinyString:
|
|
|
- return visit.visit(JsonString(content_.asTinyString));
|
|
|
+ bool isString() const {
|
|
|
+ return type == VariantType::LongString || type == VariantType::TinyString;
|
|
|
+ }
|
|
|
|
|
|
- case VariantType::LongString:
|
|
|
- return visit.visit(JsonString(content_.asStringNode->data,
|
|
|
- content_.asStringNode->length));
|
|
|
+ void setBoolean(bool value) {
|
|
|
+ ARDUINOJSON_ASSERT(type == VariantType::Null);
|
|
|
+ type = VariantType::Boolean;
|
|
|
+ content.asBoolean = value;
|
|
|
+ }
|
|
|
|
|
|
- case VariantType::RawString:
|
|
|
- return visit.visit(RawString(content_.asStringNode->data,
|
|
|
- content_.asStringNode->length));
|
|
|
+ void setRawString(StringNode* s) {
|
|
|
+ ARDUINOJSON_ASSERT(type == VariantType::Null);
|
|
|
+ ARDUINOJSON_ASSERT(s);
|
|
|
+ type = VariantType::RawString;
|
|
|
+ content.asStringNode = s;
|
|
|
+ }
|
|
|
|
|
|
- case VariantType::Int32:
|
|
|
- return visit.visit(static_cast<JsonInteger>(content_.asInt32));
|
|
|
+ template <typename TAdaptedString>
|
|
|
+ void setTinyString(const TAdaptedString& s) {
|
|
|
+ ARDUINOJSON_ASSERT(type == VariantType::Null);
|
|
|
+ ARDUINOJSON_ASSERT(s.size() <= tinyStringMaxLength);
|
|
|
|
|
|
- case VariantType::Uint32:
|
|
|
- return visit.visit(static_cast<JsonUInt>(content_.asUint32));
|
|
|
+ type = VariantType::TinyString;
|
|
|
|
|
|
-#if ARDUINOJSON_USE_LONG_LONG
|
|
|
- case VariantType::Int64:
|
|
|
- return visit.visit(eightByteValue->asInt64);
|
|
|
+ auto n = uint8_t(s.size());
|
|
|
+ for (uint8_t i = 0; i < n; i++) {
|
|
|
+ char c = s[i];
|
|
|
+ ARDUINOJSON_ASSERT(c != 0); // no NUL in tiny string
|
|
|
+ content.asTinyString[i] = c;
|
|
|
+ }
|
|
|
|
|
|
- case VariantType::Uint64:
|
|
|
- return visit.visit(eightByteValue->asUint64);
|
|
|
-#endif
|
|
|
+ content.asTinyString[n] = 0;
|
|
|
+ }
|
|
|
|
|
|
- case VariantType::Boolean:
|
|
|
- return visit.visit(content_.asBoolean != 0);
|
|
|
+ void setLongString(StringNode* s) {
|
|
|
+ ARDUINOJSON_ASSERT(type == VariantType::Null);
|
|
|
+ ARDUINOJSON_ASSERT(s);
|
|
|
+ type = VariantType::LongString;
|
|
|
+ content.asStringNode = s;
|
|
|
+ }
|
|
|
|
|
|
- default:
|
|
|
- return visit.visit(nullptr);
|
|
|
- }
|
|
|
+ CollectionData* toArray() {
|
|
|
+ ARDUINOJSON_ASSERT(type == VariantType::Null);
|
|
|
+ type = VariantType::Array;
|
|
|
+ return new (&content.asCollection) CollectionData();
|
|
|
+ }
|
|
|
+
|
|
|
+ CollectionData* toObject() {
|
|
|
+ ARDUINOJSON_ASSERT(type == VariantType::Null);
|
|
|
+ type = VariantType::Object;
|
|
|
+ return new (&content.asCollection) CollectionData();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// HACK: large functions are implemented in static function to give opportunity
|
|
|
+// to the compiler to optimize the `this` pointer away.
|
|
|
+class VariantImpl {
|
|
|
+ public:
|
|
|
+ VariantImpl() : data_(nullptr), resources_(nullptr) {}
|
|
|
+
|
|
|
+ VariantImpl(VariantData* data, ResourceManager* resources)
|
|
|
+ : data_(data), resources_(resources) {}
|
|
|
+
|
|
|
+ VariantData* getData() const {
|
|
|
+ return data_;
|
|
|
+ }
|
|
|
+
|
|
|
+ ResourceManager* getResourceManager() const {
|
|
|
+ return resources_;
|
|
|
}
|
|
|
|
|
|
template <typename TVisitor>
|
|
|
- static typename TVisitor::result_type accept(VariantData* var,
|
|
|
- ResourceManager* resources,
|
|
|
- TVisitor& visit) {
|
|
|
- if (var != 0)
|
|
|
- return var->accept(visit, resources);
|
|
|
- else
|
|
|
- return visit.visit(nullptr);
|
|
|
+ typename TVisitor::result_type accept(TVisitor& visit) {
|
|
|
+ return accept(visit, data_, resources_);
|
|
|
}
|
|
|
|
|
|
- VariantData* addElement(ResourceManager* resources) {
|
|
|
- auto array = isNull() ? toArray(resources) : asArray(resources);
|
|
|
- return array.addElement();
|
|
|
+ template <typename TVisitor>
|
|
|
+ static typename TVisitor::result_type accept(TVisitor&, VariantData*,
|
|
|
+ ResourceManager*);
|
|
|
+
|
|
|
+ VariantData* addElement() {
|
|
|
+ return addElement(data_, resources_);
|
|
|
}
|
|
|
|
|
|
- static VariantData* addElement(VariantData* var, ResourceManager* resources) {
|
|
|
- if (!var)
|
|
|
+ static VariantData* addElement(VariantData* data,
|
|
|
+ ResourceManager* resources) {
|
|
|
+ if (!data)
|
|
|
return nullptr;
|
|
|
- return var->addElement(resources);
|
|
|
+ auto array = data->type == VariantType::Null ? toArray(data, resources)
|
|
|
+ : asArray(data, resources);
|
|
|
+ return array.addElement();
|
|
|
}
|
|
|
|
|
|
template <typename T>
|
|
|
- bool addValue(const T& value, ResourceManager* resources) {
|
|
|
- auto array = isNull() ? toArray(resources) : asArray(resources);
|
|
|
- return array.addValue(value);
|
|
|
+ bool addValue(const T& value) {
|
|
|
+ return addValue(value, data_, resources_);
|
|
|
}
|
|
|
|
|
|
template <typename T>
|
|
|
- static bool addValue(VariantData* var, const T& value,
|
|
|
+ static bool addValue(const T& value, VariantData* data,
|
|
|
ResourceManager* resources) {
|
|
|
- if (!var)
|
|
|
+ if (!data)
|
|
|
return false;
|
|
|
- return var->addValue(value, resources);
|
|
|
+ auto array = data->type == VariantType::Null ? toArray(data, resources)
|
|
|
+ : asArray(data, resources);
|
|
|
+ return array.addValue(value);
|
|
|
+ }
|
|
|
+
|
|
|
+ bool asBoolean() const {
|
|
|
+ return asBoolean(data_, resources_);
|
|
|
}
|
|
|
|
|
|
- bool asBoolean(const ResourceManager* resources) const {
|
|
|
+ static bool asBoolean(VariantData* data, ResourceManager* resources) {
|
|
|
+ if (!data)
|
|
|
+ return false;
|
|
|
+
|
|
|
#if ARDUINOJSON_USE_8_BYTE_POOL
|
|
|
- auto eightByteValue = getEightByte(resources);
|
|
|
-#else
|
|
|
- (void)resources; // silence warning
|
|
|
+ auto eightByteValue = getEightByte(data, resources);
|
|
|
#endif
|
|
|
- switch (type_) {
|
|
|
+ switch (data->type) {
|
|
|
case VariantType::Boolean:
|
|
|
- return content_.asBoolean;
|
|
|
+ return data->content.asBoolean;
|
|
|
case VariantType::Uint32:
|
|
|
case VariantType::Int32:
|
|
|
- return content_.asUint32 != 0;
|
|
|
+ return data->content.asUint32 != 0;
|
|
|
case VariantType::Float:
|
|
|
- return content_.asFloat != 0;
|
|
|
+ return data->content.asFloat != 0;
|
|
|
#if ARDUINOJSON_USE_DOUBLE
|
|
|
case VariantType::Double:
|
|
|
return eightByteValue->asDouble != 0;
|
|
|
@@ -171,37 +224,44 @@ class VariantData {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- ArrayImpl asArray(ResourceManager* resources) {
|
|
|
- return ArrayImpl(isArray() ? &content_.asCollection : nullptr, resources);
|
|
|
+ ArrayImpl asArray() {
|
|
|
+ return asArray(data_, resources_);
|
|
|
}
|
|
|
|
|
|
- static ArrayImpl asArray(VariantData* var, ResourceManager* resources) {
|
|
|
- return ArrayImpl(
|
|
|
- var && var->isArray() ? &var->content_.asCollection : nullptr,
|
|
|
- resources);
|
|
|
+ static ArrayImpl asArray(VariantData* data, ResourceManager* resources) {
|
|
|
+ return ArrayImpl(data && data->type == VariantType::Array
|
|
|
+ ? &data->content.asCollection
|
|
|
+ : nullptr,
|
|
|
+ resources);
|
|
|
}
|
|
|
|
|
|
- CollectionImpl asCollection(ResourceManager* resources) {
|
|
|
- return CollectionImpl(isCollection() ? &content_.asCollection : nullptr,
|
|
|
- resources);
|
|
|
+ CollectionImpl asCollection() {
|
|
|
+ return CollectionImpl(
|
|
|
+ isCollection() ? &data_->content.asCollection : nullptr, resources_);
|
|
|
}
|
|
|
|
|
|
template <typename T>
|
|
|
- T asFloat(const ResourceManager* resources) const {
|
|
|
+ T asFloat() const {
|
|
|
+ return asFloat<T>(data_, resources_);
|
|
|
+ }
|
|
|
+
|
|
|
+ template <typename T>
|
|
|
+ static T asFloat(VariantData* data, ResourceManager* resources) {
|
|
|
+ if (!data)
|
|
|
+ return 0.0;
|
|
|
+
|
|
|
static_assert(is_floating_point<T>::value, "T must be a floating point");
|
|
|
#if ARDUINOJSON_USE_8_BYTE_POOL
|
|
|
- auto eightByteValue = getEightByte(resources);
|
|
|
-#else
|
|
|
- (void)resources; // silence warning
|
|
|
+ auto eightByteValue = getEightByte(data, resources);
|
|
|
#endif
|
|
|
const char* str = nullptr;
|
|
|
- switch (type_) {
|
|
|
+ switch (data->type) {
|
|
|
case VariantType::Boolean:
|
|
|
- return static_cast<T>(content_.asBoolean);
|
|
|
+ return static_cast<T>(data->content.asBoolean);
|
|
|
case VariantType::Uint32:
|
|
|
- return static_cast<T>(content_.asUint32);
|
|
|
+ return static_cast<T>(data->content.asUint32);
|
|
|
case VariantType::Int32:
|
|
|
- return static_cast<T>(content_.asInt32);
|
|
|
+ return static_cast<T>(data->content.asInt32);
|
|
|
#if ARDUINOJSON_USE_LONG_LONG
|
|
|
case VariantType::Uint64:
|
|
|
return static_cast<T>(eightByteValue->asUint64);
|
|
|
@@ -209,13 +269,13 @@ class VariantData {
|
|
|
return static_cast<T>(eightByteValue->asInt64);
|
|
|
#endif
|
|
|
case VariantType::TinyString:
|
|
|
- str = content_.asTinyString;
|
|
|
+ str = data->content.asTinyString;
|
|
|
break;
|
|
|
case VariantType::LongString:
|
|
|
- str = content_.asStringNode->data;
|
|
|
+ str = data->content.asStringNode->data;
|
|
|
break;
|
|
|
case VariantType::Float:
|
|
|
- return static_cast<T>(content_.asFloat);
|
|
|
+ return static_cast<T>(data->content.asFloat);
|
|
|
#if ARDUINOJSON_USE_DOUBLE
|
|
|
case VariantType::Double:
|
|
|
return static_cast<T>(eightByteValue->asDouble);
|
|
|
@@ -229,21 +289,27 @@ class VariantData {
|
|
|
}
|
|
|
|
|
|
template <typename T>
|
|
|
- T asIntegral(const ResourceManager* resources) const {
|
|
|
+ T asIntegral() const {
|
|
|
+ return asIntegral<T>(data_, resources_);
|
|
|
+ }
|
|
|
+
|
|
|
+ template <typename T>
|
|
|
+ static T asIntegral(VariantData* data, ResourceManager* resources) {
|
|
|
+ if (!data)
|
|
|
+ return 0;
|
|
|
+
|
|
|
static_assert(is_integral<T>::value, "T must be an integral type");
|
|
|
#if ARDUINOJSON_USE_8_BYTE_POOL
|
|
|
- auto eightByteValue = getEightByte(resources);
|
|
|
-#else
|
|
|
- (void)resources; // silence warning
|
|
|
+ auto eightByteValue = getEightByte(data, resources);
|
|
|
#endif
|
|
|
const char* str = nullptr;
|
|
|
- switch (type_) {
|
|
|
+ switch (data->type) {
|
|
|
case VariantType::Boolean:
|
|
|
- return content_.asBoolean;
|
|
|
+ return data->content.asBoolean;
|
|
|
case VariantType::Uint32:
|
|
|
- return convertNumber<T>(content_.asUint32);
|
|
|
+ return convertNumber<T>(data->content.asUint32);
|
|
|
case VariantType::Int32:
|
|
|
- return convertNumber<T>(content_.asInt32);
|
|
|
+ return convertNumber<T>(data->content.asInt32);
|
|
|
#if ARDUINOJSON_USE_LONG_LONG
|
|
|
case VariantType::Uint64:
|
|
|
return convertNumber<T>(eightByteValue->asUint64);
|
|
|
@@ -251,13 +317,13 @@ class VariantData {
|
|
|
return convertNumber<T>(eightByteValue->asInt64);
|
|
|
#endif
|
|
|
case VariantType::TinyString:
|
|
|
- str = content_.asTinyString;
|
|
|
+ str = data->content.asTinyString;
|
|
|
break;
|
|
|
case VariantType::LongString:
|
|
|
- str = content_.asStringNode->data;
|
|
|
+ str = data->content.asStringNode->data;
|
|
|
break;
|
|
|
case VariantType::Float:
|
|
|
- return convertNumber<T>(content_.asFloat);
|
|
|
+ return convertNumber<T>(data->content.asFloat);
|
|
|
#if ARDUINOJSON_USE_DOUBLE
|
|
|
case VariantType::Double:
|
|
|
return convertNumber<T>(eightByteValue->asDouble);
|
|
|
@@ -270,108 +336,81 @@ class VariantData {
|
|
|
return parseNumber<T>(str);
|
|
|
}
|
|
|
|
|
|
- ObjectImpl asObject(ResourceManager* resources) {
|
|
|
- return ObjectImpl(isObject() ? &content_.asCollection : nullptr, resources);
|
|
|
- }
|
|
|
-
|
|
|
- static ObjectImpl asObject(VariantData* var, ResourceManager* resources) {
|
|
|
- return ObjectImpl(
|
|
|
- var && var->isObject() ? &var->content_.asCollection : nullptr,
|
|
|
- resources);
|
|
|
- }
|
|
|
-
|
|
|
- JsonString asRawString() const {
|
|
|
- switch (type_) {
|
|
|
- case VariantType::RawString:
|
|
|
- return JsonString(content_.asStringNode->data,
|
|
|
- content_.asStringNode->length);
|
|
|
- default:
|
|
|
- return JsonString();
|
|
|
- }
|
|
|
+ ObjectImpl asObject() {
|
|
|
+ return asObject(data_, resources_);
|
|
|
}
|
|
|
|
|
|
- JsonString asString() const {
|
|
|
- switch (type_) {
|
|
|
- case VariantType::TinyString:
|
|
|
- return JsonString(content_.asTinyString);
|
|
|
- case VariantType::LongString:
|
|
|
- return JsonString(content_.asStringNode->data,
|
|
|
- content_.asStringNode->length);
|
|
|
- default:
|
|
|
- return JsonString();
|
|
|
- }
|
|
|
+ static ObjectImpl asObject(VariantData* data, ResourceManager* resources) {
|
|
|
+ return ObjectImpl(data && data->type == VariantType::Object
|
|
|
+ ? &data->content.asCollection
|
|
|
+ : nullptr,
|
|
|
+ resources);
|
|
|
}
|
|
|
|
|
|
#if ARDUINOJSON_USE_8_BYTE_POOL
|
|
|
- const EightByteValue* getEightByte(const ResourceManager* resources) const;
|
|
|
+ static const EightByteValue* getEightByte(VariantData*, ResourceManager*);
|
|
|
#endif
|
|
|
|
|
|
- VariantData* getElement(size_t index, ResourceManager* resources) {
|
|
|
- return asArray(resources).getElement(index);
|
|
|
- }
|
|
|
-
|
|
|
- static VariantData* getElement(VariantData* var, size_t index,
|
|
|
- ResourceManager* resources) {
|
|
|
- if (!var)
|
|
|
- return nullptr;
|
|
|
- return var->asArray(resources).getElement(index);
|
|
|
+ VariantData* getElement(size_t index) {
|
|
|
+ return asArray().getElement(index);
|
|
|
}
|
|
|
|
|
|
template <typename TAdaptedString>
|
|
|
- VariantData* getMember(TAdaptedString key, ResourceManager* resources) {
|
|
|
- return asObject(resources).getMember(key);
|
|
|
+ VariantData* getMember(TAdaptedString key) {
|
|
|
+ return asObject().getMember(key);
|
|
|
}
|
|
|
|
|
|
- template <typename TAdaptedString>
|
|
|
- static VariantData* getMember(VariantData* var, TAdaptedString key,
|
|
|
- ResourceManager* resources) {
|
|
|
- if (!var)
|
|
|
- return 0;
|
|
|
- return var->getMember(key, resources);
|
|
|
+ VariantData* getOrAddElement(size_t index) {
|
|
|
+ auto array = isNull() ? toArray() : asArray();
|
|
|
+ return array.getOrAddElement(index);
|
|
|
}
|
|
|
|
|
|
- VariantData* getOrAddElement(size_t index, ResourceManager* resources) {
|
|
|
- auto array = isNull() ? toArray(resources) : asArray(resources);
|
|
|
- return array.getOrAddElement(index);
|
|
|
+ template <typename TAdaptedString>
|
|
|
+ VariantData* getOrAddMember(TAdaptedString key) {
|
|
|
+ return getOrAddMember(key, data_, resources_);
|
|
|
}
|
|
|
|
|
|
template <typename TAdaptedString>
|
|
|
- VariantData* getOrAddMember(TAdaptedString key, ResourceManager* resources) {
|
|
|
+ static VariantData* getOrAddMember(TAdaptedString key, VariantData* data,
|
|
|
+ ResourceManager* resources) {
|
|
|
if (key.isNull())
|
|
|
return nullptr;
|
|
|
- auto obj = isNull() ? toObject(resources) : asObject(resources);
|
|
|
+ if (!data)
|
|
|
+ return nullptr;
|
|
|
+ auto obj = data->type == VariantType::Null ? toObject(data, resources)
|
|
|
+ : asObject(data, resources);
|
|
|
return obj.getOrAddMember(key);
|
|
|
}
|
|
|
|
|
|
bool isArray() const {
|
|
|
- return type_ == VariantType::Array;
|
|
|
- }
|
|
|
-
|
|
|
- bool isBoolean() const {
|
|
|
- return type_ == VariantType::Boolean;
|
|
|
+ return type() == VariantType::Array;
|
|
|
}
|
|
|
|
|
|
bool isCollection() const {
|
|
|
- return type_ & VariantTypeBits::CollectionMask;
|
|
|
+ return type() & VariantTypeBits::CollectionMask;
|
|
|
}
|
|
|
|
|
|
- bool isFloat() const {
|
|
|
- return type_ & VariantTypeBits::NumberBit;
|
|
|
+ template <typename T>
|
|
|
+ bool isInteger() const {
|
|
|
+ return isInteger<T>(data_, resources_);
|
|
|
}
|
|
|
|
|
|
template <typename T>
|
|
|
- bool isInteger(const ResourceManager* resources) const {
|
|
|
+ static bool isInteger(VariantData* data, ResourceManager* resources) {
|
|
|
+ if (!data)
|
|
|
+ return false;
|
|
|
+
|
|
|
#if ARDUINOJSON_USE_LONG_LONG
|
|
|
- auto eightByteValue = getEightByte(resources);
|
|
|
+ auto eightByteValue = getEightByte(data, resources);
|
|
|
#else
|
|
|
- (void)resources; // silence warning
|
|
|
+ (void)resources;
|
|
|
#endif
|
|
|
- switch (type_) {
|
|
|
+ switch (data->type) {
|
|
|
case VariantType::Uint32:
|
|
|
- return canConvertNumber<T>(content_.asUint32);
|
|
|
+ return canConvertNumber<T>(data->content.asUint32);
|
|
|
|
|
|
case VariantType::Int32:
|
|
|
- return canConvertNumber<T>(content_.asInt32);
|
|
|
+ return canConvertNumber<T>(data->content.asInt32);
|
|
|
|
|
|
#if ARDUINOJSON_USE_LONG_LONG
|
|
|
case VariantType::Uint64:
|
|
|
@@ -387,193 +426,139 @@ class VariantData {
|
|
|
}
|
|
|
|
|
|
bool isNull() const {
|
|
|
- return type_ == VariantType::Null;
|
|
|
- }
|
|
|
-
|
|
|
- static bool isNull(const VariantData* var) {
|
|
|
- if (!var)
|
|
|
- return true;
|
|
|
- return var->isNull();
|
|
|
+ return type() == VariantType::Null;
|
|
|
}
|
|
|
|
|
|
bool isObject() const {
|
|
|
- return type_ == VariantType::Object;
|
|
|
- }
|
|
|
-
|
|
|
- bool isString() const {
|
|
|
- return type_ == VariantType::LongString || type_ == VariantType::TinyString;
|
|
|
- }
|
|
|
-
|
|
|
- size_t nesting(ResourceManager* resources) {
|
|
|
- return asCollection(resources).nesting();
|
|
|
- }
|
|
|
-
|
|
|
- static size_t nesting(VariantData* var, ResourceManager* resources) {
|
|
|
- if (!var)
|
|
|
- return 0;
|
|
|
- return var->nesting(resources);
|
|
|
+ return type() == VariantType::Object;
|
|
|
}
|
|
|
|
|
|
- void removeElement(size_t index, ResourceManager* resources) {
|
|
|
- asArray(resources).removeElement(index);
|
|
|
+ size_t nesting() {
|
|
|
+ return asCollection().nesting();
|
|
|
}
|
|
|
|
|
|
- static void removeElement(VariantData* var, size_t index,
|
|
|
- ResourceManager* resources) {
|
|
|
- if (!var)
|
|
|
- return;
|
|
|
- var->removeElement(index, resources);
|
|
|
+ void removeElement(size_t index) {
|
|
|
+ asArray().removeElement(index);
|
|
|
}
|
|
|
|
|
|
template <typename TAdaptedString>
|
|
|
- void removeMember(TAdaptedString key, ResourceManager* resources) {
|
|
|
- asObject(resources).removeMember(key);
|
|
|
+ void removeMember(TAdaptedString key) {
|
|
|
+ asObject().removeMember(key);
|
|
|
}
|
|
|
|
|
|
- template <typename TAdaptedString>
|
|
|
- static void removeMember(VariantData* var, TAdaptedString key,
|
|
|
- ResourceManager* resources) {
|
|
|
- if (!var)
|
|
|
- return;
|
|
|
- var->removeMember(key, resources);
|
|
|
- }
|
|
|
-
|
|
|
- void reset() { // TODO: remove
|
|
|
- type_ = VariantType::Null;
|
|
|
+ bool setBoolean(bool value) {
|
|
|
+ if (!data_)
|
|
|
+ return false;
|
|
|
+ clear(data_, resources_);
|
|
|
+ data_->setBoolean(value);
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
- void setBoolean(bool value) {
|
|
|
- ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first
|
|
|
- type_ = VariantType::Boolean;
|
|
|
- content_.asBoolean = value;
|
|
|
+ template <typename T>
|
|
|
+ bool setFloat(T value) {
|
|
|
+ if (!data_)
|
|
|
+ return false;
|
|
|
+ clear(data_, resources_);
|
|
|
+ return setFloat(value, data_, resources_);
|
|
|
}
|
|
|
|
|
|
template <typename T>
|
|
|
- enable_if_t<sizeof(T) == 4, bool> setFloat(T value, ResourceManager*) {
|
|
|
- ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first
|
|
|
- type_ = VariantType::Float;
|
|
|
- content_.asFloat = value;
|
|
|
+ static enable_if_t<sizeof(T) == 4, bool> setFloat(T value, VariantData* data,
|
|
|
+ ResourceManager*) {
|
|
|
+ ARDUINOJSON_ASSERT(data != nullptr);
|
|
|
+ ARDUINOJSON_ASSERT(data->type == VariantType::Null);
|
|
|
+ data->type = VariantType::Float;
|
|
|
+ data->content.asFloat = value;
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
template <typename T>
|
|
|
- enable_if_t<sizeof(T) == 8, bool> setFloat(T value, ResourceManager*);
|
|
|
-
|
|
|
- template <typename T>
|
|
|
- enable_if_t<is_signed<T>::value, bool> setInteger(T value,
|
|
|
- ResourceManager* resources);
|
|
|
+ static enable_if_t<sizeof(T) == 8, bool> setFloat(T value, VariantData*,
|
|
|
+ ResourceManager*);
|
|
|
|
|
|
template <typename T>
|
|
|
- enable_if_t<is_unsigned<T>::value, bool> setInteger(
|
|
|
- T value, ResourceManager* resources);
|
|
|
-
|
|
|
- void setRawString(StringNode* s) {
|
|
|
- ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first
|
|
|
- ARDUINOJSON_ASSERT(s);
|
|
|
- type_ = VariantType::RawString;
|
|
|
- content_.asStringNode = s;
|
|
|
+ bool setInteger(T value) {
|
|
|
+ if (!data_)
|
|
|
+ return false;
|
|
|
+ clear(data_, resources_);
|
|
|
+ return setInteger(value, data_, resources_);
|
|
|
}
|
|
|
|
|
|
template <typename T>
|
|
|
- void setRawString(SerializedValue<T> value, ResourceManager* resources);
|
|
|
+ static enable_if_t<is_signed<T>::value, bool> setInteger(T value,
|
|
|
+ VariantData*,
|
|
|
+ ResourceManager*);
|
|
|
|
|
|
template <typename T>
|
|
|
- static void setRawString(VariantData* var, SerializedValue<T> value,
|
|
|
- ResourceManager* resources) {
|
|
|
- if (!var)
|
|
|
- return;
|
|
|
- var->clear(resources);
|
|
|
- var->setRawString(value, resources);
|
|
|
- }
|
|
|
+ static enable_if_t<is_unsigned<T>::value, bool> setInteger(T value,
|
|
|
+ VariantData*,
|
|
|
+ ResourceManager*);
|
|
|
|
|
|
- template <typename TAdaptedString>
|
|
|
- bool setString(TAdaptedString value, ResourceManager* resources);
|
|
|
+ template <typename T>
|
|
|
+ void setRawString(SerializedValue<T> value);
|
|
|
|
|
|
template <typename TAdaptedString>
|
|
|
- static void setString(VariantData* var, TAdaptedString value,
|
|
|
- ResourceManager* resources) {
|
|
|
- if (!var)
|
|
|
- return;
|
|
|
- var->clear(resources);
|
|
|
- var->setString(value, resources);
|
|
|
+ bool setString(TAdaptedString value) {
|
|
|
+ if (!data_)
|
|
|
+ return false;
|
|
|
+ clear(data_, resources_);
|
|
|
+ return setString(value, data_, resources_);
|
|
|
}
|
|
|
|
|
|
template <typename TAdaptedString>
|
|
|
- void setTinyString(const TAdaptedString& s) {
|
|
|
- ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first
|
|
|
- ARDUINOJSON_ASSERT(s.size() <= tinyStringMaxLength);
|
|
|
-
|
|
|
- type_ = VariantType::TinyString;
|
|
|
-
|
|
|
- auto n = uint8_t(s.size());
|
|
|
- for (uint8_t i = 0; i < n; i++) {
|
|
|
- char c = s[i];
|
|
|
- ARDUINOJSON_ASSERT(c != 0); // no NUL in tiny string
|
|
|
- content_.asTinyString[i] = c;
|
|
|
- }
|
|
|
-
|
|
|
- content_.asTinyString[n] = 0;
|
|
|
- }
|
|
|
+ static bool setString(TAdaptedString value, VariantData*, ResourceManager*);
|
|
|
|
|
|
- void setLongString(StringNode* s) {
|
|
|
- ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first
|
|
|
- ARDUINOJSON_ASSERT(s);
|
|
|
- type_ = VariantType::LongString;
|
|
|
- content_.asStringNode = s;
|
|
|
- }
|
|
|
-
|
|
|
- size_t size(ResourceManager* resources) {
|
|
|
+ size_t size() {
|
|
|
if (isObject())
|
|
|
- return asObject(resources).size();
|
|
|
+ return asObject().size();
|
|
|
|
|
|
if (isArray())
|
|
|
- return asArray(resources).size();
|
|
|
+ return asArray().size();
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
- static size_t size(VariantData* var, ResourceManager* resources) {
|
|
|
- return var != 0 ? var->size(resources) : 0;
|
|
|
- }
|
|
|
-
|
|
|
- ArrayImpl toArray(ResourceManager* resources) {
|
|
|
- ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first
|
|
|
- type_ = VariantType::Array;
|
|
|
- return ArrayImpl(new (&content_.asCollection) CollectionData(), resources);
|
|
|
+ ArrayImpl toArray() {
|
|
|
+ if (!data_)
|
|
|
+ return ArrayImpl();
|
|
|
+ clear(data_, resources_);
|
|
|
+ return toArray(data_, resources_);
|
|
|
}
|
|
|
|
|
|
- static ArrayImpl toArray(VariantData* var, ResourceManager* resources) {
|
|
|
- if (!var)
|
|
|
- return ArrayImpl(nullptr, resources);
|
|
|
- var->clear(resources);
|
|
|
- return var->toArray(resources);
|
|
|
+ static ArrayImpl toArray(VariantData* data, ResourceManager* resources) {
|
|
|
+ ARDUINOJSON_ASSERT(data != nullptr);
|
|
|
+ ARDUINOJSON_ASSERT(resources != nullptr);
|
|
|
+ return ArrayImpl(data->toArray(), resources);
|
|
|
}
|
|
|
|
|
|
- ObjectImpl toObject(ResourceManager* resources) {
|
|
|
- ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first
|
|
|
- type_ = VariantType::Object;
|
|
|
- return ObjectImpl(new (&content_.asCollection) CollectionData(), resources);
|
|
|
+ ObjectImpl toObject() {
|
|
|
+ if (!data_)
|
|
|
+ return ObjectImpl();
|
|
|
+ clear(data_, resources_);
|
|
|
+ return toObject(data_, resources_);
|
|
|
}
|
|
|
|
|
|
- static ObjectImpl toObject(VariantData* var, ResourceManager* resources) {
|
|
|
- if (!var)
|
|
|
- return ObjectImpl();
|
|
|
- var->clear(resources);
|
|
|
- return var->toObject(resources);
|
|
|
+ static ObjectImpl toObject(VariantData* data, ResourceManager* resources) {
|
|
|
+ ARDUINOJSON_ASSERT(data != nullptr);
|
|
|
+ ARDUINOJSON_ASSERT(resources != nullptr);
|
|
|
+ return ObjectImpl(data->toObject(), resources);
|
|
|
}
|
|
|
|
|
|
VariantType type() const {
|
|
|
- return type_;
|
|
|
+ return data_ ? data_->type : VariantType::Null;
|
|
|
}
|
|
|
|
|
|
// Release the resources used by this variant and set it to null.
|
|
|
- void clear(ResourceManager* resources);
|
|
|
-
|
|
|
- static void clear(VariantData* var, ResourceManager* resources) {
|
|
|
- if (!var)
|
|
|
- return;
|
|
|
- var->clear(resources);
|
|
|
+ void clear() {
|
|
|
+ if (data_)
|
|
|
+ clear(data_, resources_);
|
|
|
}
|
|
|
+
|
|
|
+ static void clear(VariantData*, ResourceManager*);
|
|
|
+
|
|
|
+ private:
|
|
|
+ VariantData* data_;
|
|
|
+ ResourceManager* resources_;
|
|
|
};
|
|
|
|
|
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|