Change link() to shallowCopy() (issue #1343)

Instead of storing a pointer, the function copies the `VariantData`.

Benefits:
* smaller code
* no impact on programs that don't use this feature

Drawbacks:
* changes to the original variant are not always reflected on the copy
* modifying the original from the shallow copy leads to UB
This commit is contained in:
Benoit Blanchon
2022-07-05 17:07:43 +02:00
parent 3b3ab8c4e1
commit cd8373ad32
36 changed files with 78 additions and 543 deletions

View File

@ -4,7 +4,7 @@ ArduinoJson: change log
HEAD
----
* Add `JsonVariant::link()` (issue #1343)
* Add `JsonVariant::shallowCopy()` (issue #1343)
* Fix `9.22337e+18 is outside the range of representable values of type 'long'`
* Fix comparison operators for `JsonArray`, `JsonArrayConst`, `JsonObject`, and `JsonObjectConst`
* Remove undocumented `accept()` functions

View File

@ -43,13 +43,5 @@ TEST_CASE("nullptr") {
variant.clear();
REQUIRE(variant.is<std::nullptr_t>() == true);
StaticJsonDocument<128> doc2;
doc2["hello"] = "world";
variant.link(doc2);
REQUIRE(variant.is<std::nullptr_t>() == false);
doc2.clear();
REQUIRE(variant.is<std::nullptr_t>() == true);
}
}

View File

@ -246,10 +246,10 @@ TEST_CASE("ElementProxy cast to JsonVariant") {
CHECK(doc.as<std::string>() == "[\"toto\"]");
}
TEST_CASE("ElementProxy::link()") {
TEST_CASE("ElementProxy::shallowCopy()") {
StaticJsonDocument<1024> doc1, doc2;
doc1[0].link(doc2);
doc2["hello"] = "world";
doc1[0].shallowCopy(doc2);
CHECK(doc1.as<std::string>() == "[{\"hello\":\"world\"}]");
}

View File

@ -318,10 +318,10 @@ TEST_CASE("MemberProxy::createNestedObject(key)") {
CHECK(doc["status"]["weather"]["temp"] == 42);
}
TEST_CASE("MemberProxy::link()") {
TEST_CASE("MemberProxy::shallowCopy()") {
StaticJsonDocument<1024> doc1, doc2;
doc1["obj"].link(doc2);
doc2["hello"] = "world";
doc1["obj"].shallowCopy(doc2);
CHECK(doc1.as<std::string>() == "{\"obj\":{\"hello\":\"world\"}}");
}

View File

@ -25,21 +25,4 @@ TEST_CASE("JsonDocument::size()") {
REQUIRE(doc.size() == 2);
}
SECTION("linked array") {
StaticJsonDocument<128> doc2;
doc2.add(1);
doc2.add(2);
doc.as<JsonVariant>().link(doc2);
REQUIRE(doc.size() == 2);
}
SECTION("linked object") {
StaticJsonDocument<128> doc2;
doc2["hello"] = "world";
doc.as<JsonVariant>().link(doc2);
REQUIRE(doc.size() == 1);
}
}

View File

@ -13,7 +13,6 @@ add_executable(JsonVariantTests
createNested.cpp
is.cpp
isnull.cpp
link.cpp
memoryUsage.cpp
misc.cpp
nesting.cpp
@ -21,6 +20,7 @@ add_executable(JsonVariantTests
overflow.cpp
remove.cpp
set.cpp
shallowCopy.cpp
size.cpp
subscript.cpp
types.cpp

View File

@ -43,14 +43,4 @@ TEST_CASE("JsonVariant::add()") {
REQUIRE(var.as<std::string>() == "{\"val\":123}");
}
SECTION("add to linked array") {
StaticJsonDocument<1024> doc2;
doc2.add(42);
var.link(doc2);
var.add(666); // no-op
CHECK(var.as<std::string>() == "[42]");
}
}

View File

@ -267,97 +267,4 @@ TEST_CASE("JsonVariant::as()") {
REQUIRE(variant.as<MY_ENUM>() == ONE);
}
SECTION("linked object") {
StaticJsonDocument<128> doc2;
doc2["hello"] = "world";
variant.link(doc2);
SECTION("as<std::string>()") {
CHECK(variant.as<std::string>() == "{\"hello\":\"world\"}");
}
SECTION("as<JsonArray>()") {
JsonArray a = variant.as<JsonArray>();
CHECK(a.isNull() == true);
}
SECTION("as<JsonObject>()") {
JsonObject o = variant.as<JsonObject>();
CHECK(o.isNull() == true);
}
SECTION("as<JsonObjectConst>()") {
JsonObjectConst o = variant.as<JsonObjectConst>();
CHECK(o.isNull() == false);
CHECK(o.size() == 1);
CHECK(o["hello"] == "world");
}
}
SECTION("linked array") {
StaticJsonDocument<128> doc2;
doc2.add("hello");
doc2.add("world");
variant.link(doc2);
SECTION("as<std::string>()") {
CHECK(variant.as<std::string>() == "[\"hello\",\"world\"]");
}
SECTION("as<JsonArray>()") {
JsonArray a = variant.as<JsonArray>();
CHECK(a.isNull() == true);
}
SECTION("as<JsonArrayConst>()") {
JsonArrayConst a = variant.as<JsonArrayConst>();
CHECK(a.isNull() == false);
CHECK(a.size() == 2);
CHECK(a[0] == "hello");
CHECK(a[1] == "world");
}
SECTION("as<JsonObject>()") {
JsonObject o = variant.as<JsonObject>();
CHECK(o.isNull() == true);
}
}
SECTION("linked int") {
StaticJsonDocument<128> doc2;
doc2.set(42);
variant.link(doc2);
CHECK(variant.as<int>() == 42);
CHECK(variant.as<double>() == 42.0);
}
SECTION("linked double") {
StaticJsonDocument<128> doc2;
doc2.set(42.0);
variant.link(doc2);
CHECK(variant.as<int>() == 42);
CHECK(variant.as<double>() == 42.0);
}
SECTION("linked string") {
StaticJsonDocument<128> doc2;
doc2.set("hello");
variant.link(doc2);
CHECK(variant.as<std::string>() == "hello");
}
SECTION("linked bool") {
StaticJsonDocument<128> doc2;
variant.link(doc2);
doc2.set(true);
CHECK(variant.as<bool>() == true);
doc2.set(false);
CHECK(variant.as<bool>() == false);
}
}

View File

@ -23,15 +23,4 @@ TEST_CASE("JsonVariant::clear()") {
REQUIRE(var.isNull() == true);
}
SECTION("doesn't alter linked object") {
StaticJsonDocument<128> doc2;
doc2["hello"] = "world";
var.link(doc2);
var.clear();
CHECK(var.isNull() == true);
CHECK(doc2.as<std::string>() == "{\"hello\":\"world\"}");
}
}

View File

@ -34,20 +34,6 @@ TEST_CASE("Compare JsonVariant with value") {
CHECK_FALSE(a < b);
CHECK_FALSE(a > b);
}
SECTION("linked 42 vs 42") {
StaticJsonDocument<128> doc2;
doc2.set(42);
a.link(doc2);
int b = 42;
CHECK(a == b);
CHECK(a <= b);
CHECK(a >= b);
CHECK_FALSE(a != b);
CHECK_FALSE(a < b);
CHECK_FALSE(a > b);
}
}
TEST_CASE("Compare JsonVariant with JsonVariant") {
@ -327,19 +313,4 @@ TEST_CASE("Compare JsonVariant with JsonVariant") {
CHECK_FALSE(a > b);
CHECK_FALSE(a >= b);
}
SECTION("linked 42 vs link 42") {
StaticJsonDocument<128> doc2, doc3;
doc2.set(42);
doc3.set(42);
a.link(doc2);
b.link(doc3);
CHECK(a == b);
CHECK(a <= b);
CHECK(a >= b);
CHECK_FALSE(a != b);
CHECK_FALSE(a < b);
CHECK_FALSE(a > b);
}
}

View File

@ -25,15 +25,6 @@ TEST_CASE("JsonVariant::containsKey()") {
REQUIRE(var.containsKey(std::string("hello")) == true);
REQUIRE(var.containsKey(std::string("world")) == false);
}
SECTION("linked object") {
StaticJsonDocument<128> doc2;
doc2["hello"] = "world";
var.link(doc2);
CHECK(var.containsKey("hello") == true);
CHECK(var.containsKey("world") == false);
}
}
TEST_CASE("JsonVariantConst::containsKey()") {

View File

@ -84,16 +84,6 @@ TEST_CASE("JsonVariant::set(JsonVariant)") {
REQUIRE(doc2.memoryUsage() == JSON_STRING_SIZE(7));
}
SECTION("stores linked object by pointer") {
StaticJsonDocument<128> doc3;
doc3["hello"] = "world";
var1.link(doc3);
var2.set(var1);
REQUIRE(doc1.memoryUsage() == 0);
REQUIRE(doc2.memoryUsage() == 0);
}
SECTION("destination is unbound") {
JsonVariant unboundVariant;

View File

@ -18,17 +18,6 @@ TEST_CASE("JsonVariant::createNestedObject()") {
REQUIRE(variant[0]["value"] == 42);
REQUIRE(obj.isNull() == false);
}
SECTION("does nothing on linked array") {
StaticJsonDocument<128> doc2;
doc2[0] = 42;
variant.link(doc2);
variant.createNestedObject();
CHECK(variant.size() == 1);
CHECK(variant[0] == 42);
}
}
TEST_CASE("JsonVariant::createNestedArray()") {
@ -41,17 +30,6 @@ TEST_CASE("JsonVariant::createNestedArray()") {
REQUIRE(variant.is<JsonArray>() == true);
REQUIRE(arr.isNull() == false);
}
SECTION("does nothing on linked array") {
StaticJsonDocument<128> doc2;
doc2[0] = 42;
variant.link(doc2);
variant.createNestedArray();
CHECK(variant.size() == 1);
CHECK(variant[0] == 42);
}
}
TEST_CASE("JsonVariant::createNestedObject(key)") {
@ -65,17 +43,6 @@ TEST_CASE("JsonVariant::createNestedObject(key)") {
REQUIRE(variant.is<JsonObject>() == true);
REQUIRE(variant["weather"]["temp"] == 42);
}
SECTION("does nothing on linked object") {
StaticJsonDocument<128> doc2;
doc2["hello"] = "world";
variant.link(doc2);
variant.createNestedObject("weather");
CHECK(variant.size() == 1);
CHECK(variant["hello"] == "world");
}
}
TEST_CASE("JsonVariant::createNestedArray(key)") {
@ -88,15 +55,4 @@ TEST_CASE("JsonVariant::createNestedArray(key)") {
REQUIRE(variant.is<JsonObject>() == true);
REQUIRE(arr.isNull() == false);
}
SECTION("does nothing on linked object") {
StaticJsonDocument<128> doc2;
doc2["hello"] = "world";
variant.link(doc2);
variant.createNestedArray("items");
CHECK(variant.size() == 1);
CHECK(variant["hello"] == "world");
}
}

View File

@ -144,24 +144,6 @@ TEST_CASE("JsonVariant::is<T>()") {
CHECK(variant.is<MYENUM2>() == false);
}
SECTION("linked array") {
StaticJsonDocument<1024> doc2;
doc2[0] = "world";
variant.link(doc2);
CHECK(variant.is<JsonArray>() == false);
CHECK(variant.is<JsonArrayConst>() == true);
CHECK(variant.is<JsonVariant>() == true);
CHECK(variant.is<JsonVariantConst>() == true);
CHECK(variant.is<JsonObject>() == false);
CHECK(variant.is<JsonObjectConst>() == false);
CHECK(variant.is<int>() == false);
CHECK(variant.is<float>() == false);
CHECK(variant.is<bool>() == false);
CHECK(variant.is<const char *>() == false);
CHECK(variant.is<MYENUM2>() == false);
}
SECTION("JsonObject") {
variant.to<JsonObject>();
@ -179,44 +161,6 @@ TEST_CASE("JsonVariant::is<T>()") {
CHECK(variant.is<JsonVariant>() == true);
CHECK(variant.is<JsonVariantConst>() == true);
}
SECTION("linked object") {
StaticJsonDocument<1024> doc2;
doc2["hello"] = "world";
variant.link(doc2);
CHECK(variant.is<JsonObject>() == false);
CHECK(variant.is<JsonObjectConst>() == true);
CHECK(variant.is<JsonVariant>() == true);
CHECK(variant.is<JsonVariantConst>() == true);
CHECK(variant.is<JsonArray>() == false);
CHECK(variant.is<JsonArrayConst>() == false);
CHECK(variant.is<int>() == false);
CHECK(variant.is<float>() == false);
CHECK(variant.is<bool>() == false);
CHECK(variant.is<const char *>() == false);
CHECK(variant.is<MYENUM2>() == false);
CHECK(variant.is<JsonVariant>() == true);
CHECK(variant.is<JsonVariantConst>() == true);
}
SECTION("linked int") {
StaticJsonDocument<1024> doc2;
doc2.set(42);
variant.link(doc2);
CHECK(variant.is<JsonObjectConst>() == false);
CHECK(variant.is<JsonVariantConst>() == true);
CHECK(variant.is<JsonObject>() == false);
CHECK(variant.is<JsonVariant>() == true);
CHECK(variant.is<JsonArray>() == false);
CHECK(variant.is<JsonArrayConst>() == false);
CHECK(variant.is<int>() == true);
CHECK(variant.is<float>() == true);
CHECK(variant.is<bool>() == false);
CHECK(variant.is<const char *>() == false);
CHECK(variant.is<MYENUM2>() == true);
}
}
TEST_CASE("JsonVariantConst::is<T>()") {
@ -372,58 +316,4 @@ TEST_CASE("JsonVariantConst::is<T>()") {
CHECK(cvariant.is<const char *>() == false);
CHECK(cvariant.is<MYENUM2>() == false);
}
SECTION("linked array") {
StaticJsonDocument<1024> doc2;
doc2[0] = "world";
variant.link(doc2);
CHECK(cvariant.is<JsonArrayConst>() == true);
CHECK(cvariant.is<JsonVariantConst>() == true);
CHECK(cvariant.is<JsonArray>() == false);
CHECK(cvariant.is<JsonVariant>() == false);
CHECK(cvariant.is<JsonObject>() == false);
CHECK(cvariant.is<JsonObjectConst>() == false);
CHECK(cvariant.is<int>() == false);
CHECK(cvariant.is<float>() == false);
CHECK(cvariant.is<bool>() == false);
CHECK(cvariant.is<const char *>() == false);
CHECK(cvariant.is<MYENUM2>() == false);
}
SECTION("linked object") {
StaticJsonDocument<1024> doc2;
doc2["hello"] = "world";
variant.link(doc2);
CHECK(cvariant.is<JsonObjectConst>() == true);
CHECK(cvariant.is<JsonVariantConst>() == true);
CHECK(cvariant.is<JsonObject>() == false);
CHECK(cvariant.is<JsonVariant>() == false);
CHECK(cvariant.is<JsonArray>() == false);
CHECK(cvariant.is<JsonArrayConst>() == false);
CHECK(cvariant.is<int>() == false);
CHECK(cvariant.is<float>() == false);
CHECK(cvariant.is<bool>() == false);
CHECK(cvariant.is<const char *>() == false);
CHECK(cvariant.is<MYENUM2>() == false);
}
SECTION("linked int") {
StaticJsonDocument<1024> doc2;
doc2.set(42);
variant.link(doc2);
CHECK(cvariant.is<JsonObjectConst>() == false);
CHECK(cvariant.is<JsonVariantConst>() == true);
CHECK(cvariant.is<JsonObject>() == false);
CHECK(cvariant.is<JsonVariant>() == false);
CHECK(cvariant.is<JsonArray>() == false);
CHECK(cvariant.is<JsonArrayConst>() == false);
CHECK(cvariant.is<int>() == true);
CHECK(cvariant.is<float>() == true);
CHECK(cvariant.is<bool>() == false);
CHECK(cvariant.is<const char *>() == false);
CHECK(cvariant.is<MYENUM2>() == true);
}
}

View File

@ -70,16 +70,16 @@ TEST_CASE("JsonVariant::isNull()") {
REQUIRE(variant.isNull() == true);
}
SECTION("returns true for a linked null") {
SECTION("returns true for a shallow null copy") {
StaticJsonDocument<128> doc2;
variant.link(doc2);
variant.shallowCopy(doc2);
CHECK(variant.isNull() == true);
}
SECTION("returns false for a linked array") {
SECTION("returns false for a shallow array copy") {
StaticJsonDocument<128> doc2;
doc2[0] = 42;
variant.link(doc2);
variant.shallowCopy(doc2);
CHECK(variant.isNull() == false);
}

View File

@ -38,12 +38,4 @@ TEST_CASE("JsonVariant::memoryUsage()") {
REQUIRE(var.memoryUsage() == 6);
REQUIRE(var.memoryUsage() == doc.memoryUsage());
}
SECTION("ignore size of linked document") {
StaticJsonDocument<128> doc2;
doc2["hello"] = "world";
var.link(doc2);
CHECK(var.memoryUsage() == 0);
CHECK(var.memoryUsage() == doc.memoryUsage());
}
}

View File

@ -28,12 +28,4 @@ TEST_CASE("JsonVariant::nesting()") {
var.to<JsonArray>();
REQUIRE(var.nesting() == 1);
}
SECTION("returns depth of linked array") {
StaticJsonDocument<128> doc2;
doc2[0][0] = 42;
var.link(doc2);
CHECK(var.nesting() == 2);
}
}

View File

@ -156,12 +156,4 @@ TEST_CASE("JsonVariant::operator|()") {
int result = variant | 42;
REQUIRE(result == 42);
}
SECTION("linked int | int") {
StaticJsonDocument<128> doc2;
doc2.set(42);
variant.link(doc2);
int result = variant | 666;
CHECK(result == 42);
}
}

View File

@ -39,24 +39,4 @@ TEST_CASE("JsonVariant::remove()") {
REQUIRE(var.as<std::string>() == "{\"a\":1}");
}
SECTION("linked array") {
StaticJsonDocument<128> doc2;
doc2[0] = 42;
var.link(doc2);
var.remove(0);
CHECK(var.as<std::string>() == "[42]");
}
SECTION("linked object") {
StaticJsonDocument<128> doc2;
doc2["hello"] = "world";
var.link(doc2);
var.remove("hello");
CHECK(var.as<std::string>() == "{\"hello\":\"world\"}");
}
}

View File

@ -5,17 +5,16 @@
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonVariant::link()") {
TEST_CASE("JsonVariant::shallowCopy()") {
StaticJsonDocument<1024> doc1, doc2;
JsonVariant variant = doc1.to<JsonVariant>();
SECTION("JsonVariant::link(JsonDocument&)") {
SECTION("JsonVariant::shallowCopy(JsonDocument&)") {
doc2["hello"] = "world";
variant.link(doc2);
variant.shallowCopy(doc2);
CHECK(variant.as<std::string>() == "{\"hello\":\"world\"}");
CHECK(variant.memoryUsage() == 0);
// altering the linked document should change the result
doc2["hello"] = "WORLD!";
@ -23,13 +22,12 @@ TEST_CASE("JsonVariant::link()") {
CHECK(variant.as<std::string>() == "{\"hello\":\"WORLD!\"}");
}
SECTION("JsonVariant::link(MemberProxy)") {
SECTION("JsonVariant::shallowCopy(MemberProxy)") {
doc2["obj"]["hello"] = "world";
variant.link(doc2["obj"]);
variant.shallowCopy(doc2["obj"]);
CHECK(variant.as<std::string>() == "{\"hello\":\"world\"}");
CHECK(variant.memoryUsage() == 0);
// altering the linked document should change the result
doc2["obj"]["hello"] = "WORLD!";
@ -37,13 +35,12 @@ TEST_CASE("JsonVariant::link()") {
CHECK(variant.as<std::string>() == "{\"hello\":\"WORLD!\"}");
}
SECTION("JsonVariant::link(ElementProxy)") {
SECTION("JsonVariant::shallowCopy(ElementProxy)") {
doc2[0]["hello"] = "world";
variant.link(doc2[0]);
variant.shallowCopy(doc2[0]);
CHECK(variant.as<std::string>() == "{\"hello\":\"world\"}");
CHECK(variant.memoryUsage() == 0);
// altering the linked document should change the result
doc2[0]["hello"] = "WORLD!";
@ -55,7 +52,7 @@ TEST_CASE("JsonVariant::link()") {
JsonVariant unbound;
variant["hello"] = "world";
variant.link(unbound);
variant.shallowCopy(unbound);
CHECK(variant.isUnbound() == false);
CHECK(variant.isNull() == true);
@ -67,11 +64,24 @@ TEST_CASE("JsonVariant::link()") {
JsonVariant unbound;
doc2["hello"] = "world";
unbound.link(doc2);
unbound.shallowCopy(doc2);
CHECK(unbound.isUnbound() == true);
CHECK(unbound.isNull() == true);
CHECK(unbound.memoryUsage() == 0);
CHECK(unbound.size() == 0);
}
SECTION("preserves owned key bit") {
doc2.set(42);
doc1["a"].shallowCopy(doc2);
doc1[std::string("b")].shallowCopy(doc2);
JsonObject::iterator it = doc1.as<JsonObject>().begin();
CHECK(it->key().isLinked() == true);
++it;
CHECK(it->key().isLinked() == false);
}
}

View File

@ -33,21 +33,4 @@ TEST_CASE("JsonVariant::size()") {
CHECK(variant.size() == 2);
}
SECTION("linked object") {
StaticJsonDocument<1024> doc2;
doc2["hello"] = "world";
variant.link(doc2);
CHECK(variant.size() == 1);
}
SECTION("linked array") {
StaticJsonDocument<1024> doc2;
doc2.add(1);
doc2.add(2);
variant.link(doc2);
CHECK(variant.size() == 2);
}
}

View File

@ -129,44 +129,6 @@ TEST_CASE("JsonVariant::operator[]") {
REQUIRE(std::string("world") == variant[vla]);
}
#endif
SECTION("get value from linked object") {
StaticJsonDocument<1024> doc2;
doc2["hello"] = "world";
var.link(doc2);
CHECK(var["hello"].as<std::string>() == "world");
}
SECTION("set value to linked object") {
StaticJsonDocument<1024> doc2;
doc2["hello"] = "world";
var.link(doc2);
var["tutu"] = "toto"; // no-op
CHECK(doc.as<std::string>() == "{\"hello\":\"world\"}");
CHECK(doc2.as<std::string>() == "{\"hello\":\"world\"}");
}
SECTION("get value from linked array") {
StaticJsonDocument<1024> doc2;
doc2.add(42);
var.link(doc2);
CHECK(var[0].as<int>() == 42);
}
SECTION("set value to linked array") {
StaticJsonDocument<1024> doc2;
doc2.add(42);
var.link(doc2);
var[0] = 666; // no-op
CHECK(doc.as<std::string>() == "[42]");
CHECK(doc2.as<std::string>() == "[42]");
}
}
TEST_CASE("JsonVariantConst::operator[]") {
@ -239,20 +201,4 @@ TEST_CASE("JsonVariantConst::operator[]") {
REQUIRE(var.is<JsonObject>() == false);
REQUIRE(value == 0);
}
SECTION("get value from linked object") {
StaticJsonDocument<1024> doc2;
doc2["hello"] = "world";
var.link(doc2);
CHECK(cvar["hello"].as<std::string>() == "world");
}
SECTION("get value from linked array") {
StaticJsonDocument<1024> doc2;
doc2.add(42);
var.link(doc2);
CHECK(cvar[0].as<int>() == 42);
}
}

View File

@ -202,12 +202,12 @@ struct Converter<ArrayConstRef> {
static ArrayConstRef fromJson(VariantConstRef src) {
const VariantData* data = getData(src);
return data ? data->resolve()->asArray() : 0;
return data ? data->asArray() : 0;
}
static bool checkJson(VariantConstRef src) {
const VariantData* data = getData(src);
return data && data->resolve()->isArray();
return data && data->isArray();
}
};

View File

@ -106,8 +106,8 @@ class ElementProxy : public VariantOperators<ElementProxy<TArray> >,
return getOrAddUpstreamElement().template to<T>();
}
FORCE_INLINE void link(VariantConstRef value) const {
getOrAddUpstreamElement().link(value);
FORCE_INLINE void shallowCopy(VariantConstRef value) const {
getOrAddUpstreamElement().shallowCopy(value);
}
// Replaces the value

View File

@ -17,6 +17,7 @@ inline VariantSlot* CollectionData::addSlot(MemoryPool* pool) {
return 0;
if (_tail) {
ARDUINOJSON_ASSERT(pool->owns(_tail)); // Can't alter a linked array/object
_tail->setNextNotNull(slot);
_tail = slot;
} else {

View File

@ -62,7 +62,7 @@ class JsonDocument : public VariantOperators<const JsonDocument&> {
}
size_t size() const {
return _data.resolve()->size();
return _data.size();
}
bool set(const JsonDocument& src) {

View File

@ -24,7 +24,7 @@ class JsonSerializer : public Visitor<size_t> {
const VariantSlot *slot = array.head();
while (slot != 0) {
slot->data()->resolve()->accept(*this);
slot->data()->accept(*this);
slot = slot->next();
if (slot == 0)
@ -45,7 +45,7 @@ class JsonSerializer : public Visitor<size_t> {
while (slot != 0) {
_formatter.writeString(slot->key());
write(':');
slot->data()->resolve()->accept(*this);
slot->data()->accept(*this);
slot = slot->next();
if (slot == 0)

View File

@ -25,7 +25,7 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
_nesting++;
while (slot != 0) {
indent();
slot->data()->resolve()->accept(*this);
slot->data()->accept(*this);
slot = slot->next();
base::write(slot ? ",\r\n" : "\r\n");
@ -48,7 +48,7 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
indent();
base::visitString(slot->key());
base::write(": ");
slot->data()->resolve()->accept(*this);
slot->data()->accept(*this);
slot = slot->next();
base::write(slot ? ",\r\n" : "\r\n");

View File

@ -56,7 +56,7 @@ class MsgPackSerializer : public Visitor<size_t> {
writeInteger(uint32_t(n));
}
for (const VariantSlot* slot = array.head(); slot; slot = slot->next()) {
slot->data()->resolve()->accept(*this);
slot->data()->accept(*this);
}
return bytesWritten();
}
@ -74,7 +74,7 @@ class MsgPackSerializer : public Visitor<size_t> {
}
for (const VariantSlot* slot = object.head(); slot; slot = slot->next()) {
visitString(slot->key());
slot->data()->resolve()->accept(*this);
slot->data()->accept(*this);
}
return bytesWritten();
}

View File

@ -132,8 +132,8 @@ class MemberProxy : public VariantOperators<MemberProxy<TObject, TStringRef> >,
getUpstreamMember().remove(key);
}
FORCE_INLINE void link(VariantConstRef value) {
getOrAddUpstreamMember().link(value);
FORCE_INLINE void shallowCopy(VariantConstRef value) {
getOrAddUpstreamMember().shallowCopy(value);
}
template <typename TValue>

View File

@ -269,12 +269,12 @@ struct Converter<ObjectConstRef> {
static ObjectConstRef fromJson(VariantConstRef src) {
const VariantData* data = getData(src);
return data != 0 ? data->resolve()->asObject() : 0;
return data != 0 ? data->asObject() : 0;
}
static bool checkJson(VariantConstRef src) {
const VariantData* data = getData(src);
return data && data->resolve()->isObject();
return data && data->isObject();
}
};

View File

@ -48,12 +48,12 @@ struct Converter<
static T fromJson(VariantConstRef src) {
ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T);
const VariantData* data = getData(src);
return data ? data->resolve()->asIntegral<T>() : T();
return data ? data->asIntegral<T>() : T();
}
static bool checkJson(VariantConstRef src) {
const VariantData* data = getData(src);
return data && data->resolve()->isInteger<T>();
return data && data->isInteger<T>();
}
};
@ -65,12 +65,12 @@ struct Converter<T, typename enable_if<is_enum<T>::value>::type> {
static T fromJson(VariantConstRef src) {
const VariantData* data = getData(src);
return data ? static_cast<T>(data->resolve()->asIntegral<int>()) : T();
return data ? static_cast<T>(data->asIntegral<int>()) : T();
}
static bool checkJson(VariantConstRef src) {
const VariantData* data = getData(src);
return data && data->resolve()->isInteger<int>();
return data && data->isInteger<int>();
}
};
@ -84,12 +84,12 @@ struct Converter<bool> {
static bool fromJson(VariantConstRef src) {
const VariantData* data = getData(src);
return data ? data->resolve()->asBoolean() : false;
return data ? data->asBoolean() : false;
}
static bool checkJson(VariantConstRef src) {
const VariantData* data = getData(src);
return data && data->resolve()->isBoolean();
return data && data->isBoolean();
}
};
@ -103,12 +103,12 @@ struct Converter<T, typename enable_if<is_floating_point<T>::value>::type> {
static T fromJson(VariantConstRef src) {
const VariantData* data = getData(src);
return data ? data->resolve()->asFloat<T>() : 0;
return data ? data->asFloat<T>() : 0;
}
static bool checkJson(VariantConstRef src) {
const VariantData* data = getData(src);
return data && data->resolve()->isFloat();
return data && data->isFloat();
}
};
@ -121,12 +121,12 @@ struct Converter<const char*> {
static const char* fromJson(VariantConstRef src) {
const VariantData* data = getData(src);
return data ? data->resolve()->asString().c_str() : 0;
return data ? data->asString().c_str() : 0;
}
static bool checkJson(VariantConstRef src) {
const VariantData* data = getData(src);
return data && data->resolve()->isString();
return data && data->isString();
}
};
@ -139,12 +139,12 @@ struct Converter<String> {
static String fromJson(VariantConstRef src) {
const VariantData* data = getData(src);
return data ? data->resolve()->asString() : 0;
return data ? data->asString() : 0;
}
static bool checkJson(VariantConstRef src) {
const VariantData* data = getData(src);
return data && data->resolve()->isString();
return data && data->isString();
}
};
@ -192,7 +192,7 @@ struct Converter<decltype(nullptr)> {
}
static bool checkJson(VariantConstRef src) {
const VariantData* data = getData(src);
return data == 0 || data->resolve()->isNull();
return data == 0 || data->isNull();
}
};

View File

@ -31,8 +31,6 @@ enum {
VALUE_IS_SIGNED_INTEGER = 0x0A,
VALUE_IS_FLOAT = 0x0C,
VALUE_IS_POINTER = 0x10,
COLLECTION_MASK = 0x60,
VALUE_IS_OBJECT = 0x20,
VALUE_IS_ARRAY = 0x40,
@ -51,7 +49,6 @@ union VariantContent {
UInt asUnsignedInteger;
Integer asSignedInteger;
CollectionData asCollection;
const class VariantData *asPointer;
struct {
const char *data;
size_t size;

View File

@ -37,6 +37,11 @@ class VariantData {
_flags = VALUE_IS_NULL;
}
void operator=(const VariantData &src) {
_content = src._content;
_flags = uint8_t((_flags & OWNED_KEY_BIT) | (src._flags & ~OWNED_KEY_BIT));
}
template <typename TVisitor>
typename TVisitor::result_type accept(TVisitor &visitor) const {
switch (type()) {
@ -83,12 +88,6 @@ class VariantData {
bool asBoolean() const;
const VariantData *resolve() const {
if (isPointer())
return _content.asPointer->resolve();
return this;
}
CollectionData *asArray() {
return isArray() ? &_content.asCollection : 0;
}
@ -123,10 +122,6 @@ class VariantData {
return (_flags & COLLECTION_MASK) != 0;
}
bool isPointer() const {
return type() == VALUE_IS_POINTER;
}
template <typename T>
bool isInteger() const {
switch (type()) {
@ -222,12 +217,6 @@ class VariantData {
setType(VALUE_IS_NULL);
}
void setPointer(const VariantData *p) {
ARDUINOJSON_ASSERT(p);
setType(VALUE_IS_POINTER);
_content.asPointer = p;
}
void setString(String s) {
ARDUINOJSON_ASSERT(s);
if (s.isLinked())

View File

@ -15,7 +15,7 @@ template <typename TVisitor>
inline typename TVisitor::result_type variantAccept(const VariantData *var,
TVisitor &visitor) {
if (var != 0)
return var->resolve()->accept(visitor);
return var->accept(visitor);
else
return visitor.visitNull();
}
@ -44,7 +44,7 @@ inline bool variantSetString(VariantData *var, TAdaptedString value,
}
inline size_t variantSize(const VariantData *var) {
return var != 0 ? var->resolve()->size() : 0;
return var != 0 ? var->size() : 0;
}
inline CollectionData *variantToArray(VariantData *var) {
@ -90,14 +90,14 @@ NO_INLINE VariantData *variantGetOrAddMember(VariantData *var,
}
inline bool variantIsNull(const VariantData *var) {
return var == 0 || var->resolve()->isNull();
return var == 0 || var->isNull();
}
inline size_t variantNesting(const VariantData *var) {
if (!var)
return 0;
const CollectionData *collection = var->resolve()->asCollection();
const CollectionData *collection = var->asCollection();
if (!collection)
return 0;

View File

@ -117,8 +117,7 @@ class VariantConstRef : public VariantRefBase<const VariantData>,
}
FORCE_INLINE VariantConstRef getElementConst(size_t index) const {
return VariantConstRef(_data != 0 ? _data->resolve()->getElement(index)
: 0);
return VariantConstRef(_data != 0 ? _data->getElement(index) : 0);
}
FORCE_INLINE VariantConstRef operator[](size_t index) const {
@ -129,8 +128,7 @@ class VariantConstRef : public VariantRefBase<const VariantData>,
// getMemberConst(const String&) const
template <typename TString>
FORCE_INLINE VariantConstRef getMemberConst(const TString &key) const {
return VariantConstRef(_data ? _data->resolve()->getMember(adaptString(key))
: 0);
return VariantConstRef(_data ? _data->getMember(adaptString(key)) : 0);
}
// getMemberConst(char*) const
@ -138,8 +136,7 @@ class VariantConstRef : public VariantRefBase<const VariantData>,
// getMemberConst(const __FlashStringHelper*) const
template <typename TChar>
FORCE_INLINE VariantConstRef getMemberConst(TChar *key) const {
return VariantConstRef(_data ? _data->resolve()->getMember(adaptString(key))
: 0);
return VariantConstRef(_data ? _data->getMember(adaptString(key)) : 0);
}
// operator[](const std::string&) const
@ -281,8 +278,7 @@ class VariantRef : public VariantRefBase<VariantData>,
}
FORCE_INLINE VariantConstRef getElementConst(size_t index) const {
return VariantConstRef(_data != 0 ? _data->resolve()->getElement(index)
: 0);
return VariantConstRef(_data != 0 ? _data->getElement(index) : 0);
}
FORCE_INLINE VariantRef getOrAddElement(size_t index) const {
@ -310,8 +306,7 @@ class VariantRef : public VariantRefBase<VariantData>,
// getMemberConst(const __FlashStringHelper*) const
template <typename TChar>
FORCE_INLINE VariantConstRef getMemberConst(TChar *key) const {
return VariantConstRef(_data ? _data->resolve()->getMember(adaptString(key))
: 0);
return VariantConstRef(_data ? _data->getMember(adaptString(key)) : 0);
}
// getMemberConst(const std::string&) const
@ -320,8 +315,7 @@ class VariantRef : public VariantRefBase<VariantData>,
FORCE_INLINE
typename enable_if<IsString<TString>::value, VariantConstRef>::type
getMemberConst(const TString &key) const {
return VariantConstRef(_data ? _data->resolve()->getMember(adaptString(key))
: 0);
return VariantConstRef(_data ? _data->getMember(adaptString(key)) : 0);
}
// getOrAddMember(char*) const
@ -361,12 +355,12 @@ class VariantRef : public VariantRefBase<VariantData>,
_data->remove(adaptString(key));
}
inline void link(VariantConstRef target) {
inline void shallowCopy(VariantConstRef target) {
if (!_data)
return;
const VariantData *targetData = getData(target);
if (targetData)
_data->setPointer(targetData);
*_data = *targetData;
else
_data->setNull();
}