forked from bblanchon/ArduinoJson
Extract VariantImpl
This commit is contained in:
@ -21,8 +21,8 @@ TEST_CASE("StringBuffer") {
|
|||||||
strcpy(ptr, "hi!");
|
strcpy(ptr, "hi!");
|
||||||
sb.save(&variant);
|
sb.save(&variant);
|
||||||
|
|
||||||
REQUIRE(variant.type() == VariantType::TinyString);
|
REQUIRE(variant.type == VariantType::TinyString);
|
||||||
REQUIRE(variant.asString(&resources) == "hi!");
|
REQUIRE(VariantImpl(&variant, &resources).asString() == "hi!");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Tiny string can't contain NUL") {
|
SECTION("Tiny string can't contain NUL") {
|
||||||
@ -30,9 +30,9 @@ TEST_CASE("StringBuffer") {
|
|||||||
memcpy(ptr, "a\0b", 3);
|
memcpy(ptr, "a\0b", 3);
|
||||||
sb.save(&variant);
|
sb.save(&variant);
|
||||||
|
|
||||||
REQUIRE(variant.type() == VariantType::OwnedString);
|
REQUIRE(variant.type == VariantType::OwnedString);
|
||||||
|
|
||||||
auto str = variant.asString(&resources);
|
auto str = VariantImpl(&variant, &resources).asString();
|
||||||
REQUIRE(str.size() == 3);
|
REQUIRE(str.size() == 3);
|
||||||
REQUIRE(str.c_str()[0] == 'a');
|
REQUIRE(str.c_str()[0] == 'a');
|
||||||
REQUIRE(str.c_str()[1] == 0);
|
REQUIRE(str.c_str()[1] == 0);
|
||||||
@ -44,7 +44,7 @@ TEST_CASE("StringBuffer") {
|
|||||||
strcpy(ptr, "alfa");
|
strcpy(ptr, "alfa");
|
||||||
sb.save(&variant);
|
sb.save(&variant);
|
||||||
|
|
||||||
REQUIRE(variant.type() == VariantType::OwnedString);
|
REQUIRE(variant.type == VariantType::OwnedString);
|
||||||
REQUIRE(variant.asString(&resources) == "alfa");
|
REQUIRE(VariantImpl(&variant, &resources).asString() == "alfa");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ TEST_CASE("StringBuilder") {
|
|||||||
REQUIRE(spyingAllocator.log() == AllocatorLog{
|
REQUIRE(spyingAllocator.log() == AllocatorLog{
|
||||||
Allocate(sizeofStringBuffer()),
|
Allocate(sizeofStringBuffer()),
|
||||||
});
|
});
|
||||||
REQUIRE(data.type() == VariantType::TinyString);
|
REQUIRE(data.type == VariantType::TinyString);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Tiny string") {
|
SECTION("Tiny string") {
|
||||||
@ -45,8 +45,8 @@ TEST_CASE("StringBuilder") {
|
|||||||
str.save(&data);
|
str.save(&data);
|
||||||
|
|
||||||
REQUIRE(resources.overflowed() == false);
|
REQUIRE(resources.overflowed() == false);
|
||||||
REQUIRE(data.type() == VariantType::TinyString);
|
REQUIRE(data.type == VariantType::TinyString);
|
||||||
REQUIRE(data.asString(&resources) == "url");
|
REQUIRE(VariantImpl(&data, &resources).asString() == "url");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Short string fits in first allocation") {
|
SECTION("Short string fits in first allocation") {
|
||||||
@ -134,10 +134,10 @@ TEST_CASE("StringBuilder::save() deduplicates strings") {
|
|||||||
auto s2 = saveString(builder, "world");
|
auto s2 = saveString(builder, "world");
|
||||||
auto s3 = saveString(builder, "hello");
|
auto s3 = saveString(builder, "hello");
|
||||||
|
|
||||||
REQUIRE(s1.asString(&resources) == "hello");
|
REQUIRE(VariantImpl(&s1, &resources).asString() == "hello");
|
||||||
REQUIRE(s2.asString(&resources) == "world");
|
REQUIRE(VariantImpl(&s2, &resources).asString() == "world");
|
||||||
REQUIRE(+s1.asString(&resources).c_str() ==
|
REQUIRE(+VariantImpl(&s1, &resources).asString().c_str() ==
|
||||||
+s3.asString(&resources).c_str()); // same address
|
+VariantImpl(&s3, &resources).asString().c_str()); // same address
|
||||||
|
|
||||||
REQUIRE(spy.log() ==
|
REQUIRE(spy.log() ==
|
||||||
AllocatorLog{
|
AllocatorLog{
|
||||||
@ -153,10 +153,11 @@ TEST_CASE("StringBuilder::save() deduplicates strings") {
|
|||||||
auto s1 = saveString(builder, "hello world");
|
auto s1 = saveString(builder, "hello world");
|
||||||
auto s2 = saveString(builder, "hello");
|
auto s2 = saveString(builder, "hello");
|
||||||
|
|
||||||
REQUIRE(s1.asString(&resources) == "hello world");
|
REQUIRE(VariantImpl(&s1, &resources).asString() == "hello world");
|
||||||
REQUIRE(s2.asString(&resources) == "hello");
|
REQUIRE(VariantImpl(&s2, &resources).asString() == "hello");
|
||||||
REQUIRE(+s2.asString(&resources).c_str() !=
|
REQUIRE(
|
||||||
+s1.asString(&resources).c_str()); // different address
|
+VariantImpl(&s1, &resources).asString().c_str() !=
|
||||||
|
+VariantImpl(&s2, &resources).asString().c_str()); // different address
|
||||||
|
|
||||||
REQUIRE(spy.log() ==
|
REQUIRE(spy.log() ==
|
||||||
AllocatorLog{
|
AllocatorLog{
|
||||||
@ -171,10 +172,11 @@ TEST_CASE("StringBuilder::save() deduplicates strings") {
|
|||||||
auto s1 = saveString(builder, "hello world");
|
auto s1 = saveString(builder, "hello world");
|
||||||
auto s2 = saveString(builder, "worl");
|
auto s2 = saveString(builder, "worl");
|
||||||
|
|
||||||
REQUIRE(s1.asString(&resources) == "hello world");
|
REQUIRE(VariantImpl(&s1, &resources).asString() == "hello world");
|
||||||
REQUIRE(s2.asString(&resources) == "worl");
|
REQUIRE(VariantImpl(&s2, &resources).asString() == "worl");
|
||||||
REQUIRE(s2.asString(&resources).c_str() !=
|
REQUIRE(
|
||||||
s1.asString(&resources).c_str()); // different address
|
VariantImpl(&s1, &resources).asString().c_str() !=
|
||||||
|
VariantImpl(&s2, &resources).asString().c_str()); // different address
|
||||||
|
|
||||||
REQUIRE(spy.log() ==
|
REQUIRE(spy.log() ==
|
||||||
AllocatorLog{
|
AllocatorLog{
|
||||||
|
@ -55,17 +55,12 @@ class ElementProxy : public VariantRefBase<ElementProxy<TUpstream>>,
|
|||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE VariantData* getData() const {
|
FORCE_INLINE VariantData* getData() const {
|
||||||
auto data = VariantAttorney::getData(upstream_);
|
return VariantAttorney::getVariantImpl(upstream_).getElement(index_);
|
||||||
auto resources = VariantAttorney::getResourceManager(upstream_);
|
|
||||||
return VariantData::asArray(data, resources).getElement(index_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VariantData* getOrCreateData() const {
|
VariantData* getOrCreateData() const {
|
||||||
auto data = VariantAttorney::getOrCreateData(upstream_);
|
return VariantAttorney::getOrCreateVariantImpl(upstream_).getOrAddElement(
|
||||||
if (!data)
|
index_);
|
||||||
return nullptr;
|
|
||||||
return data->getOrAddElement(
|
|
||||||
index_, VariantAttorney::getResourceManager(upstream_));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TUpstream upstream_;
|
TUpstream upstream_;
|
||||||
|
@ -24,7 +24,7 @@ class JsonArray : public detail::VariantOperators<JsonArray> {
|
|||||||
|
|
||||||
// INTERNAL USE ONLY
|
// INTERNAL USE ONLY
|
||||||
JsonArray(detail::VariantData* data, detail::ResourceManager* resources)
|
JsonArray(detail::VariantData* data, detail::ResourceManager* resources)
|
||||||
: impl_(detail::VariantData::asArray(data, resources)) {}
|
: impl_(detail::VariantImpl(data, resources).asArray()) {}
|
||||||
|
|
||||||
// INTERNAL USE ONLY
|
// INTERNAL USE ONLY
|
||||||
JsonArray(const detail::ArrayImpl& impl) : impl_(impl) {}
|
JsonArray(const detail::ArrayImpl& impl) : impl_(impl) {}
|
||||||
|
@ -38,7 +38,7 @@ class JsonArrayConst : public detail::VariantOperators<JsonArrayConst> {
|
|||||||
|
|
||||||
// INTERNAL USE ONLY
|
// INTERNAL USE ONLY
|
||||||
JsonArrayConst(detail::VariantData* data, detail::ResourceManager* resources)
|
JsonArrayConst(detail::VariantData* data, detail::ResourceManager* resources)
|
||||||
: impl_(detail::VariantData::asArray(data, resources)) {}
|
: impl_(detail::VariantImpl(data, resources).asArray()) {}
|
||||||
|
|
||||||
// INTERNAL USE ONLY
|
// INTERNAL USE ONLY
|
||||||
JsonArrayConst(const detail::ArrayImpl& impl) : impl_(impl) {}
|
JsonArrayConst(const detail::ArrayImpl& impl) : impl_(impl) {}
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
class VariantData;
|
struct VariantData;
|
||||||
class ResourceManager;
|
class ResourceManager;
|
||||||
|
|
||||||
class CollectionIterator {
|
class CollectionIterator {
|
||||||
|
@ -14,7 +14,7 @@ ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
|||||||
|
|
||||||
inline CollectionIterator::CollectionIterator(VariantData* slot, SlotId slotId)
|
inline CollectionIterator::CollectionIterator(VariantData* slot, SlotId slotId)
|
||||||
: slot_(slot), currentId_(slotId) {
|
: slot_(slot), currentId_(slotId) {
|
||||||
nextId_ = slot_ ? slot_->next() : NULL_SLOT;
|
nextId_ = slot_ ? slot_->next : NULL_SLOT;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void CollectionIterator::next(const ResourceManager* resources) {
|
inline void CollectionIterator::next(const ResourceManager* resources) {
|
||||||
@ -22,7 +22,7 @@ inline void CollectionIterator::next(const ResourceManager* resources) {
|
|||||||
slot_ = resources->getVariant(nextId_);
|
slot_ = resources->getVariant(nextId_);
|
||||||
currentId_ = nextId_;
|
currentId_ = nextId_;
|
||||||
if (slot_)
|
if (slot_)
|
||||||
nextId_ = slot_->next();
|
nextId_ = slot_->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline CollectionImpl::iterator CollectionImpl::createIterator() const {
|
inline CollectionImpl::iterator CollectionImpl::createIterator() const {
|
||||||
@ -37,7 +37,7 @@ inline void CollectionImpl::appendOne(Slot<VariantData> slot) {
|
|||||||
|
|
||||||
if (data_->tail != NULL_SLOT) {
|
if (data_->tail != NULL_SLOT) {
|
||||||
auto tail = resources_->getVariant(data_->tail);
|
auto tail = resources_->getVariant(data_->tail);
|
||||||
tail->setNext(slot.id());
|
tail->next = slot.id();
|
||||||
data_->tail = slot.id();
|
data_->tail = slot.id();
|
||||||
} else {
|
} else {
|
||||||
data_->head = slot.id();
|
data_->head = slot.id();
|
||||||
@ -50,11 +50,11 @@ inline void CollectionImpl::appendPair(Slot<VariantData> key,
|
|||||||
ARDUINOJSON_ASSERT(data_ != nullptr);
|
ARDUINOJSON_ASSERT(data_ != nullptr);
|
||||||
ARDUINOJSON_ASSERT(resources_ != nullptr);
|
ARDUINOJSON_ASSERT(resources_ != nullptr);
|
||||||
|
|
||||||
key->setNext(value.id());
|
key->next = value.id();
|
||||||
|
|
||||||
if (data_->tail != NULL_SLOT) {
|
if (data_->tail != NULL_SLOT) {
|
||||||
auto tail = resources_->getVariant(data_->tail);
|
auto tail = resources_->getVariant(data_->tail);
|
||||||
tail->setNext(key.id());
|
tail->next = key.id();
|
||||||
data_->tail = value.id();
|
data_->tail = value.id();
|
||||||
} else {
|
} else {
|
||||||
data_->head = key.id();
|
data_->head = key.id();
|
||||||
@ -69,7 +69,7 @@ inline void CollectionImpl::clear() {
|
|||||||
while (next != NULL_SLOT) {
|
while (next != NULL_SLOT) {
|
||||||
auto currId = next;
|
auto currId = next;
|
||||||
auto slot = resources_->getVariant(next);
|
auto slot = resources_->getVariant(next);
|
||||||
next = slot->next();
|
next = slot->next;
|
||||||
resources_->freeVariant({slot, currId});
|
resources_->freeVariant({slot, currId});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ inline Slot<VariantData> CollectionImpl::getPreviousSlot(
|
|||||||
if (currentSlot == target)
|
if (currentSlot == target)
|
||||||
break;
|
break;
|
||||||
prev = Slot<VariantData>(currentSlot, currentId);
|
prev = Slot<VariantData>(currentSlot, currentId);
|
||||||
currentId = currentSlot->next();
|
currentId = currentSlot->next;
|
||||||
}
|
}
|
||||||
return prev;
|
return prev;
|
||||||
}
|
}
|
||||||
@ -96,9 +96,9 @@ inline void CollectionImpl::removeOne(iterator it) {
|
|||||||
return;
|
return;
|
||||||
auto curr = it.slot_;
|
auto curr = it.slot_;
|
||||||
auto prev = getPreviousSlot(curr);
|
auto prev = getPreviousSlot(curr);
|
||||||
auto next = curr->next();
|
auto next = curr->next;
|
||||||
if (prev)
|
if (prev)
|
||||||
prev->setNext(next);
|
prev->next = next;
|
||||||
else
|
else
|
||||||
data_->head = next;
|
data_->head = next;
|
||||||
if (next == NULL_SLOT)
|
if (next == NULL_SLOT)
|
||||||
@ -116,7 +116,7 @@ inline void CollectionImpl::removePair(ObjectImpl::iterator it) {
|
|||||||
auto valueSlot = resources_->getVariant(valueId);
|
auto valueSlot = resources_->getVariant(valueId);
|
||||||
|
|
||||||
// remove value slot
|
// remove value slot
|
||||||
keySlot->setNext(valueSlot->next());
|
keySlot->next = valueSlot->next;
|
||||||
resources_->freeVariant({valueSlot, valueId});
|
resources_->freeVariant({valueSlot, valueId});
|
||||||
|
|
||||||
// remove key slot
|
// remove key slot
|
||||||
@ -128,7 +128,8 @@ inline size_t CollectionImpl::nesting() const {
|
|||||||
return 0;
|
return 0;
|
||||||
size_t maxChildNesting = 0;
|
size_t maxChildNesting = 0;
|
||||||
for (auto it = createIterator(); !it.done(); it.next(resources_)) {
|
for (auto it = createIterator(); !it.done(); it.next(resources_)) {
|
||||||
size_t childNesting = it->nesting(resources_);
|
VariantImpl variant(it.data(), resources_);
|
||||||
|
size_t childNesting = variant.nesting();
|
||||||
if (childNesting > maxChildNesting)
|
if (childNesting > maxChildNesting)
|
||||||
maxChildNesting = childNesting;
|
maxChildNesting = childNesting;
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ DeserializationError doDeserialize(TDestination&& dst, TReader reader,
|
|||||||
auto resources = VariantAttorney::getResourceManager(dst);
|
auto resources = VariantAttorney::getResourceManager(dst);
|
||||||
dst.clear();
|
dst.clear();
|
||||||
auto err = TDeserializer<TReader>(resources, reader)
|
auto err = TDeserializer<TReader>(resources, reader)
|
||||||
.parse(*data, options.filter, options.nestingLimit);
|
.parse(data, options.filter, options.nestingLimit);
|
||||||
shrinkJsonDocument(dst);
|
shrinkJsonDocument(dst);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
|||||||
// https://arduinojson.org/v7/api/jsondocument/clear/
|
// https://arduinojson.org/v7/api/jsondocument/clear/
|
||||||
void clear() {
|
void clear() {
|
||||||
resources_.clear();
|
resources_.clear();
|
||||||
data_.reset();
|
data_.type = detail::VariantType::Null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the root is of the specified type.
|
// Returns true if the root is of the specified type.
|
||||||
@ -120,13 +120,13 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
|||||||
// Returns the depth (nesting level) of the array.
|
// Returns the depth (nesting level) of the array.
|
||||||
// https://arduinojson.org/v7/api/jsondocument/nesting/
|
// https://arduinojson.org/v7/api/jsondocument/nesting/
|
||||||
size_t nesting() const {
|
size_t nesting() const {
|
||||||
return data_.nesting(&resources_);
|
return getVariantImpl().nesting();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the number of elements in the root array or object.
|
// Returns the number of elements in the root array or object.
|
||||||
// https://arduinojson.org/v7/api/jsondocument/size/
|
// https://arduinojson.org/v7/api/jsondocument/size/
|
||||||
size_t size() const {
|
size_t size() const {
|
||||||
return data_.size(&resources_);
|
return getVariantImpl().size();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copies the specified document.
|
// Copies the specified document.
|
||||||
@ -165,7 +165,7 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
|||||||
template <typename TChar>
|
template <typename TChar>
|
||||||
ARDUINOJSON_DEPRECATED("use doc[\"key\"].is<T>() instead")
|
ARDUINOJSON_DEPRECATED("use doc[\"key\"].is<T>() instead")
|
||||||
bool containsKey(TChar* key) const {
|
bool containsKey(TChar* key) const {
|
||||||
return data_.getMember(detail::adaptString(key), &resources_) != 0;
|
return getVariantImpl().getMember(detail::adaptString(key)) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// DEPRECATED: use obj[key].is<T>() instead
|
// DEPRECATED: use obj[key].is<T>() instead
|
||||||
@ -174,7 +174,7 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
|||||||
detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
|
detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
|
||||||
ARDUINOJSON_DEPRECATED("use doc[key].is<T>() instead")
|
ARDUINOJSON_DEPRECATED("use doc[key].is<T>() instead")
|
||||||
bool containsKey(const TString& key) const {
|
bool containsKey(const TString& key) const {
|
||||||
return data_.getMember(detail::adaptString(key), &resources_) != 0;
|
return getVariantImpl().getMember(detail::adaptString(key)) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// DEPRECATED: use obj[key].is<T>() instead
|
// DEPRECATED: use obj[key].is<T>() instead
|
||||||
@ -212,7 +212,7 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
|||||||
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(
|
return JsonVariantConst(
|
||||||
data_.getMember(detail::adaptString(key), &resources_), &resources_);
|
getVariantImpl().getMember(detail::adaptString(key)), &resources_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets a root object's member.
|
// Gets a root object's member.
|
||||||
@ -223,7 +223,7 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
|||||||
int> = 0>
|
int> = 0>
|
||||||
JsonVariantConst operator[](TChar* key) const {
|
JsonVariantConst operator[](TChar* key) const {
|
||||||
return JsonVariantConst(
|
return JsonVariantConst(
|
||||||
data_.getMember(detail::adaptString(key), &resources_), &resources_);
|
getVariantImpl().getMember(detail::adaptString(key)), &resources_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets or sets a root array's element.
|
// Gets or sets a root array's element.
|
||||||
@ -237,7 +237,7 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
|||||||
// Gets a root array's member.
|
// Gets a root array's member.
|
||||||
// https://arduinojson.org/v7/api/jsondocument/subscript/
|
// https://arduinojson.org/v7/api/jsondocument/subscript/
|
||||||
JsonVariantConst operator[](size_t index) const {
|
JsonVariantConst operator[](size_t index) const {
|
||||||
return JsonVariantConst(data_.getElement(index, &resources_), &resources_);
|
return JsonVariantConst(getVariantImpl().getElement(index), &resources_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets or sets a root object's member.
|
// Gets or sets a root object's member.
|
||||||
@ -267,14 +267,14 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
|||||||
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() {
|
JsonVariant add() {
|
||||||
return JsonVariant(data_.addElement(&resources_), &resources_);
|
return JsonVariant(getVariantImpl().addElement(), &resources_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Appends a value to the root array.
|
// Appends a value to the root array.
|
||||||
// https://arduinojson.org/v7/api/jsondocument/add/
|
// https://arduinojson.org/v7/api/jsondocument/add/
|
||||||
template <typename TValue>
|
template <typename TValue>
|
||||||
bool add(const TValue& value) {
|
bool add(const TValue& value) {
|
||||||
return data_.addValue(value, &resources_);
|
return getVariantImpl().addValue(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Appends a value to the root array.
|
// Appends a value to the root array.
|
||||||
@ -282,7 +282,7 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
|||||||
template <typename TChar,
|
template <typename TChar,
|
||||||
detail::enable_if_t<!detail::is_const<TChar>::value, int> = 0>
|
detail::enable_if_t<!detail::is_const<TChar>::value, int> = 0>
|
||||||
bool add(TChar* value) {
|
bool add(TChar* value) {
|
||||||
return data_.addValue(value, &resources_);
|
return getVariantImpl().addValue(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes an element of the root array.
|
// Removes an element of the root array.
|
||||||
@ -290,8 +290,7 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
|||||||
template <typename T,
|
template <typename T,
|
||||||
detail::enable_if_t<detail::is_integral<T>::value, int> = 0>
|
detail::enable_if_t<detail::is_integral<T>::value, int> = 0>
|
||||||
void remove(T index) {
|
void remove(T index) {
|
||||||
detail::VariantData::removeElement(getData(), size_t(index),
|
getVariantImpl().removeElement(size_t(index));
|
||||||
getResourceManager());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes a member of the root object.
|
// Removes a member of the root object.
|
||||||
@ -301,8 +300,7 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
|||||||
!detail::is_const<TChar>::value,
|
!detail::is_const<TChar>::value,
|
||||||
int> = 0>
|
int> = 0>
|
||||||
void remove(TChar* key) {
|
void remove(TChar* key) {
|
||||||
detail::VariantData::removeMember(getData(), detail::adaptString(key),
|
getVariantImpl().removeMember(detail::adaptString(key));
|
||||||
getResourceManager());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes a member of the root object.
|
// Removes a member of the root object.
|
||||||
@ -310,8 +308,7 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
|||||||
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) {
|
void remove(const TString& key) {
|
||||||
detail::VariantData::removeMember(getData(), detail::adaptString(key),
|
getVariantImpl().removeMember(detail::adaptString(key));
|
||||||
getResourceManager());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes a member of the root object or an element of the root array.
|
// Removes a member of the root object or an element of the root array.
|
||||||
@ -391,6 +388,10 @@ class JsonDocument : public detail::VariantOperators<const JsonDocument&> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
detail::VariantImpl getVariantImpl() const {
|
||||||
|
return detail::VariantImpl(&data_, &resources_);
|
||||||
|
}
|
||||||
|
|
||||||
JsonVariant getVariant() {
|
JsonVariant getVariant() {
|
||||||
return JsonVariant(&data_, &resources_);
|
return JsonVariant(&data_, &resources_);
|
||||||
}
|
}
|
||||||
|
@ -28,13 +28,13 @@ class JsonDeserializer {
|
|||||||
resources_(resources) {}
|
resources_(resources) {}
|
||||||
|
|
||||||
template <typename TFilter>
|
template <typename TFilter>
|
||||||
DeserializationError parse(VariantData& variant, TFilter filter,
|
DeserializationError parse(VariantData* variant, TFilter filter,
|
||||||
DeserializationOption::NestingLimit nestingLimit) {
|
DeserializationOption::NestingLimit nestingLimit) {
|
||||||
DeserializationError::Code err;
|
DeserializationError::Code err;
|
||||||
|
|
||||||
err = parseVariant(variant, filter, nestingLimit);
|
err = parseVariant(variant, filter, nestingLimit);
|
||||||
|
|
||||||
if (!err && latch_.last() != 0 && variant.isFloat()) {
|
if (!err && latch_.last() != 0 && variant->isFloat()) {
|
||||||
// We don't detect trailing characters earlier, so we need to check now
|
// We don't detect trailing characters earlier, so we need to check now
|
||||||
return DeserializationError::InvalidInput;
|
return DeserializationError::InvalidInput;
|
||||||
}
|
}
|
||||||
@ -60,7 +60,7 @@ class JsonDeserializer {
|
|||||||
|
|
||||||
template <typename TFilter>
|
template <typename TFilter>
|
||||||
DeserializationError::Code parseVariant(
|
DeserializationError::Code parseVariant(
|
||||||
VariantData& variant, TFilter filter,
|
VariantData* variant, TFilter filter,
|
||||||
DeserializationOption::NestingLimit nestingLimit) {
|
DeserializationOption::NestingLimit nestingLimit) {
|
||||||
DeserializationError::Code err;
|
DeserializationError::Code err;
|
||||||
|
|
||||||
@ -71,14 +71,15 @@ class JsonDeserializer {
|
|||||||
switch (current()) {
|
switch (current()) {
|
||||||
case '[':
|
case '[':
|
||||||
if (filter.allowArray())
|
if (filter.allowArray())
|
||||||
return parseArray(variant.toArray(resources_), filter, nestingLimit);
|
return parseArray(VariantImpl(variant, resources_).toArray(), filter,
|
||||||
|
nestingLimit);
|
||||||
else
|
else
|
||||||
return skipArray(nestingLimit);
|
return skipArray(nestingLimit);
|
||||||
|
|
||||||
case '{':
|
case '{':
|
||||||
if (filter.allowObject())
|
if (filter.allowObject())
|
||||||
return parseObject(variant.toObject(resources_), filter,
|
return parseObject(VariantImpl(variant, resources_).toObject(),
|
||||||
nestingLimit);
|
filter, nestingLimit);
|
||||||
else
|
else
|
||||||
return skipObject(nestingLimit);
|
return skipObject(nestingLimit);
|
||||||
|
|
||||||
@ -91,12 +92,12 @@ class JsonDeserializer {
|
|||||||
|
|
||||||
case 't':
|
case 't':
|
||||||
if (filter.allowValue())
|
if (filter.allowValue())
|
||||||
variant.setBoolean(true);
|
variant->setBoolean(true);
|
||||||
return skipKeyword("true");
|
return skipKeyword("true");
|
||||||
|
|
||||||
case 'f':
|
case 'f':
|
||||||
if (filter.allowValue())
|
if (filter.allowValue())
|
||||||
variant.setBoolean(false);
|
variant->setBoolean(false);
|
||||||
return skipKeyword("false");
|
return skipKeyword("false");
|
||||||
|
|
||||||
case 'n':
|
case 'n':
|
||||||
@ -178,7 +179,7 @@ class JsonDeserializer {
|
|||||||
return DeserializationError::NoMemory;
|
return DeserializationError::NoMemory;
|
||||||
|
|
||||||
// 1 - Parse value
|
// 1 - Parse value
|
||||||
err = parseVariant(*value, elementFilter, nestingLimit.decrement());
|
err = parseVariant(value, elementFilter, nestingLimit.decrement());
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
} else {
|
} else {
|
||||||
@ -282,11 +283,11 @@ class JsonDeserializer {
|
|||||||
|
|
||||||
stringBuilder_.save(keyVariant);
|
stringBuilder_.save(keyVariant);
|
||||||
} else {
|
} else {
|
||||||
member->clear(resources_);
|
VariantImpl(member, resources_).clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse value
|
// Parse value
|
||||||
err = parseVariant(*member, memberFilter, nestingLimit.decrement());
|
err = parseVariant(member, memberFilter, nestingLimit.decrement());
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
} else {
|
} else {
|
||||||
@ -380,7 +381,7 @@ class JsonDeserializer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError::Code parseStringValue(VariantData& variant) {
|
DeserializationError::Code parseStringValue(VariantData* variant) {
|
||||||
DeserializationError::Code err;
|
DeserializationError::Code err;
|
||||||
|
|
||||||
stringBuilder_.startString();
|
stringBuilder_.startString();
|
||||||
@ -389,7 +390,7 @@ class JsonDeserializer {
|
|||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
stringBuilder_.save(&variant);
|
stringBuilder_.save(variant);
|
||||||
|
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
}
|
}
|
||||||
@ -505,7 +506,7 @@ class JsonDeserializer {
|
|||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError::Code parseNumericValue(VariantData& result) {
|
DeserializationError::Code parseNumericValue(VariantData* result) {
|
||||||
uint8_t n = 0;
|
uint8_t n = 0;
|
||||||
|
|
||||||
char c = current();
|
char c = current();
|
||||||
@ -519,26 +520,28 @@ class JsonDeserializer {
|
|||||||
auto number = parseNumber(buffer_);
|
auto number = parseNumber(buffer_);
|
||||||
switch (number.type()) {
|
switch (number.type()) {
|
||||||
case NumberType::UnsignedInteger:
|
case NumberType::UnsignedInteger:
|
||||||
if (result.setInteger(number.asUnsignedInteger(), resources_))
|
if (VariantImpl(result, resources_)
|
||||||
|
.setInteger(number.asUnsignedInteger()))
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
else
|
else
|
||||||
return DeserializationError::NoMemory;
|
return DeserializationError::NoMemory;
|
||||||
|
|
||||||
case NumberType::SignedInteger:
|
case NumberType::SignedInteger:
|
||||||
if (result.setInteger(number.asSignedInteger(), resources_))
|
if (VariantImpl(result, resources_)
|
||||||
|
.setInteger(number.asSignedInteger()))
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
else
|
else
|
||||||
return DeserializationError::NoMemory;
|
return DeserializationError::NoMemory;
|
||||||
|
|
||||||
case NumberType::Float:
|
case NumberType::Float:
|
||||||
if (result.setFloat(number.asFloat(), resources_))
|
if (VariantImpl(result, resources_).setFloat(number.asFloat()))
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
else
|
else
|
||||||
return DeserializationError::NoMemory;
|
return DeserializationError::NoMemory;
|
||||||
|
|
||||||
#if ARDUINOJSON_USE_DOUBLE
|
#if ARDUINOJSON_USE_DOUBLE
|
||||||
case NumberType::Double:
|
case NumberType::Double:
|
||||||
if (result.setFloat(number.asDouble(), resources_))
|
if (VariantImpl(result, resources_).setFloat(number.asDouble()))
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
else
|
else
|
||||||
return DeserializationError::NoMemory;
|
return DeserializationError::NoMemory;
|
||||||
|
@ -27,9 +27,9 @@ class JsonSerializer : public VariantDataVisitor<size_t> {
|
|||||||
while (slotId != NULL_SLOT) {
|
while (slotId != NULL_SLOT) {
|
||||||
auto slot = resources_->getVariant(slotId);
|
auto slot = resources_->getVariant(slotId);
|
||||||
|
|
||||||
slot->accept(*this, resources_);
|
VariantImpl(slot, resources_).accept(*this);
|
||||||
|
|
||||||
slotId = slot->next();
|
slotId = slot->next;
|
||||||
|
|
||||||
if (slotId != NULL_SLOT)
|
if (slotId != NULL_SLOT)
|
||||||
write(',');
|
write(',');
|
||||||
@ -48,9 +48,9 @@ class JsonSerializer : public VariantDataVisitor<size_t> {
|
|||||||
|
|
||||||
while (slotId != NULL_SLOT) {
|
while (slotId != NULL_SLOT) {
|
||||||
auto slot = resources_->getVariant(slotId);
|
auto slot = resources_->getVariant(slotId);
|
||||||
slot->accept(*this, resources_);
|
VariantImpl(slot, resources_).accept(*this);
|
||||||
|
|
||||||
slotId = slot->next();
|
slotId = slot->next;
|
||||||
|
|
||||||
if (slotId != NULL_SLOT)
|
if (slotId != NULL_SLOT)
|
||||||
write(isKey ? ':' : ',');
|
write(isKey ? ':' : ',');
|
||||||
|
@ -26,7 +26,7 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
|
|||||||
nesting_++;
|
nesting_++;
|
||||||
while (!it.done()) {
|
while (!it.done()) {
|
||||||
indent();
|
indent();
|
||||||
it->accept(*this, base::resources_);
|
VariantImpl(it.data(), base::resources_).accept(*this);
|
||||||
|
|
||||||
it.next(base::resources_);
|
it.next(base::resources_);
|
||||||
base::write(it.done() ? "\r\n" : ",\r\n");
|
base::write(it.done() ? "\r\n" : ",\r\n");
|
||||||
@ -49,7 +49,7 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
|
|||||||
while (!it.done()) {
|
while (!it.done()) {
|
||||||
if (isKey)
|
if (isKey)
|
||||||
indent();
|
indent();
|
||||||
it->accept(*this, base::resources_);
|
VariantImpl(it.data(), base::resources_).accept(*this);
|
||||||
it.next(base::resources_);
|
it.next(base::resources_);
|
||||||
if (isKey)
|
if (isKey)
|
||||||
base::write(": ");
|
base::write(": ");
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
class VariantData;
|
struct VariantData;
|
||||||
class VariantWithId;
|
class VariantWithId;
|
||||||
|
|
||||||
class ResourceManager {
|
class ResourceManager {
|
||||||
|
@ -22,7 +22,7 @@ inline Slot<VariantData> ResourceManager::allocVariant() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline void ResourceManager::freeVariant(Slot<VariantData> slot) {
|
inline void ResourceManager::freeVariant(Slot<VariantData> slot) {
|
||||||
slot->clear(this);
|
VariantImpl(slot.ptr(), this).clear();
|
||||||
variantPools_.freeSlot(slot);
|
variantPools_.freeSlot(slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ struct Converter<MsgPackBinary> : private detail::VariantAttorney {
|
|||||||
if (!data)
|
if (!data)
|
||||||
return;
|
return;
|
||||||
auto resources = getResourceManager(dst);
|
auto resources = getResourceManager(dst);
|
||||||
data->clear(resources);
|
detail::VariantImpl(data, resources).clear();
|
||||||
if (src.data()) {
|
if (src.data()) {
|
||||||
size_t headerSize = src.size() >= 0x10000 ? 5
|
size_t headerSize = src.size() >= 0x10000 ? 5
|
||||||
: src.size() >= 0x100 ? 3
|
: src.size() >= 0x100 ? 3
|
||||||
@ -66,10 +66,8 @@ struct Converter<MsgPackBinary> : private detail::VariantAttorney {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static MsgPackBinary fromJson(JsonVariantConst src) {
|
static MsgPackBinary fromJson(JsonVariantConst src) {
|
||||||
auto data = getData(src);
|
auto variant = VariantAttorney::getVariantImpl(src);
|
||||||
if (!data)
|
auto rawstr = variant.asRawString();
|
||||||
return {};
|
|
||||||
auto rawstr = data->asRawString();
|
|
||||||
auto p = reinterpret_cast<const uint8_t*>(rawstr.c_str());
|
auto p = reinterpret_cast<const uint8_t*>(rawstr.c_str());
|
||||||
auto n = rawstr.size();
|
auto n = rawstr.size();
|
||||||
if (n >= 2 && p[0] == 0xc4) { // bin 8
|
if (n >= 2 && p[0] == 0xc4) { // bin 8
|
||||||
|
@ -24,10 +24,10 @@ class MsgPackDeserializer {
|
|||||||
foundSomething_(false) {}
|
foundSomething_(false) {}
|
||||||
|
|
||||||
template <typename TFilter>
|
template <typename TFilter>
|
||||||
DeserializationError parse(VariantData& variant, TFilter filter,
|
DeserializationError parse(VariantData* variant, TFilter filter,
|
||||||
DeserializationOption::NestingLimit nestingLimit) {
|
DeserializationOption::NestingLimit nestingLimit) {
|
||||||
DeserializationError::Code err;
|
DeserializationError::Code err;
|
||||||
err = parseVariant(&variant, filter, nestingLimit);
|
err = parseVariant(variant, filter, nestingLimit);
|
||||||
return foundSomething_ ? err : DeserializationError::EmptyInput;
|
return foundSomething_ ? err : DeserializationError::EmptyInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,7 +91,7 @@ class MsgPackDeserializer {
|
|||||||
|
|
||||||
if (code <= 0x7f || code >= 0xe0) { // fixint
|
if (code <= 0x7f || code >= 0xe0) { // fixint
|
||||||
if (allowValue)
|
if (allowValue)
|
||||||
variant->setInteger(static_cast<int8_t>(code), resources_);
|
VariantImpl(variant, resources_).setInteger(static_cast<int8_t>(code));
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,14 +231,14 @@ class MsgPackDeserializer {
|
|||||||
if (isSigned) {
|
if (isSigned) {
|
||||||
auto truncatedValue = static_cast<JsonInteger>(signedValue);
|
auto truncatedValue = static_cast<JsonInteger>(signedValue);
|
||||||
if (truncatedValue == signedValue) {
|
if (truncatedValue == signedValue) {
|
||||||
if (!variant->setInteger(truncatedValue, resources_))
|
if (!VariantImpl(variant, resources_).setInteger(truncatedValue))
|
||||||
return DeserializationError::NoMemory;
|
return DeserializationError::NoMemory;
|
||||||
}
|
}
|
||||||
// else set null on overflow
|
// else set null on overflow
|
||||||
} else {
|
} else {
|
||||||
auto truncatedValue = static_cast<JsonUInt>(unsignedValue);
|
auto truncatedValue = static_cast<JsonUInt>(unsignedValue);
|
||||||
if (truncatedValue == unsignedValue)
|
if (truncatedValue == unsignedValue)
|
||||||
if (!variant->setInteger(truncatedValue, resources_))
|
if (!VariantImpl(variant, resources_).setInteger(truncatedValue))
|
||||||
return DeserializationError::NoMemory;
|
return DeserializationError::NoMemory;
|
||||||
// else set null on overflow
|
// else set null on overflow
|
||||||
}
|
}
|
||||||
@ -257,7 +257,7 @@ class MsgPackDeserializer {
|
|||||||
return err;
|
return err;
|
||||||
|
|
||||||
fixEndianness(value);
|
fixEndianness(value);
|
||||||
variant->setFloat(value, resources_);
|
VariantImpl(variant, resources_).setFloat(value);
|
||||||
|
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
}
|
}
|
||||||
@ -273,7 +273,7 @@ class MsgPackDeserializer {
|
|||||||
return err;
|
return err;
|
||||||
|
|
||||||
fixEndianness(value);
|
fixEndianness(value);
|
||||||
if (variant->setFloat(value, resources_))
|
if (VariantImpl(variant, resources_).setFloat(value))
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
else
|
else
|
||||||
return DeserializationError::NoMemory;
|
return DeserializationError::NoMemory;
|
||||||
@ -293,7 +293,7 @@ class MsgPackDeserializer {
|
|||||||
|
|
||||||
doubleToFloat(i, o);
|
doubleToFloat(i, o);
|
||||||
fixEndianness(value);
|
fixEndianness(value);
|
||||||
variant->setFloat(value, resources_);
|
VariantImpl(variant, resources_).setFloat(value);
|
||||||
|
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
}
|
}
|
||||||
@ -352,7 +352,7 @@ class MsgPackDeserializer {
|
|||||||
ArrayImpl array;
|
ArrayImpl array;
|
||||||
if (allowArray) {
|
if (allowArray) {
|
||||||
ARDUINOJSON_ASSERT(variant != 0);
|
ARDUINOJSON_ASSERT(variant != 0);
|
||||||
array = variant->toArray(resources_);
|
array = VariantImpl(variant, resources_).toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
TFilter elementFilter = filter[0U];
|
TFilter elementFilter = filter[0U];
|
||||||
@ -388,7 +388,7 @@ class MsgPackDeserializer {
|
|||||||
ObjectImpl object;
|
ObjectImpl object;
|
||||||
if (filter.allowObject()) {
|
if (filter.allowObject()) {
|
||||||
ARDUINOJSON_ASSERT(variant != 0);
|
ARDUINOJSON_ASSERT(variant != 0);
|
||||||
object = variant->toObject(resources_);
|
object = VariantImpl(variant, resources_).toObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; n; --n) {
|
for (; n; --n) {
|
||||||
|
@ -31,11 +31,11 @@ class MsgPackExtension {
|
|||||||
template <>
|
template <>
|
||||||
struct Converter<MsgPackExtension> : private detail::VariantAttorney {
|
struct Converter<MsgPackExtension> : private detail::VariantAttorney {
|
||||||
static void toJson(MsgPackExtension src, JsonVariant dst) {
|
static void toJson(MsgPackExtension src, JsonVariant dst) {
|
||||||
auto data = VariantAttorney::getData(dst);
|
auto data = getData(dst);
|
||||||
if (!data)
|
if (!data)
|
||||||
return;
|
return;
|
||||||
auto resources = getResourceManager(dst);
|
auto resources = getResourceManager(dst);
|
||||||
data->clear(resources);
|
detail::VariantImpl(data, resources).clear();
|
||||||
if (src.data()) {
|
if (src.data()) {
|
||||||
uint8_t format, sizeBytes;
|
uint8_t format, sizeBytes;
|
||||||
if (src.size() >= 0x10000) {
|
if (src.size() >= 0x10000) {
|
||||||
@ -80,10 +80,8 @@ struct Converter<MsgPackExtension> : private detail::VariantAttorney {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static MsgPackExtension fromJson(JsonVariantConst src) {
|
static MsgPackExtension fromJson(JsonVariantConst src) {
|
||||||
auto data = getData(src);
|
auto variant = VariantAttorney::getVariantImpl(src);
|
||||||
if (!data)
|
auto rawstr = variant.asRawString();
|
||||||
return {};
|
|
||||||
auto rawstr = data->asRawString();
|
|
||||||
if (rawstr.size() == 0)
|
if (rawstr.size() == 0)
|
||||||
return {};
|
return {};
|
||||||
auto p = reinterpret_cast<const uint8_t*>(rawstr.c_str());
|
auto p = reinterpret_cast<const uint8_t*>(rawstr.c_str());
|
||||||
|
@ -62,8 +62,8 @@ class MsgPackSerializer : public VariantDataVisitor<size_t> {
|
|||||||
auto slotId = array.head();
|
auto slotId = array.head();
|
||||||
while (slotId != NULL_SLOT) {
|
while (slotId != NULL_SLOT) {
|
||||||
auto slot = resources_->getVariant(slotId);
|
auto slot = resources_->getVariant(slotId);
|
||||||
slot->accept(*this, resources_);
|
VariantImpl(slot, resources_).accept(*this);
|
||||||
slotId = slot->next();
|
slotId = slot->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
return bytesWritten();
|
return bytesWritten();
|
||||||
@ -84,8 +84,8 @@ class MsgPackSerializer : public VariantDataVisitor<size_t> {
|
|||||||
auto slotId = object.head();
|
auto slotId = object.head();
|
||||||
while (slotId != NULL_SLOT) {
|
while (slotId != NULL_SLOT) {
|
||||||
auto slot = resources_->getVariant(slotId);
|
auto slot = resources_->getVariant(slotId);
|
||||||
slot->accept(*this, resources_);
|
VariantImpl(slot, resources_).accept(*this);
|
||||||
slotId = slot->next();
|
slotId = slot->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
return bytesWritten();
|
return bytesWritten();
|
||||||
|
@ -27,7 +27,7 @@ class JsonObject : public detail::VariantOperators<JsonObject> {
|
|||||||
|
|
||||||
// INTERNAL USE ONLY
|
// INTERNAL USE ONLY
|
||||||
JsonObject(detail::VariantData* data, detail::ResourceManager* resource)
|
JsonObject(detail::VariantData* data, detail::ResourceManager* resource)
|
||||||
: impl_(detail::VariantData::asObject(data, resource)) {}
|
: impl_(detail::VariantImpl(data, resource).asObject()) {}
|
||||||
|
|
||||||
operator JsonVariant() const {
|
operator JsonVariant() const {
|
||||||
return JsonVariant(getData(), getResourceManager());
|
return JsonVariant(getData(), getResourceManager());
|
||||||
|
@ -23,7 +23,7 @@ class JsonObjectConst : public detail::VariantOperators<JsonObjectConst> {
|
|||||||
|
|
||||||
// INTERNAL USE ONLY
|
// INTERNAL USE ONLY
|
||||||
JsonObjectConst(detail::VariantData* data, detail::ResourceManager* resources)
|
JsonObjectConst(detail::VariantData* data, detail::ResourceManager* resources)
|
||||||
: impl_(detail::VariantData::asObject(data, resources)) {}
|
: impl_(detail::VariantImpl(data, resources).asObject()) {}
|
||||||
|
|
||||||
// INTERNAL USE ONLY
|
// INTERNAL USE ONLY
|
||||||
JsonObjectConst(const detail::ObjectImpl& impl) : impl_(impl) {}
|
JsonObjectConst(const detail::ObjectImpl& impl) : impl_(impl) {}
|
||||||
|
@ -18,7 +18,8 @@ class JsonPair {
|
|||||||
JsonPair(detail::ObjectImpl::iterator iterator,
|
JsonPair(detail::ObjectImpl::iterator iterator,
|
||||||
detail::ResourceManager* resources) {
|
detail::ResourceManager* resources) {
|
||||||
if (!iterator.done()) {
|
if (!iterator.done()) {
|
||||||
key_ = iterator->asString(resources);
|
detail::VariantImpl variant(iterator.data(), resources);
|
||||||
|
key_ = variant.asString();
|
||||||
iterator.next(resources);
|
iterator.next(resources);
|
||||||
value_ = JsonVariant(iterator.data(), resources);
|
value_ = JsonVariant(iterator.data(), resources);
|
||||||
}
|
}
|
||||||
@ -46,7 +47,8 @@ class JsonPairConst {
|
|||||||
JsonPairConst(detail::ObjectImpl::iterator iterator,
|
JsonPairConst(detail::ObjectImpl::iterator iterator,
|
||||||
detail::ResourceManager* resources) {
|
detail::ResourceManager* resources) {
|
||||||
if (!iterator.done()) {
|
if (!iterator.done()) {
|
||||||
key_ = iterator->asString(resources);
|
detail::VariantImpl variant(iterator.data(), resources);
|
||||||
|
key_ = variant.asString();
|
||||||
iterator.next(resources);
|
iterator.next(resources);
|
||||||
value_ = JsonVariantConst(iterator.data(), resources);
|
value_ = JsonVariantConst(iterator.data(), resources);
|
||||||
}
|
}
|
||||||
|
@ -56,17 +56,12 @@ class MemberProxy
|
|||||||
}
|
}
|
||||||
|
|
||||||
VariantData* getData() const {
|
VariantData* getData() const {
|
||||||
return VariantData::getMember(
|
return VariantAttorney::getVariantImpl(upstream_).getMember(key_);
|
||||||
VariantAttorney::getData(upstream_), key_,
|
|
||||||
VariantAttorney::getResourceManager(upstream_));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VariantData* getOrCreateData() const {
|
VariantData* getOrCreateData() const {
|
||||||
auto data = VariantAttorney::getOrCreateData(upstream_);
|
return VariantAttorney::getOrCreateVariantImpl(upstream_).getOrAddMember(
|
||||||
if (!data)
|
key_);
|
||||||
return nullptr;
|
|
||||||
return data->getOrAddMember(key_,
|
|
||||||
VariantAttorney::getResourceManager(upstream_));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
|
class VariantImpl;
|
||||||
|
|
||||||
class ObjectImpl : public CollectionImpl {
|
class ObjectImpl : public CollectionImpl {
|
||||||
public:
|
public:
|
||||||
ObjectImpl() {}
|
ObjectImpl() {}
|
||||||
|
@ -33,7 +33,8 @@ inline ObjectImpl::iterator ObjectImpl::findKey(TAdaptedString key) const {
|
|||||||
return iterator();
|
return iterator();
|
||||||
bool isKey = true;
|
bool isKey = true;
|
||||||
for (auto it = createIterator(); !it.done(); it.next(resources_)) {
|
for (auto it = createIterator(); !it.done(); it.next(resources_)) {
|
||||||
if (isKey && stringEquals(key, adaptString(it->asString(resources_))))
|
VariantImpl variant(it.data(), resources_);
|
||||||
|
if (isKey && stringEquals(key, adaptString(variant.asString())))
|
||||||
return it;
|
return it;
|
||||||
isKey = !isKey;
|
isKey = !isKey;
|
||||||
}
|
}
|
||||||
@ -59,7 +60,8 @@ inline VariantData* ObjectImpl::addMember(TAdaptedString key) {
|
|||||||
if (!valueSlot)
|
if (!valueSlot)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (!keySlot->setString(key, resources_))
|
VariantImpl keyImpl(keySlot.ptr(), resources_);
|
||||||
|
if (!keyImpl.setString(key))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
CollectionImpl::appendPair(keySlot, valueSlot);
|
CollectionImpl::appendPair(keySlot, valueSlot);
|
||||||
|
@ -14,7 +14,7 @@ size_t measure(ArduinoJson::JsonVariantConst source) {
|
|||||||
auto data = VariantAttorney::getData(source);
|
auto data = VariantAttorney::getData(source);
|
||||||
auto resources = VariantAttorney::getResourceManager(source);
|
auto resources = VariantAttorney::getResourceManager(source);
|
||||||
TSerializer<DummyWriter> serializer(dp, resources);
|
TSerializer<DummyWriter> serializer(dp, resources);
|
||||||
return VariantData::accept(data, resources, serializer);
|
return VariantImpl(data, resources).accept(serializer);
|
||||||
}
|
}
|
||||||
|
|
||||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||||
|
@ -13,7 +13,7 @@ size_t doSerialize(ArduinoJson::JsonVariantConst source, TWriter writer) {
|
|||||||
auto data = VariantAttorney::getData(source);
|
auto data = VariantAttorney::getData(source);
|
||||||
auto resources = VariantAttorney::getResourceManager(source);
|
auto resources = VariantAttorney::getResourceManager(source);
|
||||||
TSerializer<TWriter> serializer(writer, resources);
|
TSerializer<TWriter> serializer(writer, resources);
|
||||||
return VariantData::accept(data, resources, serializer);
|
return VariantImpl(data, resources).accept(serializer);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <template <typename> class TSerializer, typename TDestination>
|
template <template <typename> class TSerializer, typename TDestination>
|
||||||
|
@ -60,25 +60,18 @@ struct Converter<T, detail::enable_if_t<detail::is_integral<T>::value &&
|
|||||||
: private detail::VariantAttorney {
|
: private detail::VariantAttorney {
|
||||||
static bool toJson(T src, JsonVariant dst) {
|
static bool toJson(T src, JsonVariant dst) {
|
||||||
ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T);
|
ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T);
|
||||||
auto data = getData(dst);
|
auto variant = getVariantImpl(dst);
|
||||||
if (!data)
|
variant.clear();
|
||||||
return false;
|
return variant.setInteger(src);
|
||||||
auto resources = getResourceManager(dst);
|
|
||||||
data->clear(resources);
|
|
||||||
return data->setInteger(src, resources);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static T fromJson(JsonVariantConst src) {
|
static T fromJson(JsonVariantConst src) {
|
||||||
ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T);
|
ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T);
|
||||||
auto data = getData(src);
|
return getVariantImpl(src).template asIntegral<T>();
|
||||||
auto resources = getResourceManager(src);
|
|
||||||
return data ? data->template asIntegral<T>(resources) : T();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool checkJson(JsonVariantConst src) {
|
static bool checkJson(JsonVariantConst src) {
|
||||||
auto data = getData(src);
|
return getVariantImpl(src).template isInteger<T>();
|
||||||
auto resources = getResourceManager(src);
|
|
||||||
return data && data->template isInteger<T>(resources);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -90,40 +83,29 @@ struct Converter<T, detail::enable_if_t<detail::is_enum<T>::value>>
|
|||||||
}
|
}
|
||||||
|
|
||||||
static T fromJson(JsonVariantConst src) {
|
static T fromJson(JsonVariantConst src) {
|
||||||
auto data = getData(src);
|
return static_cast<T>(getVariantImpl(src).template asIntegral<int>());
|
||||||
auto resources = getResourceManager(src);
|
|
||||||
return data ? static_cast<T>(data->template asIntegral<int>(resources))
|
|
||||||
: T();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool checkJson(JsonVariantConst src) {
|
static bool checkJson(JsonVariantConst src) {
|
||||||
auto data = getData(src);
|
return getVariantImpl(src).template isInteger<int>();
|
||||||
auto resources = getResourceManager(src);
|
|
||||||
return data && data->template isInteger<int>(resources);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct Converter<bool> : private detail::VariantAttorney {
|
struct Converter<bool> : private detail::VariantAttorney {
|
||||||
static bool toJson(bool src, JsonVariant dst) {
|
static bool toJson(bool src, JsonVariant dst) {
|
||||||
auto data = getData(dst);
|
auto variant = getVariantImpl(dst);
|
||||||
if (!data)
|
variant.clear();
|
||||||
return false;
|
return variant.setBoolean(src);
|
||||||
auto resources = getResourceManager(dst);
|
|
||||||
data->clear(resources);
|
|
||||||
data->setBoolean(src);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool fromJson(JsonVariantConst src) {
|
static bool fromJson(JsonVariantConst src) {
|
||||||
auto data = getData(src);
|
return getVariantImpl(src).asBoolean();
|
||||||
auto resources = getResourceManager(src);
|
|
||||||
return data ? data->asBoolean(resources) : false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool checkJson(JsonVariantConst src) {
|
static bool checkJson(JsonVariantConst src) {
|
||||||
auto data = getData(src);
|
auto data = getData(src);
|
||||||
return data && data->isBoolean();
|
return data && data->type == detail::VariantType::Boolean;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -131,18 +113,13 @@ template <typename T>
|
|||||||
struct Converter<T, detail::enable_if_t<detail::is_floating_point<T>::value>>
|
struct Converter<T, detail::enable_if_t<detail::is_floating_point<T>::value>>
|
||||||
: private detail::VariantAttorney {
|
: private detail::VariantAttorney {
|
||||||
static bool toJson(T src, JsonVariant dst) {
|
static bool toJson(T src, JsonVariant dst) {
|
||||||
auto data = getData(dst);
|
auto variant = getVariantImpl(dst);
|
||||||
if (!data)
|
variant.clear();
|
||||||
return false;
|
return variant.setFloat(src);
|
||||||
auto resources = getResourceManager(dst);
|
|
||||||
data->clear(resources);
|
|
||||||
return data->setFloat(src, resources);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static T fromJson(JsonVariantConst src) {
|
static T fromJson(JsonVariantConst src) {
|
||||||
auto data = getData(src);
|
return getVariantImpl(src).template asFloat<T>();
|
||||||
auto resources = getResourceManager(src);
|
|
||||||
return data ? data->template asFloat<T>(resources) : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool checkJson(JsonVariantConst src) {
|
static bool checkJson(JsonVariantConst src) {
|
||||||
@ -154,13 +131,13 @@ struct Converter<T, detail::enable_if_t<detail::is_floating_point<T>::value>>
|
|||||||
template <>
|
template <>
|
||||||
struct Converter<const char*> : private detail::VariantAttorney {
|
struct Converter<const char*> : private detail::VariantAttorney {
|
||||||
static void toJson(const char* src, JsonVariant dst) {
|
static void toJson(const char* src, JsonVariant dst) {
|
||||||
detail::VariantData::setString(getData(dst), detail::adaptString(src),
|
auto variant = getVariantImpl(dst);
|
||||||
getResourceManager(dst));
|
variant.clear();
|
||||||
|
variant.setString(detail::adaptString(src));
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* fromJson(JsonVariantConst src) {
|
static const char* fromJson(JsonVariantConst src) {
|
||||||
auto data = getData(src);
|
return getVariantImpl(src).asString().c_str();
|
||||||
return data ? data->asString(getResourceManager(src)).c_str() : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool checkJson(JsonVariantConst src) {
|
static bool checkJson(JsonVariantConst src) {
|
||||||
@ -172,13 +149,13 @@ struct Converter<const char*> : private detail::VariantAttorney {
|
|||||||
template <>
|
template <>
|
||||||
struct Converter<JsonString> : private detail::VariantAttorney {
|
struct Converter<JsonString> : private detail::VariantAttorney {
|
||||||
static void toJson(JsonString src, JsonVariant dst) {
|
static void toJson(JsonString src, JsonVariant dst) {
|
||||||
detail::VariantData::setString(getData(dst), detail::adaptString(src),
|
auto variant = getVariantImpl(dst);
|
||||||
getResourceManager(dst));
|
variant.clear();
|
||||||
|
variant.setString(detail::adaptString(src));
|
||||||
}
|
}
|
||||||
|
|
||||||
static JsonString fromJson(JsonVariantConst src) {
|
static JsonString fromJson(JsonVariantConst src) {
|
||||||
auto data = getData(src);
|
return getVariantImpl(src).asString();
|
||||||
return data ? data->asString(getResourceManager(src)) : JsonString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool checkJson(JsonVariantConst src) {
|
static bool checkJson(JsonVariantConst src) {
|
||||||
@ -190,10 +167,9 @@ struct Converter<JsonString> : private detail::VariantAttorney {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
inline detail::enable_if_t<detail::IsString<T>::value> convertToJson(
|
inline detail::enable_if_t<detail::IsString<T>::value> convertToJson(
|
||||||
const T& src, JsonVariant dst) {
|
const T& src, JsonVariant dst) {
|
||||||
using namespace detail;
|
auto variant = detail::VariantAttorney::getVariantImpl(dst);
|
||||||
auto data = VariantAttorney::getData(dst);
|
variant.clear();
|
||||||
auto resources = VariantAttorney::getResourceManager(dst);
|
variant.setString(detail::adaptString(src));
|
||||||
detail::VariantData::setString(data, adaptString(src), resources);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SerializedValue<std::string>
|
// SerializedValue<std::string>
|
||||||
@ -202,22 +178,23 @@ inline detail::enable_if_t<detail::IsString<T>::value> convertToJson(
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
struct Converter<SerializedValue<T>> : private detail::VariantAttorney {
|
struct Converter<SerializedValue<T>> : private detail::VariantAttorney {
|
||||||
static void toJson(SerializedValue<T> src, JsonVariant dst) {
|
static void toJson(SerializedValue<T> src, JsonVariant dst) {
|
||||||
detail::VariantData::setRawString(getData(dst), src,
|
auto variant = getVariantImpl(dst);
|
||||||
getResourceManager(dst));
|
variant.clear();
|
||||||
|
variant.setRawString(src);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct Converter<detail::nullptr_t> : private detail::VariantAttorney {
|
struct Converter<detail::nullptr_t> : private detail::VariantAttorney {
|
||||||
static void toJson(detail::nullptr_t, JsonVariant dst) {
|
static void toJson(detail::nullptr_t, JsonVariant dst) {
|
||||||
detail::VariantData::clear(getData(dst), getResourceManager(dst));
|
getVariantImpl(dst).clear();
|
||||||
}
|
}
|
||||||
static detail::nullptr_t fromJson(JsonVariantConst) {
|
static detail::nullptr_t fromJson(JsonVariantConst) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
static bool checkJson(JsonVariantConst src) {
|
static bool checkJson(JsonVariantConst src) {
|
||||||
auto data = getData(src);
|
auto data = getData(src);
|
||||||
return data == 0 || data->isNull();
|
return data == 0 || data->type == detail::VariantType::Null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -263,7 +240,7 @@ inline void convertToJson(const ::Printable& src, JsonVariant dst) {
|
|||||||
auto data = detail::VariantAttorney::getData(dst);
|
auto data = detail::VariantAttorney::getData(dst);
|
||||||
if (!resources || !data)
|
if (!resources || !data)
|
||||||
return;
|
return;
|
||||||
data->clear(resources);
|
detail::VariantImpl(data, resources).clear();
|
||||||
detail::StringBuilderPrint print(resources);
|
detail::StringBuilderPrint print(resources);
|
||||||
src.printTo(print);
|
src.printTo(print);
|
||||||
if (print.overflowed())
|
if (print.overflowed())
|
||||||
@ -334,7 +311,7 @@ struct Converter<JsonArrayConst> : private detail::VariantAttorney {
|
|||||||
|
|
||||||
static bool checkJson(JsonVariantConst src) {
|
static bool checkJson(JsonVariantConst src) {
|
||||||
auto data = getData(src);
|
auto data = getData(src);
|
||||||
return data && data->isArray();
|
return data && data->type == detail::VariantType::Array;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -353,7 +330,7 @@ struct Converter<JsonArray> : private detail::VariantAttorney {
|
|||||||
|
|
||||||
static bool checkJson(JsonVariant src) {
|
static bool checkJson(JsonVariant src) {
|
||||||
auto data = getData(src);
|
auto data = getData(src);
|
||||||
return data && data->isArray();
|
return data && data->type == detail::VariantType::Array;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -372,7 +349,7 @@ struct Converter<JsonObjectConst> : private detail::VariantAttorney {
|
|||||||
|
|
||||||
static bool checkJson(JsonVariantConst src) {
|
static bool checkJson(JsonVariantConst src) {
|
||||||
auto data = getData(src);
|
auto data = getData(src);
|
||||||
return data && data->isObject();
|
return data && data->type == detail::VariantType::Object;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -391,7 +368,7 @@ struct Converter<JsonObject> : private detail::VariantAttorney {
|
|||||||
|
|
||||||
static bool checkJson(JsonVariant src) {
|
static bool checkJson(JsonVariant src) {
|
||||||
auto data = getData(src);
|
auto data = getData(src);
|
||||||
return data && data->isObject();
|
return data && data->type == detail::VariantType::Object;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -16,27 +16,29 @@ class JsonVariant : public detail::VariantRefBase<JsonVariant>,
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// Creates an unbound reference.
|
// Creates an unbound reference.
|
||||||
JsonVariant() : data_(0), resources_(0) {}
|
JsonVariant() {}
|
||||||
|
|
||||||
// INTERNAL USE ONLY
|
// INTERNAL USE ONLY
|
||||||
JsonVariant(detail::VariantData* data, detail::ResourceManager* resources)
|
JsonVariant(detail::VariantData* data, detail::ResourceManager* resources)
|
||||||
: data_(data), resources_(resources) {}
|
: impl_(data, resources) {}
|
||||||
|
|
||||||
|
// INTERNAL USE ONLY
|
||||||
|
JsonVariant(detail::VariantImpl impl) : impl_(impl) {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
detail::ResourceManager* getResourceManager() const {
|
detail::ResourceManager* getResourceManager() const {
|
||||||
return resources_;
|
return impl_.getResourceManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
detail::VariantData* getData() const {
|
detail::VariantData* getData() const {
|
||||||
return data_;
|
return impl_.getData();
|
||||||
}
|
}
|
||||||
|
|
||||||
detail::VariantData* getOrCreateData() const {
|
detail::VariantData* getOrCreateData() const {
|
||||||
return data_;
|
return impl_.getData();
|
||||||
}
|
}
|
||||||
|
|
||||||
detail::VariantData* data_;
|
mutable detail::VariantImpl impl_;
|
||||||
detail::ResourceManager* resources_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
@ -35,34 +35,34 @@ class JsonVariantConst : public detail::VariantTag,
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// Creates an unbound reference.
|
// Creates an unbound reference.
|
||||||
JsonVariantConst() : data_(nullptr), resources_(nullptr) {}
|
JsonVariantConst() {}
|
||||||
|
|
||||||
// INTERNAL USE ONLY
|
// INTERNAL USE ONLY
|
||||||
explicit JsonVariantConst(detail::VariantData* data,
|
explicit JsonVariantConst(detail::VariantData* data,
|
||||||
detail::ResourceManager* resources)
|
detail::ResourceManager* resources)
|
||||||
: data_(data), resources_(resources) {}
|
: impl_(data, resources) {}
|
||||||
|
|
||||||
// Returns true if the value is null or the reference is unbound.
|
// Returns true if the value is null or the reference is unbound.
|
||||||
// https://arduinojson.org/v7/api/jsonvariantconst/isnull/
|
// https://arduinojson.org/v7/api/jsonvariantconst/isnull/
|
||||||
bool isNull() const {
|
bool isNull() const {
|
||||||
return detail::VariantData::isNull(data_);
|
return impl_.isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the reference is unbound.
|
// Returns true if the reference is unbound.
|
||||||
bool isUnbound() const {
|
bool isUnbound() const {
|
||||||
return !data_;
|
return impl_.getData() == nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the depth (nesting level) of the value.
|
// Returns the depth (nesting level) of the value.
|
||||||
// https://arduinojson.org/v7/api/jsonvariantconst/nesting/
|
// https://arduinojson.org/v7/api/jsonvariantconst/nesting/
|
||||||
size_t nesting() const {
|
size_t nesting() const {
|
||||||
return detail::VariantData::nesting(data_, resources_);
|
return impl_.nesting();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the size of the array or object.
|
// Returns the size of the array or object.
|
||||||
// https://arduinojson.org/v7/api/jsonvariantconst/size/
|
// https://arduinojson.org/v7/api/jsonvariantconst/size/
|
||||||
size_t size() const {
|
size_t size() const {
|
||||||
return detail::VariantData::size(data_, resources_);
|
return impl_.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Casts the value to the specified type.
|
// Casts the value to the specified type.
|
||||||
@ -104,9 +104,8 @@ class JsonVariantConst : public detail::VariantTag,
|
|||||||
template <typename T,
|
template <typename T,
|
||||||
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(impl_.getElement(size_t(index)),
|
||||||
detail::VariantData::getElement(data_, size_t(index), resources_),
|
impl_.getResourceManager());
|
||||||
resources_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets object's member with specified key.
|
// Gets object's member with specified key.
|
||||||
@ -114,9 +113,8 @@ class JsonVariantConst : public detail::VariantTag,
|
|||||||
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::VariantData::getMember(
|
return JsonVariantConst(impl_.getMember(detail::adaptString(key)),
|
||||||
data_, detail::adaptString(key), resources_),
|
impl_.getResourceManager());
|
||||||
resources_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets object's member with specified key.
|
// Gets object's member with specified key.
|
||||||
@ -126,9 +124,8 @@ class JsonVariantConst : public detail::VariantTag,
|
|||||||
!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::VariantData::getMember(
|
return JsonVariantConst(impl_.getMember(detail::adaptString(key)),
|
||||||
data_, detail::adaptString(key), resources_),
|
impl_.getResourceManager());
|
||||||
resources_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets object's member with specified key or the array's element at the
|
// Gets object's member with specified key or the array's element at the
|
||||||
@ -149,8 +146,7 @@ class JsonVariantConst : public detail::VariantTag,
|
|||||||
detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
|
detail::enable_if_t<detail::IsString<TString>::value, int> = 0>
|
||||||
ARDUINOJSON_DEPRECATED("use var[key].is<T>() instead")
|
ARDUINOJSON_DEPRECATED("use var[key].is<T>() instead")
|
||||||
bool containsKey(const TString& key) const {
|
bool containsKey(const TString& key) const {
|
||||||
return detail::VariantData::getMember(getData(), detail::adaptString(key),
|
return impl_.getMember(detail::adaptString(key)) != 0;
|
||||||
resources_) != 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DEPRECATED: use obj["key"].is<T>() instead
|
// DEPRECATED: use obj["key"].is<T>() instead
|
||||||
@ -161,8 +157,7 @@ class JsonVariantConst : public detail::VariantTag,
|
|||||||
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::VariantData::getMember(getData(), detail::adaptString(key),
|
return impl_.getMember(detail::adaptString(key)) != 0;
|
||||||
resources_) != 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DEPRECATED: use obj[key].is<T>() instead
|
// DEPRECATED: use obj[key].is<T>() instead
|
||||||
@ -182,16 +177,15 @@ class JsonVariantConst : public detail::VariantTag,
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
detail::VariantData* getData() const {
|
detail::VariantData* getData() const {
|
||||||
return data_;
|
return impl_.getData();
|
||||||
}
|
}
|
||||||
|
|
||||||
detail::ResourceManager* getResourceManager() const {
|
detail::ResourceManager* getResourceManager() const {
|
||||||
return resources_;
|
return impl_.getResourceManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mutable detail::VariantData* data_;
|
mutable detail::VariantImpl impl_;
|
||||||
mutable detail::ResourceManager* resources_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
ARDUINOJSON_END_PUBLIC_NAMESPACE
|
||||||
|
@ -49,11 +49,9 @@ template <typename TVisitor>
|
|||||||
typename TVisitor::result_type accept(JsonVariantConst variant,
|
typename TVisitor::result_type accept(JsonVariantConst variant,
|
||||||
TVisitor& visit) {
|
TVisitor& visit) {
|
||||||
auto data = VariantAttorney::getData(variant);
|
auto data = VariantAttorney::getData(variant);
|
||||||
if (!data)
|
|
||||||
return visit.visit(nullptr);
|
|
||||||
auto resources = VariantAttorney::getResourceManager(variant);
|
auto resources = VariantAttorney::getResourceManager(variant);
|
||||||
VisitorAdapter<TVisitor> adapter(visit);
|
VisitorAdapter<TVisitor> adapter(visit);
|
||||||
return data->accept(adapter, resources);
|
return VariantImpl(data, resources).accept(adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||||
|
@ -26,6 +26,16 @@ class VariantAttorney {
|
|||||||
return client.getData();
|
return client.getData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename TClient>
|
||||||
|
static VariantImpl getVariantImpl(TClient& client) {
|
||||||
|
return VariantImpl(client.getData(), client.getResourceManager());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TClient>
|
||||||
|
static VariantImpl getOrCreateVariantImpl(TClient& client) {
|
||||||
|
return VariantImpl(client.getOrCreateData(), client.getResourceManager());
|
||||||
|
}
|
||||||
|
|
||||||
template <typename TClient>
|
template <typename TClient>
|
||||||
static VariantData* getOrCreateData(TClient& client) {
|
static VariantData* getOrCreateData(TClient& client) {
|
||||||
return client.getOrCreateData();
|
return client.getOrCreateData();
|
||||||
|
@ -27,12 +27,11 @@ static bool isTinyString(const T& s, size_t n) {
|
|||||||
return !containsNul;
|
return !containsNul;
|
||||||
}
|
}
|
||||||
|
|
||||||
class VariantData {
|
struct VariantData {
|
||||||
VariantContent content_; // must be first to allow cast from array to variant
|
VariantContent content; // must be first to allow cast from array to variant
|
||||||
VariantType type_;
|
VariantType type = VariantType::Null;
|
||||||
SlotId next_;
|
SlotId next = NULL_SLOT;
|
||||||
|
|
||||||
public:
|
|
||||||
// Placement new
|
// Placement new
|
||||||
static void* operator new(size_t, void* p) noexcept {
|
static void* operator new(size_t, void* p) noexcept {
|
||||||
return p;
|
return p;
|
||||||
@ -40,27 +39,79 @@ class VariantData {
|
|||||||
|
|
||||||
static void operator delete(void*, void*) noexcept {}
|
static void operator delete(void*, void*) noexcept {}
|
||||||
|
|
||||||
VariantData() : type_(VariantType::Null), next_(NULL_SLOT) {}
|
void setBoolean(bool value) {
|
||||||
|
ARDUINOJSON_ASSERT(type == VariantType::Null);
|
||||||
SlotId next() const {
|
type = VariantType::Boolean;
|
||||||
return next_;
|
content.asBoolean = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setNext(SlotId slot) {
|
template <typename TAdaptedString>
|
||||||
next_ = slot;
|
void setTinyString(const TAdaptedString& s) {
|
||||||
|
ARDUINOJSON_ASSERT(type == VariantType::Null);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setOwnedString(StringNode* s) {
|
||||||
|
ARDUINOJSON_ASSERT(type == VariantType::Null);
|
||||||
|
ARDUINOJSON_ASSERT(s);
|
||||||
|
type = VariantType::OwnedString;
|
||||||
|
content.asOwnedString = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setRawString(StringNode* s) {
|
||||||
|
ARDUINOJSON_ASSERT(type == VariantType::Null);
|
||||||
|
ARDUINOJSON_ASSERT(s);
|
||||||
|
type = VariantType::RawString;
|
||||||
|
content.asOwnedString = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isFloat() const {
|
||||||
|
return type & VariantTypeBits::NumberBit;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isString() const {
|
||||||
|
return type == VariantType::LinkedString ||
|
||||||
|
type == VariantType::OwnedString || type == VariantType::TinyString;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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>
|
template <typename TVisitor>
|
||||||
typename TVisitor::result_type accept(TVisitor& visit,
|
typename TVisitor::result_type accept(TVisitor& visit) {
|
||||||
ResourceManager* resources) {
|
if (!data_)
|
||||||
|
return visit.visit(nullptr);
|
||||||
|
|
||||||
#if ARDUINOJSON_USE_8_BYTE_POOL
|
#if ARDUINOJSON_USE_8_BYTE_POOL
|
||||||
auto eightByteValue = getEightByte(resources);
|
auto eightByteValue = getEightByte();
|
||||||
#else
|
|
||||||
(void)resources; // silence warning
|
|
||||||
#endif
|
#endif
|
||||||
switch (type_) {
|
switch (data_->type) {
|
||||||
case VariantType::Float:
|
case VariantType::Float:
|
||||||
return visit.visit(content_.asFloat);
|
return visit.visit(data_->content.asFloat);
|
||||||
|
|
||||||
#if ARDUINOJSON_USE_DOUBLE
|
#if ARDUINOJSON_USE_DOUBLE
|
||||||
case VariantType::Double:
|
case VariantType::Double:
|
||||||
@ -68,30 +119,30 @@ class VariantData {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
case VariantType::Array:
|
case VariantType::Array:
|
||||||
return visit.visit(asArray(resources));
|
return visit.visit(asArray());
|
||||||
|
|
||||||
case VariantType::Object:
|
case VariantType::Object:
|
||||||
return visit.visit(asObject(resources));
|
return visit.visit(asObject());
|
||||||
|
|
||||||
case VariantType::TinyString:
|
case VariantType::TinyString:
|
||||||
return visit.visit(JsonString(content_.asTinyString));
|
return visit.visit(JsonString(data_->content.asTinyString));
|
||||||
|
|
||||||
case VariantType::LinkedString:
|
case VariantType::LinkedString:
|
||||||
return visit.visit(JsonString(asLinkedString(resources), true));
|
return visit.visit(JsonString(asLinkedString(), true));
|
||||||
|
|
||||||
case VariantType::OwnedString:
|
case VariantType::OwnedString:
|
||||||
return visit.visit(JsonString(content_.asOwnedString->data,
|
return visit.visit(JsonString(data_->content.asOwnedString->data,
|
||||||
content_.asOwnedString->length));
|
data_->content.asOwnedString->length));
|
||||||
|
|
||||||
case VariantType::RawString:
|
case VariantType::RawString:
|
||||||
return visit.visit(RawString(content_.asOwnedString->data,
|
return visit.visit(RawString(data_->content.asOwnedString->data,
|
||||||
content_.asOwnedString->length));
|
data_->content.asOwnedString->length));
|
||||||
|
|
||||||
case VariantType::Int32:
|
case VariantType::Int32:
|
||||||
return visit.visit(static_cast<JsonInteger>(content_.asInt32));
|
return visit.visit(static_cast<JsonInteger>(data_->content.asInt32));
|
||||||
|
|
||||||
case VariantType::Uint32:
|
case VariantType::Uint32:
|
||||||
return visit.visit(static_cast<JsonUInt>(content_.asUint32));
|
return visit.visit(static_cast<JsonUInt>(data_->content.asUint32));
|
||||||
|
|
||||||
#if ARDUINOJSON_USE_LONG_LONG
|
#if ARDUINOJSON_USE_LONG_LONG
|
||||||
case VariantType::Int64:
|
case VariantType::Int64:
|
||||||
@ -102,62 +153,39 @@ class VariantData {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
case VariantType::Boolean:
|
case VariantType::Boolean:
|
||||||
return visit.visit(content_.asBoolean != 0);
|
return visit.visit(data_->content.asBoolean != 0);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return visit.visit(nullptr);
|
return visit.visit(nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TVisitor>
|
VariantData* addElement() {
|
||||||
static typename TVisitor::result_type accept(VariantData* var,
|
auto array = isNull() ? toArray() : asArray();
|
||||||
ResourceManager* resources,
|
|
||||||
TVisitor& visit) {
|
|
||||||
if (var != 0)
|
|
||||||
return var->accept(visit, resources);
|
|
||||||
else
|
|
||||||
return visit.visit(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
VariantData* addElement(ResourceManager* resources) {
|
|
||||||
auto array = isNull() ? toArray(resources) : asArray(resources);
|
|
||||||
return array.addElement();
|
return array.addElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
static VariantData* addElement(VariantData* var, ResourceManager* resources) {
|
|
||||||
if (!var)
|
|
||||||
return nullptr;
|
|
||||||
return var->addElement(resources);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool addValue(const T& value, ResourceManager* resources) {
|
bool addValue(const T& value) {
|
||||||
auto array = isNull() ? toArray(resources) : asArray(resources);
|
auto array = isNull() ? toArray() : asArray();
|
||||||
return array.addValue(value);
|
return array.addValue(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
bool asBoolean() const {
|
||||||
static bool addValue(VariantData* var, const T& value,
|
if (!data_)
|
||||||
ResourceManager* resources) {
|
|
||||||
if (!var)
|
|
||||||
return false;
|
return false;
|
||||||
return var->addValue(value, resources);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool asBoolean(const ResourceManager* resources) const {
|
|
||||||
#if ARDUINOJSON_USE_8_BYTE_POOL
|
#if ARDUINOJSON_USE_8_BYTE_POOL
|
||||||
auto eightByteValue = getEightByte(resources);
|
auto eightByteValue = getEightByte();
|
||||||
#else
|
|
||||||
(void)resources; // silence warning
|
|
||||||
#endif
|
#endif
|
||||||
switch (type_) {
|
switch (data_->type) {
|
||||||
case VariantType::Boolean:
|
case VariantType::Boolean:
|
||||||
return content_.asBoolean;
|
return data_->content.asBoolean;
|
||||||
case VariantType::Uint32:
|
case VariantType::Uint32:
|
||||||
case VariantType::Int32:
|
case VariantType::Int32:
|
||||||
return content_.asUint32 != 0;
|
return data_->content.asUint32 != 0;
|
||||||
case VariantType::Float:
|
case VariantType::Float:
|
||||||
return content_.asFloat != 0;
|
return data_->content.asFloat != 0;
|
||||||
#if ARDUINOJSON_USE_DOUBLE
|
#if ARDUINOJSON_USE_DOUBLE
|
||||||
case VariantType::Double:
|
case VariantType::Double:
|
||||||
return eightByteValue->asDouble != 0;
|
return eightByteValue->asDouble != 0;
|
||||||
@ -174,37 +202,33 @@ class VariantData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayImpl asArray(ResourceManager* resources) {
|
ArrayImpl asArray() {
|
||||||
return ArrayImpl(isArray() ? &content_.asCollection : nullptr, resources);
|
return ArrayImpl(isArray() ? &data_->content.asCollection : nullptr,
|
||||||
|
resources_);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ArrayImpl asArray(VariantData* var, ResourceManager* resources) {
|
CollectionImpl asCollection() {
|
||||||
return ArrayImpl(
|
return CollectionImpl(
|
||||||
var && var->isArray() ? &var->content_.asCollection : nullptr,
|
isCollection() ? &data_->content.asCollection : nullptr, resources_);
|
||||||
resources);
|
|
||||||
}
|
|
||||||
|
|
||||||
CollectionImpl asCollection(ResourceManager* resources) {
|
|
||||||
return CollectionImpl(isCollection() ? &content_.asCollection : nullptr,
|
|
||||||
resources);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T asFloat(const ResourceManager* resources) const {
|
T asFloat() const {
|
||||||
|
if (!data_)
|
||||||
|
return 0.0;
|
||||||
|
|
||||||
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_8_BYTE_POOL
|
#if ARDUINOJSON_USE_8_BYTE_POOL
|
||||||
auto eightByteValue = getEightByte(resources);
|
auto eightByteValue = getEightByte();
|
||||||
#else
|
|
||||||
(void)resources; // silence warning
|
|
||||||
#endif
|
#endif
|
||||||
const char* str = nullptr;
|
const char* str = nullptr;
|
||||||
switch (type_) {
|
switch (data_->type) {
|
||||||
case VariantType::Boolean:
|
case VariantType::Boolean:
|
||||||
return static_cast<T>(content_.asBoolean);
|
return static_cast<T>(data_->content.asBoolean);
|
||||||
case VariantType::Uint32:
|
case VariantType::Uint32:
|
||||||
return static_cast<T>(content_.asUint32);
|
return static_cast<T>(data_->content.asUint32);
|
||||||
case VariantType::Int32:
|
case VariantType::Int32:
|
||||||
return static_cast<T>(content_.asInt32);
|
return static_cast<T>(data_->content.asInt32);
|
||||||
#if ARDUINOJSON_USE_LONG_LONG
|
#if ARDUINOJSON_USE_LONG_LONG
|
||||||
case VariantType::Uint64:
|
case VariantType::Uint64:
|
||||||
return static_cast<T>(eightByteValue->asUint64);
|
return static_cast<T>(eightByteValue->asUint64);
|
||||||
@ -212,16 +236,16 @@ class VariantData {
|
|||||||
return static_cast<T>(eightByteValue->asInt64);
|
return static_cast<T>(eightByteValue->asInt64);
|
||||||
#endif
|
#endif
|
||||||
case VariantType::TinyString:
|
case VariantType::TinyString:
|
||||||
str = content_.asTinyString;
|
str = data_->content.asTinyString;
|
||||||
break;
|
break;
|
||||||
case VariantType::LinkedString:
|
case VariantType::LinkedString:
|
||||||
str = asLinkedString(resources);
|
str = asLinkedString();
|
||||||
break;
|
break;
|
||||||
case VariantType::OwnedString:
|
case VariantType::OwnedString:
|
||||||
str = content_.asOwnedString->data;
|
str = data_->content.asOwnedString->data;
|
||||||
break;
|
break;
|
||||||
case VariantType::Float:
|
case VariantType::Float:
|
||||||
return static_cast<T>(content_.asFloat);
|
return static_cast<T>(data_->content.asFloat);
|
||||||
#if ARDUINOJSON_USE_DOUBLE
|
#if ARDUINOJSON_USE_DOUBLE
|
||||||
case VariantType::Double:
|
case VariantType::Double:
|
||||||
return static_cast<T>(eightByteValue->asDouble);
|
return static_cast<T>(eightByteValue->asDouble);
|
||||||
@ -235,21 +259,22 @@ class VariantData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T asIntegral(const ResourceManager* resources) const {
|
T asIntegral() const {
|
||||||
|
if (!data_)
|
||||||
|
return 0;
|
||||||
|
|
||||||
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_8_BYTE_POOL
|
#if ARDUINOJSON_USE_8_BYTE_POOL
|
||||||
auto eightByteValue = getEightByte(resources);
|
auto eightByteValue = getEightByte();
|
||||||
#else
|
|
||||||
(void)resources; // silence warning
|
|
||||||
#endif
|
#endif
|
||||||
const char* str = nullptr;
|
const char* str = nullptr;
|
||||||
switch (type_) {
|
switch (data_->type) {
|
||||||
case VariantType::Boolean:
|
case VariantType::Boolean:
|
||||||
return content_.asBoolean;
|
return data_->content.asBoolean;
|
||||||
case VariantType::Uint32:
|
case VariantType::Uint32:
|
||||||
return convertNumber<T>(content_.asUint32);
|
return convertNumber<T>(data_->content.asUint32);
|
||||||
case VariantType::Int32:
|
case VariantType::Int32:
|
||||||
return convertNumber<T>(content_.asInt32);
|
return convertNumber<T>(data_->content.asInt32);
|
||||||
#if ARDUINOJSON_USE_LONG_LONG
|
#if ARDUINOJSON_USE_LONG_LONG
|
||||||
case VariantType::Uint64:
|
case VariantType::Uint64:
|
||||||
return convertNumber<T>(eightByteValue->asUint64);
|
return convertNumber<T>(eightByteValue->asUint64);
|
||||||
@ -257,16 +282,16 @@ class VariantData {
|
|||||||
return convertNumber<T>(eightByteValue->asInt64);
|
return convertNumber<T>(eightByteValue->asInt64);
|
||||||
#endif
|
#endif
|
||||||
case VariantType::TinyString:
|
case VariantType::TinyString:
|
||||||
str = content_.asTinyString;
|
str = data_->content.asTinyString;
|
||||||
break;
|
break;
|
||||||
case VariantType::LinkedString:
|
case VariantType::LinkedString:
|
||||||
str = asLinkedString(resources);
|
str = asLinkedString();
|
||||||
break;
|
break;
|
||||||
case VariantType::OwnedString:
|
case VariantType::OwnedString:
|
||||||
str = content_.asOwnedString->data;
|
str = data_->content.asOwnedString->data;
|
||||||
break;
|
break;
|
||||||
case VariantType::Float:
|
case VariantType::Float:
|
||||||
return convertNumber<T>(content_.asFloat);
|
return convertNumber<T>(data_->content.asFloat);
|
||||||
#if ARDUINOJSON_USE_DOUBLE
|
#if ARDUINOJSON_USE_DOUBLE
|
||||||
case VariantType::Double:
|
case VariantType::Double:
|
||||||
return convertNumber<T>(eightByteValue->asDouble);
|
return convertNumber<T>(eightByteValue->asDouble);
|
||||||
@ -279,112 +304,93 @@ class VariantData {
|
|||||||
return parseNumber<T>(str);
|
return parseNumber<T>(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectImpl asObject(ResourceManager* resources) {
|
ObjectImpl asObject() {
|
||||||
return ObjectImpl(isObject() ? &content_.asCollection : nullptr, resources);
|
return ObjectImpl(isObject() ? &data_->content.asCollection : nullptr,
|
||||||
}
|
resources_);
|
||||||
|
|
||||||
static ObjectImpl asObject(VariantData* var, ResourceManager* resources) {
|
|
||||||
return ObjectImpl(
|
|
||||||
var && var->isObject() ? &var->content_.asCollection : nullptr,
|
|
||||||
resources);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonString asRawString() const {
|
JsonString asRawString() const {
|
||||||
switch (type_) {
|
switch (type()) {
|
||||||
case VariantType::RawString:
|
case VariantType::RawString:
|
||||||
return JsonString(content_.asOwnedString->data,
|
return JsonString(data_->content.asOwnedString->data,
|
||||||
content_.asOwnedString->length);
|
data_->content.asOwnedString->length);
|
||||||
default:
|
default:
|
||||||
return JsonString();
|
return JsonString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* asLinkedString(const ResourceManager* resources) const;
|
const char* asLinkedString() const;
|
||||||
|
|
||||||
JsonString asString(const ResourceManager* resources) const {
|
JsonString asString() const {
|
||||||
switch (type_) {
|
switch (type()) {
|
||||||
case VariantType::TinyString:
|
case VariantType::TinyString:
|
||||||
return JsonString(content_.asTinyString);
|
return JsonString(data_->content.asTinyString);
|
||||||
case VariantType::LinkedString:
|
case VariantType::LinkedString:
|
||||||
return JsonString(asLinkedString(resources), true);
|
return JsonString(asLinkedString(), true);
|
||||||
case VariantType::OwnedString:
|
case VariantType::OwnedString:
|
||||||
return JsonString(content_.asOwnedString->data,
|
return JsonString(data_->content.asOwnedString->data,
|
||||||
content_.asOwnedString->length);
|
data_->content.asOwnedString->length);
|
||||||
default:
|
default:
|
||||||
return JsonString();
|
return JsonString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ARDUINOJSON_USE_8_BYTE_POOL
|
#if ARDUINOJSON_USE_8_BYTE_POOL
|
||||||
const EightByteValue* getEightByte(const ResourceManager* resources) const;
|
const EightByteValue* getEightByte() const;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
VariantData* getElement(size_t index, ResourceManager* resources) {
|
VariantData* getElement(size_t index) {
|
||||||
return asArray(resources).getElement(index);
|
return asArray().getElement(index);
|
||||||
}
|
|
||||||
|
|
||||||
static VariantData* getElement(VariantData* var, size_t index,
|
|
||||||
ResourceManager* resources) {
|
|
||||||
if (!var)
|
|
||||||
return nullptr;
|
|
||||||
return var->asArray(resources).getElement(index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TAdaptedString>
|
template <typename TAdaptedString>
|
||||||
VariantData* getMember(TAdaptedString key, ResourceManager* resources) {
|
VariantData* getMember(TAdaptedString key) {
|
||||||
return asObject(resources).getMember(key);
|
return asObject().getMember(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TAdaptedString>
|
VariantData* getOrAddElement(size_t index) {
|
||||||
static VariantData* getMember(VariantData* var, TAdaptedString key,
|
auto array = isNull() ? toArray() : asArray();
|
||||||
ResourceManager* resources) {
|
|
||||||
if (!var)
|
|
||||||
return 0;
|
|
||||||
return var->getMember(key, resources);
|
|
||||||
}
|
|
||||||
|
|
||||||
VariantData* getOrAddElement(size_t index, ResourceManager* resources) {
|
|
||||||
auto array = isNull() ? toArray(resources) : asArray(resources);
|
|
||||||
return array.getOrAddElement(index);
|
return array.getOrAddElement(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TAdaptedString>
|
template <typename TAdaptedString>
|
||||||
VariantData* getOrAddMember(TAdaptedString key, ResourceManager* resources) {
|
VariantData* getOrAddMember(TAdaptedString key) {
|
||||||
if (key.isNull())
|
if (key.isNull())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
auto obj = isNull() ? toObject(resources) : asObject(resources);
|
auto obj = isNull() ? toObject() : asObject();
|
||||||
return obj.getOrAddMember(key);
|
return obj.getOrAddMember(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isArray() const {
|
bool isArray() const {
|
||||||
return type_ == VariantType::Array;
|
return type() == VariantType::Array;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isBoolean() const {
|
bool isBoolean() const {
|
||||||
return type_ == VariantType::Boolean;
|
return type() == VariantType::Boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isCollection() const {
|
bool isCollection() const {
|
||||||
return type_ & VariantTypeBits::CollectionMask;
|
return type() & VariantTypeBits::CollectionMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isFloat() const {
|
bool isFloat() const {
|
||||||
return type_ & VariantTypeBits::NumberBit;
|
return data_ && data_->isFloat();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool isInteger(const ResourceManager* resources) const {
|
bool isInteger() const {
|
||||||
|
if (!data_)
|
||||||
|
return false;
|
||||||
|
|
||||||
#if ARDUINOJSON_USE_LONG_LONG
|
#if ARDUINOJSON_USE_LONG_LONG
|
||||||
auto eightByteValue = getEightByte(resources);
|
auto eightByteValue = getEightByte();
|
||||||
#else
|
|
||||||
(void)resources; // silence warning
|
|
||||||
#endif
|
#endif
|
||||||
switch (type_) {
|
switch (data_->type) {
|
||||||
case VariantType::Uint32:
|
case VariantType::Uint32:
|
||||||
return canConvertNumber<T>(content_.asUint32);
|
return canConvertNumber<T>(data_->content.asUint32);
|
||||||
|
|
||||||
case VariantType::Int32:
|
case VariantType::Int32:
|
||||||
return canConvertNumber<T>(content_.asInt32);
|
return canConvertNumber<T>(data_->content.asInt32);
|
||||||
|
|
||||||
#if ARDUINOJSON_USE_LONG_LONG
|
#if ARDUINOJSON_USE_LONG_LONG
|
||||||
case VariantType::Uint64:
|
case VariantType::Uint64:
|
||||||
@ -400,197 +406,102 @@ class VariantData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool isNull() const {
|
bool isNull() const {
|
||||||
return type_ == VariantType::Null;
|
return type() == VariantType::Null;
|
||||||
}
|
|
||||||
|
|
||||||
static bool isNull(const VariantData* var) {
|
|
||||||
if (!var)
|
|
||||||
return true;
|
|
||||||
return var->isNull();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isObject() const {
|
bool isObject() const {
|
||||||
return type_ == VariantType::Object;
|
return type() == VariantType::Object;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isString() const {
|
bool isString() const {
|
||||||
return type_ == VariantType::LinkedString ||
|
return data_ && data_->isString();
|
||||||
type_ == VariantType::OwnedString ||
|
|
||||||
type_ == VariantType::TinyString;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t nesting(ResourceManager* resources) {
|
size_t nesting() {
|
||||||
return asCollection(resources).nesting();
|
return asCollection().nesting();
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t nesting(VariantData* var, ResourceManager* resources) {
|
void removeElement(size_t index) {
|
||||||
if (!var)
|
asArray().removeElement(index);
|
||||||
return 0;
|
|
||||||
return var->nesting(resources);
|
|
||||||
}
|
|
||||||
|
|
||||||
void removeElement(size_t index, ResourceManager* resources) {
|
|
||||||
asArray(resources).removeElement(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void removeElement(VariantData* var, size_t index,
|
|
||||||
ResourceManager* resources) {
|
|
||||||
if (!var)
|
|
||||||
return;
|
|
||||||
var->removeElement(index, resources);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TAdaptedString>
|
template <typename TAdaptedString>
|
||||||
void removeMember(TAdaptedString key, ResourceManager* resources) {
|
void removeMember(TAdaptedString key) {
|
||||||
asObject(resources).removeMember(key);
|
asObject().removeMember(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TAdaptedString>
|
bool setBoolean(bool value) {
|
||||||
static void removeMember(VariantData* var, TAdaptedString key,
|
if (!data_)
|
||||||
ResourceManager* resources) {
|
return false;
|
||||||
if (!var)
|
data_->setBoolean(value);
|
||||||
return;
|
|
||||||
var->removeMember(key, resources);
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset() { // TODO: remove
|
|
||||||
type_ = VariantType::Null;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setBoolean(bool value) {
|
|
||||||
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_ == VariantType::Null); // must call clear() first
|
|
||||||
type_ = VariantType::Float;
|
|
||||||
content_.asFloat = value;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
enable_if_t<sizeof(T) == 8, bool> setFloat(T value, ResourceManager*);
|
enable_if_t<sizeof(T) == 4, bool> setFloat(T value) {
|
||||||
|
ARDUINOJSON_ASSERT(type() == VariantType::Null); // must call clear() first
|
||||||
template <typename T>
|
if (!data_)
|
||||||
enable_if_t<is_signed<T>::value, bool> setInteger(T value,
|
return false;
|
||||||
ResourceManager* resources);
|
data_->type = VariantType::Float;
|
||||||
|
data_->content.asFloat = value;
|
||||||
template <typename T>
|
return true;
|
||||||
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_.asOwnedString = s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void setRawString(SerializedValue<T> value, ResourceManager* resources);
|
enable_if_t<sizeof(T) == 8, bool> setFloat(T value);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static void setRawString(VariantData* var, SerializedValue<T> value,
|
enable_if_t<is_signed<T>::value, bool> setInteger(T value);
|
||||||
ResourceManager* resources) {
|
|
||||||
if (!var)
|
template <typename T>
|
||||||
return;
|
enable_if_t<is_unsigned<T>::value, bool> setInteger(T value);
|
||||||
var->clear(resources);
|
|
||||||
var->setRawString(value, resources);
|
template <typename T>
|
||||||
}
|
void setRawString(SerializedValue<T> value);
|
||||||
|
|
||||||
template <typename TAdaptedString>
|
template <typename TAdaptedString>
|
||||||
bool setString(TAdaptedString value, ResourceManager* resources);
|
bool setString(TAdaptedString value);
|
||||||
|
|
||||||
template <typename TAdaptedString>
|
bool setLinkedString(const char* s);
|
||||||
static void setString(VariantData* var, TAdaptedString value,
|
|
||||||
ResourceManager* resources) {
|
|
||||||
if (!var)
|
|
||||||
return;
|
|
||||||
var->clear(resources);
|
|
||||||
var->setString(value, resources);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool setLinkedString(const char* s, ResourceManager* resources);
|
size_t size() {
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setOwnedString(StringNode* s) {
|
|
||||||
ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first
|
|
||||||
ARDUINOJSON_ASSERT(s);
|
|
||||||
type_ = VariantType::OwnedString;
|
|
||||||
content_.asOwnedString = s;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t size(ResourceManager* resources) {
|
|
||||||
if (isObject())
|
if (isObject())
|
||||||
return asObject(resources).size();
|
return asObject().size();
|
||||||
|
|
||||||
if (isArray())
|
if (isArray())
|
||||||
return asArray(resources).size();
|
return asArray().size();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t size(VariantData* var, ResourceManager* resources) {
|
ArrayImpl toArray() {
|
||||||
return var != 0 ? var->size(resources) : 0;
|
ARDUINOJSON_ASSERT(type() == VariantType::Null); // must call clear() first
|
||||||
|
if (!data_)
|
||||||
|
return ArrayImpl();
|
||||||
|
data_->type = VariantType::Array;
|
||||||
|
return ArrayImpl(new (&data_->content.asCollection) CollectionData(),
|
||||||
|
resources_);
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayImpl toArray(ResourceManager* resources) {
|
ObjectImpl toObject() {
|
||||||
ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first
|
ARDUINOJSON_ASSERT(type() == VariantType::Null); // must call clear() first
|
||||||
type_ = VariantType::Array;
|
if (!data_)
|
||||||
return ArrayImpl(new (&content_.asCollection) CollectionData(), resources);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ArrayImpl toArray(VariantData* var, ResourceManager* resources) {
|
|
||||||
if (!var)
|
|
||||||
return ArrayImpl(nullptr, resources);
|
|
||||||
var->clear(resources);
|
|
||||||
return var->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);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ObjectImpl toObject(VariantData* var, ResourceManager* resources) {
|
|
||||||
if (!var)
|
|
||||||
return ObjectImpl();
|
return ObjectImpl();
|
||||||
var->clear(resources);
|
data_->type = VariantType::Object;
|
||||||
return var->toObject(resources);
|
return ObjectImpl(new (&data_->content.asCollection) CollectionData(),
|
||||||
|
resources_);
|
||||||
}
|
}
|
||||||
|
|
||||||
VariantType type() const {
|
VariantType type() const {
|
||||||
return type_;
|
return data_ ? data_->type : VariantType::Null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release the resources used by this variant and set it to null.
|
// Release the resources used by this variant and set it to null.
|
||||||
void clear(ResourceManager* resources);
|
void clear();
|
||||||
|
|
||||||
static void clear(VariantData* var, ResourceManager* resources) {
|
private:
|
||||||
if (!var)
|
VariantData* data_;
|
||||||
return;
|
ResourceManager* resources_;
|
||||||
var->clear(resources);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||||
|
@ -10,126 +10,130 @@
|
|||||||
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline void VariantData::setRawString(SerializedValue<T> value,
|
inline void VariantImpl::setRawString(SerializedValue<T> value) {
|
||||||
ResourceManager* resources) {
|
if (!data_)
|
||||||
ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first
|
return;
|
||||||
auto dup = resources->saveString(adaptString(value.data(), value.size()));
|
auto dup = resources_->saveString(adaptString(value.data(), value.size()));
|
||||||
if (dup)
|
if (dup)
|
||||||
setRawString(dup);
|
data_->setRawString(dup);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool VariantData::setLinkedString(const char* s,
|
inline bool VariantImpl::setLinkedString(const char* s) {
|
||||||
ResourceManager* resources) {
|
ARDUINOJSON_ASSERT(isNull()); // must call clear() first
|
||||||
ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first
|
|
||||||
ARDUINOJSON_ASSERT(s);
|
ARDUINOJSON_ASSERT(s);
|
||||||
|
|
||||||
auto slotId = resources->saveStaticString(s);
|
auto slotId = resources_->saveStaticString(s);
|
||||||
if (slotId == NULL_SLOT)
|
if (slotId == NULL_SLOT)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
type_ = VariantType::LinkedString;
|
data_->type = VariantType::LinkedString;
|
||||||
content_.asSlotId = slotId;
|
data_->content.asSlotId = slotId;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TAdaptedString>
|
template <typename TAdaptedString>
|
||||||
inline bool VariantData::setString(TAdaptedString value,
|
inline bool VariantImpl::setString(TAdaptedString value) {
|
||||||
ResourceManager* resources) {
|
ARDUINOJSON_ASSERT(isNull()); // must call clear() first
|
||||||
ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first
|
|
||||||
|
if (!data_)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (value.isNull())
|
if (value.isNull())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (value.isStatic())
|
if (value.isStatic())
|
||||||
return setLinkedString(value.data(), resources);
|
return setLinkedString(value.data());
|
||||||
|
|
||||||
if (isTinyString(value, value.size())) {
|
if (isTinyString(value, value.size())) {
|
||||||
setTinyString(value);
|
data_->setTinyString(value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto dup = resources->saveString(value);
|
auto dup = resources_->saveString(value);
|
||||||
if (dup) {
|
if (dup) {
|
||||||
setOwnedString(dup);
|
data_->setOwnedString(dup);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void VariantData::clear(ResourceManager* resources) {
|
inline void VariantImpl::clear() {
|
||||||
if (type_ & VariantTypeBits::OwnedStringBit)
|
if (!data_)
|
||||||
resources->dereferenceString(content_.asOwnedString->data);
|
return;
|
||||||
|
|
||||||
|
if (data_->type & VariantTypeBits::OwnedStringBit)
|
||||||
|
resources_->dereferenceString(data_->content.asOwnedString->data);
|
||||||
|
|
||||||
#if ARDUINOJSON_USE_8_BYTE_POOL
|
#if ARDUINOJSON_USE_8_BYTE_POOL
|
||||||
if (type_ & VariantTypeBits::EightByteBit)
|
if (data_->type & VariantTypeBits::EightByteBit)
|
||||||
resources->freeEightByte(content_.asSlotId);
|
resources_->freeEightByte(data_->content.asSlotId);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
asCollection(resources).clear();
|
asCollection().clear();
|
||||||
|
|
||||||
type_ = VariantType::Null;
|
data_->type = VariantType::Null;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ARDUINOJSON_USE_8_BYTE_POOL
|
#if ARDUINOJSON_USE_8_BYTE_POOL
|
||||||
inline const EightByteValue* VariantData::getEightByte(
|
inline const EightByteValue* VariantImpl::getEightByte() const {
|
||||||
const ResourceManager* resources) const {
|
return type() & VariantTypeBits::EightByteBit
|
||||||
return type_ & VariantTypeBits::EightByteBit
|
? resources_->getEightByte(data_->content.asSlotId)
|
||||||
? resources->getEightByte(content_.asSlotId)
|
|
||||||
: 0;
|
: 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
inline const char* VariantData::asLinkedString(
|
inline const char* VariantImpl::asLinkedString() const {
|
||||||
const ResourceManager* resources) const {
|
ARDUINOJSON_ASSERT(type() == VariantType::LinkedString);
|
||||||
ARDUINOJSON_ASSERT(type_ == VariantType::LinkedString);
|
return resources_->getStaticString(data_->content.asSlotId);
|
||||||
return resources->getStaticString(content_.asSlotId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
enable_if_t<sizeof(T) == 8, bool> VariantData::setFloat(
|
enable_if_t<sizeof(T) == 8, bool> VariantImpl::setFloat(T value) {
|
||||||
T value, ResourceManager* resources) {
|
ARDUINOJSON_ASSERT(isNull()); // must call clear() first
|
||||||
ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first
|
|
||||||
(void)resources; // silence warning
|
if (!data_)
|
||||||
|
return false;
|
||||||
|
|
||||||
float valueAsFloat = static_cast<float>(value);
|
float valueAsFloat = static_cast<float>(value);
|
||||||
|
|
||||||
#if ARDUINOJSON_USE_DOUBLE
|
#if ARDUINOJSON_USE_DOUBLE
|
||||||
if (value == valueAsFloat) {
|
if (value == valueAsFloat) {
|
||||||
type_ = VariantType::Float;
|
data_->type = VariantType::Float;
|
||||||
content_.asFloat = valueAsFloat;
|
data_->content.asFloat = valueAsFloat;
|
||||||
} else {
|
} else {
|
||||||
auto slot = resources->allocEightByte();
|
auto slot = resources_->allocEightByte();
|
||||||
if (!slot)
|
if (!slot)
|
||||||
return false;
|
return false;
|
||||||
type_ = VariantType::Double;
|
data_->type = VariantType::Double;
|
||||||
content_.asSlotId = slot.id();
|
data_->content.asSlotId = slot.id();
|
||||||
slot->asDouble = value;
|
slot->asDouble = value;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
type_ = VariantType::Float;
|
data_->type = VariantType::Float;
|
||||||
content_.asFloat = valueAsFloat;
|
data_->content.asFloat = valueAsFloat;
|
||||||
#endif
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
enable_if_t<is_signed<T>::value, bool> VariantData::setInteger(
|
enable_if_t<is_signed<T>::value, bool> VariantImpl::setInteger(T value) {
|
||||||
T value, ResourceManager* resources) {
|
ARDUINOJSON_ASSERT(isNull()); // must call clear() first
|
||||||
ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first
|
|
||||||
(void)resources; // silence warning
|
if (!data_)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (canConvertNumber<int32_t>(value)) {
|
if (canConvertNumber<int32_t>(value)) {
|
||||||
type_ = VariantType::Int32;
|
data_->type = VariantType::Int32;
|
||||||
content_.asInt32 = static_cast<int32_t>(value);
|
data_->content.asInt32 = static_cast<int32_t>(value);
|
||||||
}
|
}
|
||||||
#if ARDUINOJSON_USE_LONG_LONG
|
#if ARDUINOJSON_USE_LONG_LONG
|
||||||
else {
|
else {
|
||||||
auto slot = resources->allocEightByte();
|
auto slot = resources_->allocEightByte();
|
||||||
if (!slot)
|
if (!slot)
|
||||||
return false;
|
return false;
|
||||||
type_ = VariantType::Int64;
|
data_->type = VariantType::Int64;
|
||||||
content_.asSlotId = slot.id();
|
data_->content.asSlotId = slot.id();
|
||||||
slot->asInt64 = value;
|
slot->asInt64 = value;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -137,22 +141,23 @@ enable_if_t<is_signed<T>::value, bool> VariantData::setInteger(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
enable_if_t<is_unsigned<T>::value, bool> VariantData::setInteger(
|
enable_if_t<is_unsigned<T>::value, bool> VariantImpl::setInteger(T value) {
|
||||||
T value, ResourceManager* resources) {
|
ARDUINOJSON_ASSERT(isNull()); // must call clear() first
|
||||||
ARDUINOJSON_ASSERT(type_ == VariantType::Null); // must call clear() first
|
|
||||||
(void)resources; // silence warning
|
if (!data_)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (canConvertNumber<uint32_t>(value)) {
|
if (canConvertNumber<uint32_t>(value)) {
|
||||||
type_ = VariantType::Uint32;
|
data_->type = VariantType::Uint32;
|
||||||
content_.asUint32 = static_cast<uint32_t>(value);
|
data_->content.asUint32 = static_cast<uint32_t>(value);
|
||||||
}
|
}
|
||||||
#if ARDUINOJSON_USE_LONG_LONG
|
#if ARDUINOJSON_USE_LONG_LONG
|
||||||
else {
|
else {
|
||||||
auto slot = resources->allocEightByte();
|
auto slot = resources_->allocEightByte();
|
||||||
if (!slot)
|
if (!slot)
|
||||||
return false;
|
return false;
|
||||||
type_ = VariantType::Uint64;
|
data_->type = VariantType::Uint64;
|
||||||
content_.asSlotId = slot.id();
|
data_->content.asSlotId = slot.id();
|
||||||
slot->asUint64 = value;
|
slot->asUint64 = value;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -29,13 +29,13 @@ class VariantRefBase : public VariantTag {
|
|||||||
// Sets the value to null.
|
// Sets the value to null.
|
||||||
// https://arduinojson.org/v7/api/jsonvariant/clear/
|
// https://arduinojson.org/v7/api/jsonvariant/clear/
|
||||||
void clear() const {
|
void clear() const {
|
||||||
VariantData::clear(getOrCreateData(), getResourceManager());
|
getOrCreateVariantImpl().clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the value is null or the reference is unbound.
|
// Returns true if the value is null or the reference is unbound.
|
||||||
// https://arduinojson.org/v7/api/jsonvariant/isnull/
|
// https://arduinojson.org/v7/api/jsonvariant/isnull/
|
||||||
bool isNull() const {
|
bool isNull() const {
|
||||||
return VariantData::isNull(getData());
|
return getVariantImpl().isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the reference is unbound.
|
// Returns true if the reference is unbound.
|
||||||
@ -93,13 +93,13 @@ class VariantRefBase : public VariantTag {
|
|||||||
// Returns the size of the array or object.
|
// Returns the size of the array or object.
|
||||||
// https://arduinojson.org/v7/api/jsonvariant/size/
|
// https://arduinojson.org/v7/api/jsonvariant/size/
|
||||||
size_t size() const {
|
size_t size() const {
|
||||||
return VariantData::size(getData(), getResourceManager());
|
return getVariantImpl().size();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the depth (nesting level) of the value.
|
// Returns the depth (nesting level) of the value.
|
||||||
// https://arduinojson.org/v7/api/jsonvariant/nesting/
|
// https://arduinojson.org/v7/api/jsonvariant/nesting/
|
||||||
size_t nesting() const {
|
size_t nesting() const {
|
||||||
return VariantData::nesting(getData(), getResourceManager());
|
return getVariantImpl().nesting();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Appends a new (empty) element to the array.
|
// Appends a new (empty) element to the array.
|
||||||
@ -120,38 +120,34 @@ class VariantRefBase : public VariantTag {
|
|||||||
// https://arduinojson.org/v7/api/jsonvariant/add/
|
// https://arduinojson.org/v7/api/jsonvariant/add/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool add(const T& value) const {
|
bool add(const T& value) const {
|
||||||
return detail::VariantData::addValue(getOrCreateData(), value,
|
return getOrCreateVariantImpl().addValue(value);
|
||||||
getResourceManager());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Appends a value to the array.
|
// Appends a value to the array.
|
||||||
// https://arduinojson.org/v7/api/jsonvariant/add/
|
// https://arduinojson.org/v7/api/jsonvariant/add/
|
||||||
template <typename T, enable_if_t<!is_const<T>::value, int> = 0>
|
template <typename T, enable_if_t<!is_const<T>::value, int> = 0>
|
||||||
bool add(T* value) const {
|
bool add(T* value) const {
|
||||||
return detail::VariantData::addValue(getOrCreateData(), value,
|
return getOrCreateVariantImpl().addValue(value);
|
||||||
getResourceManager());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes an element of the array.
|
// Removes an element of the array.
|
||||||
// https://arduinojson.org/v7/api/jsonvariant/remove/
|
// https://arduinojson.org/v7/api/jsonvariant/remove/
|
||||||
void remove(size_t index) const {
|
void remove(size_t index) const {
|
||||||
VariantData::removeElement(getData(), index, getResourceManager());
|
getVariantImpl().removeElement(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes a member of the object.
|
// Removes a member of the object.
|
||||||
// https://arduinojson.org/v7/api/jsonvariant/remove/
|
// https://arduinojson.org/v7/api/jsonvariant/remove/
|
||||||
template <typename TChar, enable_if_t<IsString<TChar*>::value, int> = 0>
|
template <typename TChar, enable_if_t<IsString<TChar*>::value, int> = 0>
|
||||||
void remove(TChar* key) const {
|
void remove(TChar* key) const {
|
||||||
VariantData::removeMember(getData(), adaptString(key),
|
getVariantImpl().removeMember(adaptString(key));
|
||||||
getResourceManager());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes a member of the object.
|
// Removes a member of the object.
|
||||||
// https://arduinojson.org/v7/api/jsonvariant/remove/
|
// https://arduinojson.org/v7/api/jsonvariant/remove/
|
||||||
template <typename TString, enable_if_t<IsString<TString>::value, int> = 0>
|
template <typename TString, enable_if_t<IsString<TString>::value, int> = 0>
|
||||||
void remove(const TString& key) const {
|
void remove(const TString& key) const {
|
||||||
VariantData::removeMember(getData(), adaptString(key),
|
getVariantImpl().removeMember(adaptString(key));
|
||||||
getResourceManager());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes a member of the object or an element of the array.
|
// Removes a member of the object or an element of the array.
|
||||||
@ -275,6 +271,14 @@ class VariantRefBase : public VariantTag {
|
|||||||
return VariantAttorney::getOrCreateData(derived());
|
return VariantAttorney::getOrCreateData(derived());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VariantImpl getVariantImpl() const {
|
||||||
|
return VariantImpl(getData(), getResourceManager());
|
||||||
|
}
|
||||||
|
|
||||||
|
VariantImpl getOrCreateVariantImpl() const {
|
||||||
|
return VariantImpl(getOrCreateData(), getResourceManager());
|
||||||
|
}
|
||||||
|
|
||||||
FORCE_INLINE ArduinoJson::JsonVariant getVariant() const;
|
FORCE_INLINE ArduinoJson::JsonVariant getVariant() const;
|
||||||
|
|
||||||
FORCE_INLINE ArduinoJson::JsonVariantConst getVariantConst() const {
|
FORCE_INLINE ArduinoJson::JsonVariantConst getVariantConst() const {
|
||||||
|
@ -69,23 +69,20 @@ inline void convertToJson(const VariantRefBase<TDerived>& src,
|
|||||||
template <typename TDerived>
|
template <typename TDerived>
|
||||||
template <typename T, enable_if_t<is_same<T, JsonVariant>::value, int>>
|
template <typename T, enable_if_t<is_same<T, JsonVariant>::value, int>>
|
||||||
inline T VariantRefBase<TDerived>::add() const {
|
inline T VariantRefBase<TDerived>::add() const {
|
||||||
return JsonVariant(
|
return JsonVariant(getOrCreateVariantImpl().addElement(),
|
||||||
detail::VariantData::addElement(getOrCreateData(), getResourceManager()),
|
getResourceManager());
|
||||||
getResourceManager());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TDerived>
|
template <typename TDerived>
|
||||||
template <typename TString, enable_if_t<IsString<TString>::value, int>>
|
template <typename TString, enable_if_t<IsString<TString>::value, int>>
|
||||||
inline bool VariantRefBase<TDerived>::containsKey(const TString& key) const {
|
inline bool VariantRefBase<TDerived>::containsKey(const TString& key) const {
|
||||||
return VariantData::getMember(getData(), adaptString(key),
|
return getVariantImpl().getMember(adaptString(key)) != 0;
|
||||||
getResourceManager()) != 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TDerived>
|
template <typename TDerived>
|
||||||
template <typename TChar, enable_if_t<IsString<TChar*>::value, int>>
|
template <typename TChar, enable_if_t<IsString<TChar*>::value, int>>
|
||||||
inline bool VariantRefBase<TDerived>::containsKey(TChar* key) const {
|
inline bool VariantRefBase<TDerived>::containsKey(TChar* key) const {
|
||||||
return VariantData::getMember(getData(), adaptString(key),
|
return getVariantImpl().getMember(adaptString(key)) != 0;
|
||||||
getResourceManager()) != 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TDerived>
|
template <typename TDerived>
|
||||||
@ -150,24 +147,25 @@ inline bool VariantRefBase<TDerived>::doSet(const T& value, true_type) const {
|
|||||||
template <typename TDerived>
|
template <typename TDerived>
|
||||||
template <typename T, enable_if_t<is_same<T, JsonArray>::value, int>>
|
template <typename T, enable_if_t<is_same<T, JsonArray>::value, int>>
|
||||||
inline JsonArray VariantRefBase<TDerived>::to() const {
|
inline JsonArray VariantRefBase<TDerived>::to() const {
|
||||||
return JsonArray(
|
auto variant = getOrCreateVariantImpl();
|
||||||
VariantData::toArray(getOrCreateData(), getResourceManager()));
|
variant.clear();
|
||||||
|
return JsonArray(variant.toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TDerived>
|
template <typename TDerived>
|
||||||
template <typename T, enable_if_t<is_same<T, JsonObject>::value, int>>
|
template <typename T, enable_if_t<is_same<T, JsonObject>::value, int>>
|
||||||
JsonObject VariantRefBase<TDerived>::to() const {
|
JsonObject VariantRefBase<TDerived>::to() const {
|
||||||
return JsonObject(
|
auto variant = getOrCreateVariantImpl();
|
||||||
VariantData::toObject(getOrCreateData(), getResourceManager()));
|
variant.clear();
|
||||||
|
return JsonObject(variant.toObject());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TDerived>
|
template <typename TDerived>
|
||||||
template <typename T, enable_if_t<is_same<T, JsonVariant>::value, int>>
|
template <typename T, enable_if_t<is_same<T, JsonVariant>::value, int>>
|
||||||
JsonVariant VariantRefBase<TDerived>::to() const {
|
JsonVariant VariantRefBase<TDerived>::to() const {
|
||||||
auto data = getOrCreateData();
|
detail::VariantImpl impl(getOrCreateData(), getResourceManager());
|
||||||
auto resources = getResourceManager();
|
impl.clear();
|
||||||
detail::VariantData::clear(data, resources);
|
return JsonVariant(impl);
|
||||||
return JsonVariant(data, resources);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
ARDUINOJSON_END_PRIVATE_NAMESPACE
|
||||||
|
Reference in New Issue
Block a user