forked from bblanchon/ArduinoJson
Added comparisons between JsonVariant
s
This commit is contained in:
@ -1,6 +1,11 @@
|
|||||||
ArduinoJson: change log
|
ArduinoJson: change log
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
|
HEAD
|
||||||
|
----
|
||||||
|
|
||||||
|
* Added comparisons (`>`, `>=`, `==`, `!=`, `<`, and `<=`) between `JsonVariant`s
|
||||||
|
|
||||||
v6.15.2 (2020-05-15)
|
v6.15.2 (2020-05-15)
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
@ -10,19 +10,39 @@ using namespace ARDUINOJSON_NAMESPACE;
|
|||||||
TEST_CASE("ElementProxy::operator==()") {
|
TEST_CASE("ElementProxy::operator==()") {
|
||||||
DynamicJsonDocument doc(4096);
|
DynamicJsonDocument doc(4096);
|
||||||
|
|
||||||
SECTION("same value") {
|
SECTION("1 vs 1") {
|
||||||
doc.add(1);
|
doc.add(1);
|
||||||
doc.add(1);
|
doc.add(1);
|
||||||
|
|
||||||
|
REQUIRE(doc[0] <= doc[1]);
|
||||||
REQUIRE(doc[0] == doc[1]);
|
REQUIRE(doc[0] == doc[1]);
|
||||||
|
REQUIRE(doc[0] >= doc[1]);
|
||||||
REQUIRE_FALSE(doc[0] != doc[1]);
|
REQUIRE_FALSE(doc[0] != doc[1]);
|
||||||
|
REQUIRE_FALSE(doc[0] < doc[1]);
|
||||||
|
REQUIRE_FALSE(doc[0] > doc[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("different values") {
|
SECTION("1 vs 2") {
|
||||||
doc.add(1);
|
doc.add(1);
|
||||||
doc.add(2);
|
doc.add(2);
|
||||||
|
|
||||||
REQUIRE_FALSE(doc[0] == doc[1]);
|
|
||||||
REQUIRE(doc[0] != doc[1]);
|
REQUIRE(doc[0] != doc[1]);
|
||||||
|
REQUIRE(doc[0] < doc[1]);
|
||||||
|
REQUIRE(doc[0] <= doc[1]);
|
||||||
|
REQUIRE_FALSE(doc[0] == doc[1]);
|
||||||
|
REQUIRE_FALSE(doc[0] > doc[1]);
|
||||||
|
REQUIRE_FALSE(doc[0] >= doc[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("'abc' vs 'bcd'") {
|
||||||
|
doc.add("abc");
|
||||||
|
doc.add("bcd");
|
||||||
|
|
||||||
|
REQUIRE(doc[0] != doc[1]);
|
||||||
|
REQUIRE(doc[0] < doc[1]);
|
||||||
|
REQUIRE(doc[0] <= doc[1]);
|
||||||
|
REQUIRE_FALSE(doc[0] == doc[1]);
|
||||||
|
REQUIRE_FALSE(doc[0] > doc[1]);
|
||||||
|
REQUIRE_FALSE(doc[0] >= doc[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,460 +5,276 @@
|
|||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <catch.hpp>
|
#include <catch.hpp>
|
||||||
|
|
||||||
template <typename T>
|
// Most code is already covered by arithmeticCompare.cpp.
|
||||||
void checkEquals(T a, T b) {
|
// Here, we're just filling the holes
|
||||||
DynamicJsonDocument doc(4096);
|
|
||||||
JsonVariant variant = doc.to<JsonVariant>();
|
|
||||||
variant.set(a);
|
|
||||||
|
|
||||||
REQUIRE(b == variant);
|
TEST_CASE("Compare JsonVariant with value") {
|
||||||
REQUIRE(variant == b);
|
|
||||||
REQUIRE(b <= variant);
|
|
||||||
REQUIRE(variant <= b);
|
|
||||||
REQUIRE(b >= variant);
|
|
||||||
REQUIRE(variant >= b);
|
|
||||||
|
|
||||||
REQUIRE_FALSE(b != variant);
|
|
||||||
REQUIRE_FALSE(variant != b);
|
|
||||||
REQUIRE_FALSE(b > variant);
|
|
||||||
REQUIRE_FALSE(variant > b);
|
|
||||||
REQUIRE_FALSE(b < variant);
|
|
||||||
REQUIRE_FALSE(variant < b);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void checkGreater(T a, T b) {
|
|
||||||
DynamicJsonDocument doc(4096);
|
|
||||||
JsonVariant variant = doc.to<JsonVariant>();
|
|
||||||
variant.set(a);
|
|
||||||
|
|
||||||
REQUIRE(variant > b);
|
|
||||||
REQUIRE(b < variant);
|
|
||||||
REQUIRE(variant != b);
|
|
||||||
REQUIRE(b != variant);
|
|
||||||
|
|
||||||
REQUIRE_FALSE(variant < b);
|
|
||||||
REQUIRE_FALSE(b > variant);
|
|
||||||
REQUIRE_FALSE(variant == b);
|
|
||||||
REQUIRE_FALSE(b == variant);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void checkLower(T a, T b) {
|
|
||||||
DynamicJsonDocument doc(4096);
|
|
||||||
JsonVariant variant = doc.to<JsonVariant>();
|
|
||||||
variant.set(a);
|
|
||||||
|
|
||||||
REQUIRE(variant < b);
|
|
||||||
REQUIRE(b > variant);
|
|
||||||
REQUIRE(variant != b);
|
|
||||||
REQUIRE(b != variant);
|
|
||||||
|
|
||||||
REQUIRE_FALSE(variant > b);
|
|
||||||
REQUIRE_FALSE(b < variant);
|
|
||||||
REQUIRE_FALSE(variant == b);
|
|
||||||
REQUIRE_FALSE(b == variant);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void checkComparisons(T low, T mid, T high) {
|
|
||||||
checkEquals(mid, mid);
|
|
||||||
checkGreater(mid, low);
|
|
||||||
checkLower(mid, high);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("JsonVariant comparisons") {
|
|
||||||
static const char* null = 0;
|
|
||||||
|
|
||||||
SECTION("Double") {
|
|
||||||
checkComparisons<double>(123.44, 123.45, 123.46);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("Float") {
|
|
||||||
checkComparisons<float>(123.44f, 123.45f, 123.46f);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("SChar") {
|
|
||||||
checkComparisons<signed char>(122, 123, 124);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("SInt") {
|
|
||||||
checkComparisons<signed int>(122, 123, 124);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("SLong") {
|
|
||||||
checkComparisons<signed long>(122L, 123L, 124L);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("SShort") {
|
|
||||||
checkComparisons<signed short>(122, 123, 124);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("UChar") {
|
|
||||||
checkComparisons<unsigned char>(122, 123, 124);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("UInt") {
|
|
||||||
checkComparisons<unsigned int>(122, 123, 124);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("ULong") {
|
|
||||||
checkComparisons<unsigned long>(122L, 123L, 124L);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("UShort") {
|
|
||||||
checkComparisons<unsigned short>(122, 123, 124);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("null") {
|
|
||||||
DynamicJsonDocument doc(4096);
|
|
||||||
JsonVariant variant = doc.to<JsonVariant>();
|
|
||||||
variant.set(null);
|
|
||||||
|
|
||||||
REQUIRE(variant == variant);
|
|
||||||
REQUIRE_FALSE(variant != variant);
|
|
||||||
|
|
||||||
REQUIRE(variant == null);
|
|
||||||
REQUIRE_FALSE(variant != null);
|
|
||||||
|
|
||||||
REQUIRE(variant != "null");
|
|
||||||
REQUIRE_FALSE(variant == "null");
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("StringLiteral") {
|
|
||||||
DynamicJsonDocument doc(4096);
|
|
||||||
deserializeJson(doc, "\"hello\"");
|
|
||||||
JsonVariant variant = doc.as<JsonVariant>();
|
|
||||||
|
|
||||||
REQUIRE(variant == variant);
|
|
||||||
REQUIRE_FALSE(variant != variant);
|
|
||||||
|
|
||||||
REQUIRE(variant == "hello");
|
|
||||||
REQUIRE_FALSE(variant != "hello");
|
|
||||||
|
|
||||||
REQUIRE(variant != "world");
|
|
||||||
REQUIRE_FALSE(variant == "world");
|
|
||||||
|
|
||||||
REQUIRE(variant != null);
|
|
||||||
REQUIRE_FALSE(variant == null);
|
|
||||||
|
|
||||||
REQUIRE("hello" == variant);
|
|
||||||
REQUIRE_FALSE("hello" != variant);
|
|
||||||
|
|
||||||
REQUIRE("world" != variant);
|
|
||||||
REQUIRE_FALSE("world" == variant);
|
|
||||||
|
|
||||||
REQUIRE(null != variant);
|
|
||||||
REQUIRE_FALSE(null == variant);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("String") {
|
|
||||||
DynamicJsonDocument doc(4096);
|
|
||||||
JsonVariant variant = doc.to<JsonVariant>();
|
|
||||||
variant.set("hello");
|
|
||||||
|
|
||||||
REQUIRE(variant == variant);
|
|
||||||
REQUIRE_FALSE(variant != variant);
|
|
||||||
|
|
||||||
REQUIRE(variant == std::string("hello"));
|
|
||||||
REQUIRE_FALSE(variant != std::string("hello"));
|
|
||||||
|
|
||||||
REQUIRE(variant != std::string("world"));
|
|
||||||
REQUIRE_FALSE(variant == std::string("world"));
|
|
||||||
|
|
||||||
REQUIRE(variant != null);
|
|
||||||
REQUIRE_FALSE(variant == null);
|
|
||||||
|
|
||||||
REQUIRE(std::string("hello") == variant);
|
|
||||||
REQUIRE_FALSE(std::string("hello") != variant);
|
|
||||||
|
|
||||||
REQUIRE(std::string("world") != variant);
|
|
||||||
REQUIRE_FALSE(std::string("world") == variant);
|
|
||||||
|
|
||||||
REQUIRE(null != variant);
|
|
||||||
REQUIRE_FALSE(null == variant);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
|
||||||
SECTION("VLA equals") {
|
|
||||||
int i = 16;
|
|
||||||
char vla[i];
|
|
||||||
strcpy(vla, "hello");
|
|
||||||
|
|
||||||
DynamicJsonDocument doc(4096);
|
|
||||||
JsonVariant variant = doc.to<JsonVariant>();
|
|
||||||
variant.set("hello");
|
|
||||||
|
|
||||||
REQUIRE((vla == variant));
|
|
||||||
REQUIRE((variant == vla));
|
|
||||||
REQUIRE_FALSE((vla != variant));
|
|
||||||
REQUIRE_FALSE((variant != vla));
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("VLA differs") {
|
|
||||||
int i = 16;
|
|
||||||
char vla[i];
|
|
||||||
strcpy(vla, "hello");
|
|
||||||
|
|
||||||
DynamicJsonDocument doc(4096);
|
|
||||||
JsonVariant variant = doc.to<JsonVariant>();
|
|
||||||
variant.set("world");
|
|
||||||
|
|
||||||
REQUIRE((vla != variant));
|
|
||||||
REQUIRE((variant != vla));
|
|
||||||
REQUIRE_FALSE((vla == variant));
|
|
||||||
REQUIRE_FALSE((variant == vla));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
DynamicJsonDocument doc1(4096), doc2(4096), doc3(4096);
|
|
||||||
JsonVariant variant1 = doc1.to<JsonVariant>();
|
|
||||||
JsonVariant variant2 = doc2.to<JsonVariant>();
|
|
||||||
JsonVariant variant3 = doc3.to<JsonVariant>();
|
|
||||||
|
|
||||||
SECTION("Variants containing integers") {
|
|
||||||
variant1.set(42);
|
|
||||||
variant2.set(42);
|
|
||||||
variant3.set(666);
|
|
||||||
|
|
||||||
REQUIRE(variant1 == variant2);
|
|
||||||
REQUIRE_FALSE(variant1 != variant2);
|
|
||||||
|
|
||||||
REQUIRE(variant1 != variant3);
|
|
||||||
REQUIRE_FALSE(variant1 == variant3);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("Variants containing linked strings") {
|
|
||||||
// create two identical strings at different addresses
|
|
||||||
char hello1[] = "hello";
|
|
||||||
char hello2[] = "hello";
|
|
||||||
REQUIRE(hello1 != hello2);
|
|
||||||
|
|
||||||
variant1.set(hello1);
|
|
||||||
variant2.set(hello2);
|
|
||||||
variant3.set("world");
|
|
||||||
|
|
||||||
REQUIRE(variant1 == variant2);
|
|
||||||
REQUIRE_FALSE(variant1 != variant2);
|
|
||||||
|
|
||||||
REQUIRE(variant1 != variant3);
|
|
||||||
REQUIRE_FALSE(variant1 == variant3);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("Variants containing owned strings") {
|
|
||||||
variant1.set(std::string("hello"));
|
|
||||||
variant2.set(std::string("hello"));
|
|
||||||
variant3.set(std::string("world"));
|
|
||||||
|
|
||||||
REQUIRE(variant1 == variant2);
|
|
||||||
REQUIRE_FALSE(variant1 != variant2);
|
|
||||||
|
|
||||||
REQUIRE(variant1 != variant3);
|
|
||||||
REQUIRE_FALSE(variant1 == variant3);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("Variants containing linked raws") {
|
|
||||||
// create two identical strings at different addresses
|
|
||||||
char hello1[] = "hello";
|
|
||||||
char hello2[] = "hello";
|
|
||||||
REQUIRE(hello1 != hello2);
|
|
||||||
|
|
||||||
variant1.set(serialized(hello1));
|
|
||||||
variant2.set(serialized(hello2));
|
|
||||||
variant3.set(serialized("world"));
|
|
||||||
|
|
||||||
REQUIRE(variant1 == variant2);
|
|
||||||
REQUIRE_FALSE(variant1 != variant2);
|
|
||||||
|
|
||||||
REQUIRE(variant1 != variant3);
|
|
||||||
REQUIRE_FALSE(variant1 == variant3);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("Variants containing owned raws") {
|
|
||||||
variant1.set(serialized(std::string("hello")));
|
|
||||||
variant2.set(serialized(std::string("hello")));
|
|
||||||
variant3.set(serialized(std::string("world")));
|
|
||||||
|
|
||||||
REQUIRE(variant1 == variant2);
|
|
||||||
REQUIRE_FALSE(variant1 != variant2);
|
|
||||||
|
|
||||||
REQUIRE(variant1 != variant3);
|
|
||||||
REQUIRE_FALSE(variant1 == variant3);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("Variants containing mixed strings (issue #1051)") {
|
|
||||||
variant1.set("hello");
|
|
||||||
variant2.set(std::string("hello"));
|
|
||||||
|
|
||||||
REQUIRE(variant1 == variant2);
|
|
||||||
REQUIRE_FALSE(variant1 != variant2);
|
|
||||||
|
|
||||||
REQUIRE(variant2 == variant1);
|
|
||||||
REQUIRE_FALSE(variant2 != variant1);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("Variants containing double") {
|
|
||||||
variant1.set(42.0);
|
|
||||||
variant2.set(42.0);
|
|
||||||
variant3.set(666.0);
|
|
||||||
|
|
||||||
REQUIRE(variant1 == variant2);
|
|
||||||
REQUIRE_FALSE(variant1 != variant2);
|
|
||||||
|
|
||||||
REQUIRE(variant1 != variant3);
|
|
||||||
REQUIRE_FALSE(variant1 == variant3);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("BoolInVariant") {
|
|
||||||
variant1.set(true);
|
|
||||||
variant2.set(true);
|
|
||||||
variant3.set(false);
|
|
||||||
|
|
||||||
REQUIRE(variant1 == variant2);
|
|
||||||
REQUIRE_FALSE(variant1 != variant2);
|
|
||||||
|
|
||||||
REQUIRE(variant1 != variant3);
|
|
||||||
REQUIRE_FALSE(variant1 == variant3);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("ArrayInVariant") {
|
|
||||||
JsonArray array1 = variant1.to<JsonArray>();
|
|
||||||
JsonArray array2 = variant2.to<JsonArray>();
|
|
||||||
|
|
||||||
array1.add(42);
|
|
||||||
array2.add(42);
|
|
||||||
|
|
||||||
REQUIRE(variant1 == variant2);
|
|
||||||
REQUIRE_FALSE(variant1 != variant2);
|
|
||||||
|
|
||||||
REQUIRE(variant1 != variant3);
|
|
||||||
REQUIRE_FALSE(variant1 == variant3);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTION("ObjectInVariant") {
|
|
||||||
JsonObject obj1 = variant1.to<JsonObject>();
|
|
||||||
JsonObject obj2 = variant2.to<JsonObject>();
|
|
||||||
|
|
||||||
obj1["hello"] = "world";
|
|
||||||
obj2["hello"] = "world";
|
|
||||||
|
|
||||||
REQUIRE(variant1 == variant2);
|
|
||||||
REQUIRE_FALSE(variant1 != variant2);
|
|
||||||
|
|
||||||
REQUIRE(variant1 != variant3);
|
|
||||||
REQUIRE_FALSE(variant1 == variant3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class VariantComparisionFixture {
|
|
||||||
private:
|
|
||||||
StaticJsonDocument<256> doc;
|
StaticJsonDocument<256> doc;
|
||||||
JsonVariant variant;
|
JsonVariant a = doc.addElement();
|
||||||
|
|
||||||
public:
|
SECTION("null vs (char*)0") {
|
||||||
VariantComparisionFixture() : variant(doc.to<JsonVariant>()) {}
|
char* b = 0;
|
||||||
|
|
||||||
protected:
|
CHECK(a == b);
|
||||||
template <typename T>
|
CHECK(a <= b);
|
||||||
void setValue(const T& value) {
|
CHECK(a >= b);
|
||||||
variant.set(value);
|
CHECK_FALSE(a != b);
|
||||||
|
CHECK_FALSE(a < b);
|
||||||
|
CHECK_FALSE(a > b);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
SECTION("42 vs 42") {
|
||||||
void assertEqualsTo(const T& value) {
|
a.set(42);
|
||||||
REQUIRE(variant == value);
|
int b = 42;
|
||||||
REQUIRE(value == variant);
|
|
||||||
|
|
||||||
REQUIRE_FALSE(variant != value);
|
CHECK(a == b);
|
||||||
REQUIRE_FALSE(value != variant);
|
CHECK(a <= b);
|
||||||
}
|
CHECK(a >= b);
|
||||||
|
CHECK_FALSE(a != b);
|
||||||
template <typename T>
|
CHECK_FALSE(a < b);
|
||||||
void assertDiffersFrom(const T& value) {
|
CHECK_FALSE(a > b);
|
||||||
REQUIRE(variant != value);
|
}
|
||||||
REQUIRE(value != variant);
|
}
|
||||||
|
|
||||||
REQUIRE_FALSE(variant == value);
|
TEST_CASE("Compare JsonVariant with JsonVariant") {
|
||||||
REQUIRE_FALSE(value == variant);
|
StaticJsonDocument<256> doc;
|
||||||
}
|
JsonVariant a = doc.addElement();
|
||||||
|
JsonVariant b = doc.addElement();
|
||||||
template <typename T>
|
|
||||||
void assertGreaterThan(const T& value) {
|
SECTION("'abc' vs 'abc'") {
|
||||||
REQUIRE((variant > value));
|
a.set("abc");
|
||||||
REQUIRE((variant >= value));
|
b.set("abc");
|
||||||
REQUIRE(value < variant);
|
|
||||||
REQUIRE(value <= variant);
|
CHECK(a == b);
|
||||||
|
CHECK(a <= b);
|
||||||
REQUIRE_FALSE((variant < value));
|
CHECK(a >= b);
|
||||||
REQUIRE_FALSE((variant <= value));
|
CHECK_FALSE(a != b);
|
||||||
REQUIRE_FALSE(value > variant);
|
CHECK_FALSE(a < b);
|
||||||
REQUIRE_FALSE(value >= variant);
|
CHECK_FALSE(a > b);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
SECTION("'abc' vs 'bcd'") {
|
||||||
void assertLowerThan(const T& value) {
|
a.set("abc");
|
||||||
REQUIRE(variant < value);
|
b.set("bcd");
|
||||||
REQUIRE(variant <= value);
|
|
||||||
REQUIRE(value > variant);
|
CHECK(a != b);
|
||||||
REQUIRE(value >= variant);
|
CHECK(a < b);
|
||||||
|
CHECK(a <= b);
|
||||||
REQUIRE_FALSE(variant > value);
|
CHECK_FALSE(a == b);
|
||||||
REQUIRE_FALSE(variant >= value);
|
CHECK_FALSE(a > b);
|
||||||
REQUIRE_FALSE(value < variant);
|
CHECK_FALSE(a >= b);
|
||||||
REQUIRE_FALSE(value <= variant);
|
}
|
||||||
}
|
|
||||||
};
|
SECTION("'bcd' vs 'abc'") {
|
||||||
|
a.set("bcd");
|
||||||
TEST_CASE_METHOD(VariantComparisionFixture,
|
b.set("abc");
|
||||||
"Compare variant with another type") {
|
|
||||||
SECTION("null") {
|
CHECK(a != b);
|
||||||
assertDiffersFrom(3);
|
CHECK(a > b);
|
||||||
assertDiffersFrom("world");
|
CHECK(a >= b);
|
||||||
}
|
CHECK_FALSE(a < b);
|
||||||
|
CHECK_FALSE(a <= b);
|
||||||
SECTION("string") {
|
CHECK_FALSE(a == b);
|
||||||
setValue("hello");
|
}
|
||||||
assertEqualsTo("hello");
|
|
||||||
assertDiffersFrom(3);
|
SECTION("serialized('abc') vs serialized('abc')") {
|
||||||
assertDiffersFrom("world");
|
a.set(serialized("abc"));
|
||||||
assertGreaterThan("helln");
|
b.set(serialized("abc"));
|
||||||
assertLowerThan("hellp");
|
|
||||||
}
|
CHECK(a == b);
|
||||||
|
CHECK(a <= b);
|
||||||
SECTION("positive integer") {
|
CHECK(a >= b);
|
||||||
setValue(42);
|
CHECK_FALSE(a != b);
|
||||||
assertEqualsTo(42);
|
CHECK_FALSE(a < b);
|
||||||
assertDiffersFrom(43);
|
CHECK_FALSE(a > b);
|
||||||
assertGreaterThan(41);
|
}
|
||||||
assertLowerThan(43);
|
|
||||||
assertDiffersFrom("world");
|
SECTION("serialized('abc') vs serialized('bcd')") {
|
||||||
}
|
a.set(serialized("abc"));
|
||||||
|
b.set(serialized("bcd"));
|
||||||
SECTION("negative integer") {
|
|
||||||
setValue(-42);
|
CHECK(a != b);
|
||||||
assertEqualsTo(-42);
|
CHECK(a < b);
|
||||||
assertDiffersFrom(42);
|
CHECK(a <= b);
|
||||||
assertGreaterThan(-43);
|
CHECK_FALSE(a == b);
|
||||||
assertLowerThan(-41);
|
CHECK_FALSE(a > b);
|
||||||
assertDiffersFrom("world");
|
CHECK_FALSE(a >= b);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("double") {
|
SECTION("serialized('bcd') vs serialized('abc')") {
|
||||||
setValue(42.0);
|
a.set(serialized("bcd"));
|
||||||
assertEqualsTo(42.0);
|
b.set(serialized("abc"));
|
||||||
assertDiffersFrom(42.1);
|
|
||||||
assertGreaterThan(41.0);
|
CHECK(a != b);
|
||||||
assertLowerThan(43.0);
|
CHECK(a > b);
|
||||||
assertDiffersFrom("42.0");
|
CHECK(a >= b);
|
||||||
}
|
CHECK_FALSE(a < b);
|
||||||
|
CHECK_FALSE(a <= b);
|
||||||
SECTION("true") {
|
CHECK_FALSE(a == b);
|
||||||
setValue(true);
|
}
|
||||||
assertEqualsTo(true);
|
|
||||||
assertDiffersFrom(false);
|
SECTION("false vs true") {
|
||||||
assertDiffersFrom(1);
|
a.set(false);
|
||||||
assertDiffersFrom("true");
|
b.set(true);
|
||||||
assertDiffersFrom(1.0);
|
|
||||||
assertGreaterThan(false);
|
CHECK(a != b);
|
||||||
|
CHECK(a < b);
|
||||||
|
CHECK(a <= b);
|
||||||
|
CHECK_FALSE(a == b);
|
||||||
|
CHECK_FALSE(a > b);
|
||||||
|
CHECK_FALSE(a >= b);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("false vs -1") {
|
||||||
|
a.set(false);
|
||||||
|
b.set(-1);
|
||||||
|
|
||||||
|
CHECK(a != b);
|
||||||
|
CHECK(a > b);
|
||||||
|
CHECK(a >= b);
|
||||||
|
CHECK_FALSE(a < b);
|
||||||
|
CHECK_FALSE(a <= b);
|
||||||
|
CHECK_FALSE(a == b);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("null vs null") {
|
||||||
|
CHECK(a == b);
|
||||||
|
CHECK(a <= b);
|
||||||
|
CHECK(a >= b);
|
||||||
|
CHECK_FALSE(a != b);
|
||||||
|
CHECK_FALSE(a < b);
|
||||||
|
CHECK_FALSE(a > b);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("42 vs 42") {
|
||||||
|
a.set(42);
|
||||||
|
b.set(42);
|
||||||
|
|
||||||
|
CHECK(a == b);
|
||||||
|
CHECK(a <= b);
|
||||||
|
CHECK(a >= b);
|
||||||
|
CHECK_FALSE(a != b);
|
||||||
|
CHECK_FALSE(a < b);
|
||||||
|
CHECK_FALSE(a > b);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("42 vs 42.0") {
|
||||||
|
a.set(42);
|
||||||
|
b.set(42.0);
|
||||||
|
|
||||||
|
CHECK(a == b);
|
||||||
|
CHECK(a <= b);
|
||||||
|
CHECK(a >= b);
|
||||||
|
CHECK_FALSE(a != b);
|
||||||
|
CHECK_FALSE(a < b);
|
||||||
|
CHECK_FALSE(a > b);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("42.0 vs 42") {
|
||||||
|
a.set(42.0);
|
||||||
|
b.set(42);
|
||||||
|
|
||||||
|
CHECK(a == b);
|
||||||
|
CHECK(a <= b);
|
||||||
|
CHECK(a >= b);
|
||||||
|
CHECK_FALSE(a != b);
|
||||||
|
CHECK_FALSE(a < b);
|
||||||
|
CHECK_FALSE(a > b);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("-42 vs -42") {
|
||||||
|
a.set(-42);
|
||||||
|
b.set(-42);
|
||||||
|
|
||||||
|
CHECK(a == b);
|
||||||
|
CHECK(a <= b);
|
||||||
|
CHECK(a >= b);
|
||||||
|
CHECK_FALSE(a != b);
|
||||||
|
CHECK_FALSE(a < b);
|
||||||
|
CHECK_FALSE(a > b);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("-42 vs 42") {
|
||||||
|
a.set(-42);
|
||||||
|
b.set(42);
|
||||||
|
|
||||||
|
CHECK(a != b);
|
||||||
|
CHECK(a < b);
|
||||||
|
CHECK(a <= b);
|
||||||
|
CHECK_FALSE(a == b);
|
||||||
|
CHECK_FALSE(a > b);
|
||||||
|
CHECK_FALSE(a >= b);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("42 vs -42") {
|
||||||
|
a.set(42);
|
||||||
|
b.set(-42);
|
||||||
|
|
||||||
|
CHECK(a != b);
|
||||||
|
CHECK(a > b);
|
||||||
|
CHECK(a >= b);
|
||||||
|
CHECK_FALSE(a < b);
|
||||||
|
CHECK_FALSE(a <= b);
|
||||||
|
CHECK_FALSE(a == b);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("42.0 vs -42") {
|
||||||
|
a.set(42.0);
|
||||||
|
b.set(-42);
|
||||||
|
|
||||||
|
CHECK(a != b);
|
||||||
|
CHECK(a > b);
|
||||||
|
CHECK(a >= b);
|
||||||
|
CHECK_FALSE(a < b);
|
||||||
|
CHECK_FALSE(a <= b);
|
||||||
|
CHECK_FALSE(a == b);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("[1] vs [1]") {
|
||||||
|
a.add(1);
|
||||||
|
b.add(1);
|
||||||
|
|
||||||
|
CHECK(a <= b);
|
||||||
|
CHECK(a == b);
|
||||||
|
CHECK(a >= b);
|
||||||
|
CHECK_FALSE(a != b);
|
||||||
|
CHECK_FALSE(a < b);
|
||||||
|
CHECK_FALSE(a > b);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("[1] vs [2]") {
|
||||||
|
a.add(1);
|
||||||
|
b.add(2);
|
||||||
|
|
||||||
|
CHECK(a != b);
|
||||||
|
CHECK_FALSE(a < b);
|
||||||
|
CHECK_FALSE(a <= b);
|
||||||
|
CHECK_FALSE(a == b);
|
||||||
|
CHECK_FALSE(a > b);
|
||||||
|
CHECK_FALSE(a >= b);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("{x:1} vs {x:1}") {
|
||||||
|
a["x"] = 1;
|
||||||
|
b["x"] = 1;
|
||||||
|
|
||||||
|
CHECK(a <= b);
|
||||||
|
CHECK(a == b);
|
||||||
|
CHECK(a >= b);
|
||||||
|
CHECK_FALSE(a != b);
|
||||||
|
CHECK_FALSE(a < b);
|
||||||
|
CHECK_FALSE(a > b);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("{x:1} vs {x:2}") {
|
||||||
|
a["x"] = 1;
|
||||||
|
b["x"] = 2;
|
||||||
|
|
||||||
|
CHECK(a != b);
|
||||||
|
CHECK_FALSE(a < b);
|
||||||
|
CHECK_FALSE(a <= b);
|
||||||
|
CHECK_FALSE(a == b);
|
||||||
|
CHECK_FALSE(a > b);
|
||||||
|
CHECK_FALSE(a >= b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,17 +10,39 @@ using namespace ARDUINOJSON_NAMESPACE;
|
|||||||
TEST_CASE("MemberProxy::operator==()") {
|
TEST_CASE("MemberProxy::operator==()") {
|
||||||
DynamicJsonDocument doc(4096);
|
DynamicJsonDocument doc(4096);
|
||||||
|
|
||||||
SECTION("same values") {
|
SECTION("1 vs 1") {
|
||||||
doc["key1"] = "value";
|
doc["a"] = 1;
|
||||||
doc["key2"] = "value";
|
doc["b"] = 1;
|
||||||
REQUIRE(doc["key1"] == doc["key2"]);
|
|
||||||
REQUIRE_FALSE(doc["key1"] != doc["key2"]);
|
REQUIRE(doc["a"] <= doc["b"]);
|
||||||
|
REQUIRE(doc["a"] == doc["b"]);
|
||||||
|
REQUIRE(doc["a"] >= doc["b"]);
|
||||||
|
REQUIRE_FALSE(doc["a"] != doc["b"]);
|
||||||
|
REQUIRE_FALSE(doc["a"] < doc["b"]);
|
||||||
|
REQUIRE_FALSE(doc["a"] > doc["b"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("different values") {
|
SECTION("1 vs 2") {
|
||||||
doc["key1"] = "value1";
|
doc["a"] = 1;
|
||||||
doc["key2"] = "value2";
|
doc["b"] = 2;
|
||||||
REQUIRE_FALSE(doc["key1"] == doc["key2"]);
|
|
||||||
REQUIRE(doc["key1"] != doc["key2"]);
|
REQUIRE(doc["a"] != doc["b"]);
|
||||||
|
REQUIRE(doc["a"] < doc["b"]);
|
||||||
|
REQUIRE(doc["a"] <= doc["b"]);
|
||||||
|
REQUIRE_FALSE(doc["a"] == doc["b"]);
|
||||||
|
REQUIRE_FALSE(doc["a"] > doc["b"]);
|
||||||
|
REQUIRE_FALSE(doc["a"] >= doc["b"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("'abc' vs 'bcd'") {
|
||||||
|
doc["a"] = "abc";
|
||||||
|
doc["b"] = "bcd";
|
||||||
|
|
||||||
|
REQUIRE(doc["a"] != doc["b"]);
|
||||||
|
REQUIRE(doc["a"] < doc["b"]);
|
||||||
|
REQUIRE(doc["a"] <= doc["b"]);
|
||||||
|
REQUIRE_FALSE(doc["a"] == doc["b"]);
|
||||||
|
REQUIRE_FALSE(doc["a"] > doc["b"]);
|
||||||
|
REQUIRE_FALSE(doc["a"] >= doc["b"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
# MIT License
|
# MIT License
|
||||||
|
|
||||||
add_executable(MiscTests
|
add_executable(MiscTests
|
||||||
|
arithmeticCompare.cpp
|
||||||
conflicts.cpp
|
conflicts.cpp
|
||||||
FloatParts.cpp
|
FloatParts.cpp
|
||||||
Readers.cpp
|
Readers.cpp
|
||||||
|
@ -29,6 +29,24 @@ TEST_CASE("Polyfills/type_traits") {
|
|||||||
CHECK(is_const<const char>::value == true);
|
CHECK(is_const<const char>::value == true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("is_integral") {
|
||||||
|
CHECK(is_integral<double>::value == false);
|
||||||
|
CHECK(is_integral<float>::value == false);
|
||||||
|
|
||||||
|
CHECK(is_integral<bool>::value == true);
|
||||||
|
CHECK(is_integral<char>::value == true);
|
||||||
|
CHECK(is_integral<signed char>::value == true);
|
||||||
|
CHECK(is_integral<signed int>::value == true);
|
||||||
|
CHECK(is_integral<signed long>::value == true);
|
||||||
|
CHECK(is_integral<signed short>::value == true);
|
||||||
|
CHECK(is_integral<unsigned char>::value == true);
|
||||||
|
CHECK(is_integral<unsigned int>::value == true);
|
||||||
|
CHECK(is_integral<unsigned long>::value == true);
|
||||||
|
CHECK(is_integral<unsigned short>::value == true);
|
||||||
|
|
||||||
|
CHECK(is_integral<UInt>::value == true);
|
||||||
|
}
|
||||||
|
|
||||||
SECTION("is_signed") {
|
SECTION("is_signed") {
|
||||||
CHECK(is_signed<char>::value == true);
|
CHECK(is_signed<char>::value == true);
|
||||||
CHECK(is_signed<signed char>::value == true);
|
CHECK(is_signed<signed char>::value == true);
|
||||||
|
103
extras/tests/Misc/arithmeticCompare.cpp
Normal file
103
extras/tests/Misc/arithmeticCompare.cpp
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
// ArduinoJson - arduinojson.org
|
||||||
|
// Copyright Benoit Blanchon 2014-2020
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#include <ArduinoJson/Numbers/arithmeticCompare.hpp>
|
||||||
|
#include <catch.hpp>
|
||||||
|
|
||||||
|
using namespace ARDUINOJSON_NAMESPACE;
|
||||||
|
|
||||||
|
TEST_CASE("arithmeticCompare()") {
|
||||||
|
SECTION("int vs uint8_t") {
|
||||||
|
CHECK((arithmeticCompare<int, uint8_t>(256, 1) == COMPARE_RESULT_GREATER));
|
||||||
|
CHECK((arithmeticCompare<int, uint8_t>(41, 42) == COMPARE_RESULT_LESS));
|
||||||
|
CHECK((arithmeticCompare<int, uint8_t>(42, 42) == COMPARE_RESULT_EQUAL));
|
||||||
|
CHECK((arithmeticCompare<int, uint8_t>(43, 42) == COMPARE_RESULT_GREATER));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("unsigned vs int") {
|
||||||
|
CHECK((arithmeticCompare<unsigned, int>(0, -1) == COMPARE_RESULT_GREATER));
|
||||||
|
CHECK((arithmeticCompare<unsigned, int>(42, 41) == COMPARE_RESULT_GREATER));
|
||||||
|
CHECK((arithmeticCompare<unsigned, int>(42, 42) == COMPARE_RESULT_EQUAL));
|
||||||
|
CHECK((arithmeticCompare<unsigned, int>(42, 43) == COMPARE_RESULT_LESS));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("float vs int") {
|
||||||
|
CHECK((arithmeticCompare<float, int>(42, 41) == COMPARE_RESULT_GREATER));
|
||||||
|
CHECK((arithmeticCompare<float, int>(42, 42) == COMPARE_RESULT_EQUAL));
|
||||||
|
CHECK((arithmeticCompare<float, int>(42, 43) == COMPARE_RESULT_LESS));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("int vs unsigned") {
|
||||||
|
CHECK((arithmeticCompare<int, unsigned>(-1, 0) == COMPARE_RESULT_LESS));
|
||||||
|
CHECK((arithmeticCompare<int, unsigned>(0, 0) == COMPARE_RESULT_EQUAL));
|
||||||
|
CHECK((arithmeticCompare<int, unsigned>(1, 0) == COMPARE_RESULT_GREATER));
|
||||||
|
CHECK((arithmeticCompare<int, unsigned>(42, 41) == COMPARE_RESULT_GREATER));
|
||||||
|
CHECK((arithmeticCompare<int, unsigned>(42, 42) == COMPARE_RESULT_EQUAL));
|
||||||
|
CHECK((arithmeticCompare<int, unsigned>(42, 43) == COMPARE_RESULT_LESS));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("unsigned vs unsigned") {
|
||||||
|
CHECK((arithmeticCompare<unsigned, unsigned>(42, 41) ==
|
||||||
|
COMPARE_RESULT_GREATER));
|
||||||
|
CHECK((arithmeticCompare<unsigned, unsigned>(42, 42) ==
|
||||||
|
COMPARE_RESULT_EQUAL));
|
||||||
|
CHECK(
|
||||||
|
(arithmeticCompare<unsigned, unsigned>(42, 43) == COMPARE_RESULT_LESS));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("bool vs bool") {
|
||||||
|
CHECK(
|
||||||
|
(arithmeticCompare<bool, bool>(false, false) == COMPARE_RESULT_EQUAL));
|
||||||
|
CHECK((arithmeticCompare<bool, bool>(true, true) == COMPARE_RESULT_EQUAL));
|
||||||
|
CHECK((arithmeticCompare<bool, bool>(false, true) == COMPARE_RESULT_LESS));
|
||||||
|
CHECK(
|
||||||
|
(arithmeticCompare<bool, bool>(true, false) == COMPARE_RESULT_GREATER));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("bool vs int") {
|
||||||
|
CHECK((arithmeticCompare<bool, int>(false, -1) == COMPARE_RESULT_GREATER));
|
||||||
|
CHECK((arithmeticCompare<bool, int>(false, 0) == COMPARE_RESULT_EQUAL));
|
||||||
|
CHECK((arithmeticCompare<bool, int>(false, 1) == COMPARE_RESULT_LESS));
|
||||||
|
CHECK((arithmeticCompare<bool, int>(true, 0) == COMPARE_RESULT_GREATER));
|
||||||
|
CHECK((arithmeticCompare<bool, int>(true, 1) == COMPARE_RESULT_EQUAL));
|
||||||
|
CHECK((arithmeticCompare<bool, int>(true, 2) == COMPARE_RESULT_LESS));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("bool vs int") {
|
||||||
|
CHECK((arithmeticCompare<int, bool>(0, false) == COMPARE_RESULT_EQUAL));
|
||||||
|
CHECK((arithmeticCompare<int, bool>(1, true) == COMPARE_RESULT_EQUAL));
|
||||||
|
CHECK((arithmeticCompare<int, bool>(1, false) == COMPARE_RESULT_GREATER));
|
||||||
|
CHECK((arithmeticCompare<int, bool>(0, true) == COMPARE_RESULT_LESS));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("arithmeticCompareNegateLeft()") {
|
||||||
|
SECTION("unsigned vs int") {
|
||||||
|
CHECK((arithmeticCompareNegateLeft<int>(0, 1) == COMPARE_RESULT_LESS));
|
||||||
|
CHECK((arithmeticCompareNegateLeft<int>(42, -41) == COMPARE_RESULT_LESS));
|
||||||
|
CHECK((arithmeticCompareNegateLeft<int>(42, -42) == COMPARE_RESULT_EQUAL));
|
||||||
|
CHECK(
|
||||||
|
(arithmeticCompareNegateLeft<int>(42, -43) == COMPARE_RESULT_GREATER));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("unsigned vs unsigned") {
|
||||||
|
CHECK(
|
||||||
|
(arithmeticCompareNegateLeft<unsigned>(42, 42) == COMPARE_RESULT_LESS));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("arithmeticCompareNegateRight()") {
|
||||||
|
SECTION("int vs unsigned") {
|
||||||
|
CHECK((arithmeticCompareNegateRight<int>(1, 0) == COMPARE_RESULT_GREATER));
|
||||||
|
CHECK(
|
||||||
|
(arithmeticCompareNegateRight<int>(-41, 42) == COMPARE_RESULT_GREATER));
|
||||||
|
CHECK((arithmeticCompareNegateRight<int>(-42, 42) == COMPARE_RESULT_EQUAL));
|
||||||
|
CHECK((arithmeticCompareNegateRight<int>(-43, 42) == COMPARE_RESULT_LESS));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("unsigned vs unsigned") {
|
||||||
|
CHECK((arithmeticCompareNegateRight<unsigned>(42, 42) ==
|
||||||
|
COMPARE_RESULT_GREATER));
|
||||||
|
}
|
||||||
|
}
|
@ -53,14 +53,6 @@ class ElementProxy : public VariantOperators<ElementProxy<TArray> >,
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE bool operator==(VariantConstRef rhs) const {
|
|
||||||
return static_cast<VariantConstRef>(getUpstreamElement()) == rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
FORCE_INLINE bool operator!=(VariantConstRef rhs) const {
|
|
||||||
return static_cast<VariantConstRef>(getUpstreamElement()) != rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
FORCE_INLINE void clear() const {
|
FORCE_INLINE void clear() const {
|
||||||
getUpstreamElement().clear();
|
getUpstreamElement().clear();
|
||||||
}
|
}
|
||||||
@ -79,11 +71,6 @@ class ElementProxy : public VariantOperators<ElementProxy<TArray> >,
|
|||||||
return getUpstreamElement();
|
return getUpstreamElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
FORCE_INLINE int compare(const T& rhs) const {
|
|
||||||
return getUpstreamElement().template compare<T>(rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
FORCE_INLINE bool is() const {
|
FORCE_INLINE bool is() const {
|
||||||
return getUpstreamElement().template is<T>();
|
return getUpstreamElement().template is<T>();
|
||||||
|
@ -9,6 +9,10 @@
|
|||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
|
inline bool variantEquals(const VariantData* a, const VariantData* b) {
|
||||||
|
return variantCompare(a, b) == COMPARE_RESULT_EQUAL;
|
||||||
|
}
|
||||||
|
|
||||||
inline VariantSlot* CollectionData::addSlot(MemoryPool* pool) {
|
inline VariantSlot* CollectionData::addSlot(MemoryPool* pool) {
|
||||||
VariantSlot* slot = pool->allocVariant();
|
VariantSlot* slot = pool->allocVariant();
|
||||||
if (!slot)
|
if (!slot)
|
||||||
|
121
src/ArduinoJson/Numbers/arithmeticCompare.hpp
Normal file
121
src/ArduinoJson/Numbers/arithmeticCompare.hpp
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
// ArduinoJson - arduinojson.org
|
||||||
|
// Copyright Benoit Blanchon 2014-2020
|
||||||
|
// MIT License
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ArduinoJson/Numbers/Integer.hpp>
|
||||||
|
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||||
|
|
||||||
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
|
enum CompareResult {
|
||||||
|
COMPARE_RESULT_DIFFER = 0,
|
||||||
|
COMPARE_RESULT_EQUAL = 1,
|
||||||
|
COMPARE_RESULT_GREATER = 2,
|
||||||
|
COMPARE_RESULT_LESS = 4,
|
||||||
|
|
||||||
|
COMPARE_RESULT_GREATER_OR_EQUAL = 3,
|
||||||
|
COMPARE_RESULT_LESS_OR_EQUAL = 5
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
CompareResult arithmeticCompare(const T &lhs, const T &rhs) {
|
||||||
|
if (lhs < rhs)
|
||||||
|
return COMPARE_RESULT_LESS;
|
||||||
|
else if (lhs > rhs)
|
||||||
|
return COMPARE_RESULT_GREATER;
|
||||||
|
else
|
||||||
|
return COMPARE_RESULT_EQUAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
CompareResult arithmeticCompare(
|
||||||
|
const T1 &lhs, const T2 &rhs,
|
||||||
|
typename enable_if<is_integral<T1>::value && is_integral<T2>::value &&
|
||||||
|
sizeof(T1) < sizeof(T2),
|
||||||
|
int // Using int instead of void to avoid C2572 on
|
||||||
|
// Visual Studio 2012, 2013, and 2015
|
||||||
|
>::type * = 0) {
|
||||||
|
return arithmeticCompare<T2>(static_cast<T2>(lhs), rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
CompareResult arithmeticCompare(
|
||||||
|
const T1 &lhs, const T2 &rhs,
|
||||||
|
typename enable_if<is_integral<T1>::value && is_integral<T2>::value &&
|
||||||
|
sizeof(T2) < sizeof(T1)>::type * = 0) {
|
||||||
|
return arithmeticCompare<T1>(lhs, static_cast<T1>(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
CompareResult arithmeticCompare(
|
||||||
|
const T1 &lhs, const T2 &rhs,
|
||||||
|
typename enable_if<is_integral<T1>::value && is_integral<T2>::value &&
|
||||||
|
is_signed<T1>::value == is_signed<T2>::value &&
|
||||||
|
sizeof(T2) == sizeof(T1)>::type * = 0) {
|
||||||
|
return arithmeticCompare<T1>(lhs, static_cast<T1>(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
CompareResult arithmeticCompare(
|
||||||
|
const T1 &lhs, const T2 &rhs,
|
||||||
|
typename enable_if<is_integral<T1>::value && is_integral<T2>::value &&
|
||||||
|
is_unsigned<T1>::value && is_signed<T2>::value &&
|
||||||
|
sizeof(T2) == sizeof(T1)>::type * = 0) {
|
||||||
|
if (rhs < 0)
|
||||||
|
return COMPARE_RESULT_GREATER;
|
||||||
|
return arithmeticCompare<T1>(lhs, static_cast<T1>(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
CompareResult arithmeticCompare(
|
||||||
|
const T1 &lhs, const T2 &rhs,
|
||||||
|
typename enable_if<is_integral<T1>::value && is_integral<T2>::value &&
|
||||||
|
is_signed<T1>::value && is_unsigned<T2>::value &&
|
||||||
|
sizeof(T2) == sizeof(T1)>::type * = 0) {
|
||||||
|
if (lhs < 0)
|
||||||
|
return COMPARE_RESULT_LESS;
|
||||||
|
return arithmeticCompare<T2>(static_cast<T2>(lhs), rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
CompareResult arithmeticCompare(
|
||||||
|
const T1 &lhs, const T2 &rhs,
|
||||||
|
typename enable_if<is_floating_point<T1>::value ||
|
||||||
|
is_floating_point<T2>::value>::type * = 0) {
|
||||||
|
return arithmeticCompare<double>(static_cast<double>(lhs),
|
||||||
|
static_cast<double>(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T2>
|
||||||
|
CompareResult arithmeticCompareNegateLeft(
|
||||||
|
UInt, const T2 &, typename enable_if<is_unsigned<T2>::value>::type * = 0) {
|
||||||
|
return COMPARE_RESULT_LESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T2>
|
||||||
|
CompareResult arithmeticCompareNegateLeft(
|
||||||
|
UInt lhs, const T2 &rhs,
|
||||||
|
typename enable_if<is_signed<T2>::value>::type * = 0) {
|
||||||
|
if (rhs > 0)
|
||||||
|
return COMPARE_RESULT_LESS;
|
||||||
|
return arithmeticCompare(-rhs, static_cast<T2>(lhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1>
|
||||||
|
CompareResult arithmeticCompareNegateRight(
|
||||||
|
const T1 &, UInt, typename enable_if<is_unsigned<T1>::value>::type * = 0) {
|
||||||
|
return COMPARE_RESULT_GREATER;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1>
|
||||||
|
CompareResult arithmeticCompareNegateRight(
|
||||||
|
const T1 &lhs, UInt rhs,
|
||||||
|
typename enable_if<is_signed<T1>::value>::type * = 0) {
|
||||||
|
if (lhs > 0)
|
||||||
|
return COMPARE_RESULT_GREATER;
|
||||||
|
return arithmeticCompare(static_cast<T1>(rhs), -lhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ARDUINOJSON_NAMESPACE
|
@ -56,14 +56,6 @@ class MemberProxy : public VariantOperators<MemberProxy<TObject, TStringRef> >,
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE bool operator==(VariantConstRef rhs) const {
|
|
||||||
return static_cast<VariantConstRef>(getUpstreamMember()) == rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
FORCE_INLINE bool operator!=(VariantConstRef rhs) const {
|
|
||||||
return static_cast<VariantConstRef>(getUpstreamMember()) != rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
FORCE_INLINE void clear() const {
|
FORCE_INLINE void clear() const {
|
||||||
getUpstreamMember().clear();
|
getUpstreamMember().clear();
|
||||||
}
|
}
|
||||||
@ -82,11 +74,6 @@ class MemberProxy : public VariantOperators<MemberProxy<TObject, TStringRef> >,
|
|||||||
return getUpstreamMember();
|
return getUpstreamMember();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
FORCE_INLINE int compare(const T &rhs) const {
|
|
||||||
return getUpstreamMember().template compare<T>(rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename TValue>
|
template <typename TValue>
|
||||||
FORCE_INLINE bool is() const {
|
FORCE_INLINE bool is() const {
|
||||||
return getUpstreamMember().template is<TValue>();
|
return getUpstreamMember().template is<TValue>();
|
||||||
|
@ -16,8 +16,7 @@ template <typename T>
|
|||||||
struct is_enum {
|
struct is_enum {
|
||||||
static const bool value = is_convertible<T, int>::value &&
|
static const bool value = is_convertible<T, int>::value &&
|
||||||
!is_class<T>::value && !is_integral<T>::value &&
|
!is_class<T>::value && !is_integral<T>::value &&
|
||||||
!is_floating_point<T>::value &&
|
!is_floating_point<T>::value;
|
||||||
!is_same<T, bool>::value;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
|
@ -25,9 +25,7 @@ struct is_integral {
|
|||||||
is_same<T, signed __int64>::value ||
|
is_same<T, signed __int64>::value ||
|
||||||
is_same<T, unsigned __int64>::value ||
|
is_same<T, unsigned __int64>::value ||
|
||||||
#endif
|
#endif
|
||||||
is_same<T, char>::value;
|
is_same<T, char>::value || is_same<T, bool>::value;
|
||||||
|
|
||||||
// CAUTION: differs from std::is_integral as it doesn't include bool
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -53,8 +53,9 @@ struct VariantConstAs<ArrayRef> {
|
|||||||
// ---
|
// ---
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline typename enable_if<is_integral<T>::value, T>::type variantAs(
|
inline typename enable_if<is_integral<T>::value && !is_same<bool, T>::value,
|
||||||
const VariantData* data) {
|
T>::type
|
||||||
|
variantAs(const VariantData* data) {
|
||||||
ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T);
|
ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T);
|
||||||
return data != 0 ? data->asIntegral<T>() : T(0);
|
return data != 0 ? data->asIntegral<T>() : T(0);
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,7 @@
|
|||||||
|
|
||||||
#include <ArduinoJson/Configuration.hpp>
|
#include <ArduinoJson/Configuration.hpp>
|
||||||
#include <ArduinoJson/Misc/Visitable.hpp>
|
#include <ArduinoJson/Misc/Visitable.hpp>
|
||||||
#include <ArduinoJson/Numbers/Float.hpp>
|
#include <ArduinoJson/Numbers/arithmeticCompare.hpp>
|
||||||
#include <ArduinoJson/Numbers/Integer.hpp>
|
|
||||||
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||||
#include <ArduinoJson/Strings/IsString.hpp>
|
#include <ArduinoJson/Strings/IsString.hpp>
|
||||||
|
|
||||||
@ -15,115 +14,228 @@ namespace ARDUINOJSON_NAMESPACE {
|
|||||||
|
|
||||||
class CollectionData;
|
class CollectionData;
|
||||||
|
|
||||||
|
struct ComparerBase {
|
||||||
|
CompareResult result;
|
||||||
|
|
||||||
|
ComparerBase() : result(COMPARE_RESULT_DIFFER) {}
|
||||||
|
|
||||||
|
void visitArray(const CollectionData &) {}
|
||||||
|
void visitBoolean(bool) {}
|
||||||
|
void visitFloat(Float) {}
|
||||||
|
void visitNegativeInteger(UInt) {}
|
||||||
|
void visitNull() {}
|
||||||
|
void visitObject(const CollectionData &) {}
|
||||||
|
void visitPositiveInteger(UInt) {}
|
||||||
|
void visitRawJson(const char *, size_t) {}
|
||||||
|
void visitString(const char *) {}
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T, typename Enable = void>
|
template <typename T, typename Enable = void>
|
||||||
struct Comparer;
|
struct Comparer;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct Comparer<T, typename enable_if<IsString<T>::value>::type> {
|
struct Comparer<T, typename enable_if<IsString<T>::value>::type>
|
||||||
|
: ComparerBase {
|
||||||
T rhs;
|
T rhs;
|
||||||
int result;
|
|
||||||
|
|
||||||
explicit Comparer(T value) : rhs(value), result(1) {}
|
explicit Comparer(T value) : rhs(value) {}
|
||||||
|
|
||||||
void visitArray(const CollectionData &) {}
|
|
||||||
void visitObject(const CollectionData &) {}
|
|
||||||
void visitFloat(Float) {}
|
|
||||||
void visitString(const char *lhs) {
|
void visitString(const char *lhs) {
|
||||||
result = -adaptString(rhs).compare(lhs);
|
int i = adaptString(rhs).compare(lhs);
|
||||||
|
if (i < 0)
|
||||||
|
result = COMPARE_RESULT_GREATER;
|
||||||
|
else if (i > 0)
|
||||||
|
result = COMPARE_RESULT_LESS;
|
||||||
|
else
|
||||||
|
result = COMPARE_RESULT_EQUAL;
|
||||||
}
|
}
|
||||||
void visitRawJson(const char *, size_t) {}
|
|
||||||
void visitNegativeInteger(UInt) {}
|
|
||||||
void visitPositiveInteger(UInt) {}
|
|
||||||
void visitBoolean(bool) {}
|
|
||||||
void visitNull() {
|
void visitNull() {
|
||||||
result = adaptString(rhs).compare(NULL);
|
if (adaptString(rhs).isNull())
|
||||||
|
result = COMPARE_RESULT_EQUAL;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
template <typename T>
|
|
||||||
typename enable_if<is_signed<T>::value, int>::type sign2(const T &value) {
|
|
||||||
return value < 0 ? -1 : value > 0 ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
typename enable_if<is_unsigned<T>::value, int>::type sign2(const T &value) {
|
|
||||||
return value > 0 ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct Comparer<T, typename enable_if<is_integral<T>::value ||
|
struct Comparer<T, typename enable_if<is_integral<T>::value ||
|
||||||
is_floating_point<T>::value>::type> {
|
is_floating_point<T>::value>::type>
|
||||||
|
: ComparerBase {
|
||||||
T rhs;
|
T rhs;
|
||||||
int result;
|
|
||||||
|
|
||||||
explicit Comparer(T value) : rhs(value), result(1) {}
|
explicit Comparer(T value) : rhs(value) {}
|
||||||
|
|
||||||
void visitArray(const CollectionData &) {}
|
|
||||||
void visitObject(const CollectionData &) {}
|
|
||||||
void visitFloat(Float lhs) {
|
void visitFloat(Float lhs) {
|
||||||
result = sign2(lhs - static_cast<Float>(rhs));
|
result = arithmeticCompare(lhs, rhs);
|
||||||
}
|
}
|
||||||
void visitString(const char *) {}
|
|
||||||
void visitRawJson(const char *, size_t) {}
|
|
||||||
void visitNegativeInteger(UInt lhs) {
|
void visitNegativeInteger(UInt lhs) {
|
||||||
result = -sign2(static_cast<T>(lhs) + rhs);
|
result = arithmeticCompareNegateLeft(lhs, rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void visitPositiveInteger(UInt lhs) {
|
void visitPositiveInteger(UInt lhs) {
|
||||||
result = static_cast<T>(lhs) < rhs ? -1 : static_cast<T>(lhs) > rhs ? 1 : 0;
|
result = arithmeticCompare(lhs, rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitBoolean(bool lhs) {
|
||||||
|
visitPositiveInteger(static_cast<UInt>(lhs));
|
||||||
}
|
}
|
||||||
void visitBoolean(bool) {}
|
|
||||||
void visitNull() {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
struct NullComparer : ComparerBase {
|
||||||
struct Comparer<bool, void> {
|
void visitNull() {
|
||||||
bool rhs;
|
result = COMPARE_RESULT_EQUAL;
|
||||||
int result;
|
|
||||||
|
|
||||||
explicit Comparer(bool value) : rhs(value), result(1) {}
|
|
||||||
|
|
||||||
void visitArray(const CollectionData &) {}
|
|
||||||
void visitObject(const CollectionData &) {}
|
|
||||||
void visitFloat(Float) {}
|
|
||||||
void visitString(const char *) {}
|
|
||||||
void visitRawJson(const char *, size_t) {}
|
|
||||||
void visitNegativeInteger(UInt) {}
|
|
||||||
void visitPositiveInteger(UInt) {}
|
|
||||||
void visitBoolean(bool lhs) {
|
|
||||||
result = static_cast<int>(lhs - rhs);
|
|
||||||
}
|
}
|
||||||
void visitNull() {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#if ARDUINOJSON_HAS_NULLPTR
|
#if ARDUINOJSON_HAS_NULLPTR
|
||||||
template <>
|
template <>
|
||||||
struct Comparer<decltype(nullptr), void> {
|
struct Comparer<decltype(nullptr), void> : NullComparer {
|
||||||
int result;
|
explicit Comparer(decltype(nullptr)) : NullComparer() {}
|
||||||
|
|
||||||
explicit Comparer(decltype(nullptr)) : result(1) {}
|
|
||||||
|
|
||||||
void visitArray(const CollectionData &) {}
|
|
||||||
void visitObject(const CollectionData &) {}
|
|
||||||
void visitFloat(Float) {}
|
|
||||||
void visitString(const char *) {}
|
|
||||||
void visitRawJson(const char *, size_t) {}
|
|
||||||
void visitNegativeInteger(UInt) {}
|
|
||||||
void visitPositiveInteger(UInt) {}
|
|
||||||
void visitBoolean(bool) {}
|
|
||||||
void visitNull() {
|
|
||||||
result = 0;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <typename TData>
|
struct ArrayComparer : ComparerBase {
|
||||||
|
const CollectionData *_rhs;
|
||||||
|
|
||||||
|
explicit ArrayComparer(const CollectionData &rhs) : _rhs(&rhs) {}
|
||||||
|
|
||||||
|
void visitArray(const CollectionData &lhs) {
|
||||||
|
if (lhs.equalsArray(*_rhs))
|
||||||
|
result = COMPARE_RESULT_EQUAL;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NegativeIntegerComparer : ComparerBase {
|
||||||
|
UInt _rhs;
|
||||||
|
|
||||||
|
explicit NegativeIntegerComparer(UInt rhs) : _rhs(rhs) {}
|
||||||
|
|
||||||
|
void visitFloat(Float lhs) {
|
||||||
|
result = arithmeticCompareNegateRight(lhs, _rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitNegativeInteger(UInt lhs) {
|
||||||
|
result = arithmeticCompare(_rhs, lhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitPositiveInteger(UInt) {
|
||||||
|
result = COMPARE_RESULT_GREATER;
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitBoolean(bool) {
|
||||||
|
result = COMPARE_RESULT_GREATER;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ObjectComparer : ComparerBase {
|
||||||
|
const CollectionData *_rhs;
|
||||||
|
|
||||||
|
explicit ObjectComparer(const CollectionData &rhs) : _rhs(&rhs) {}
|
||||||
|
|
||||||
|
void visitObject(const CollectionData &lhs) {
|
||||||
|
if (lhs.equalsObject(*_rhs))
|
||||||
|
result = COMPARE_RESULT_EQUAL;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RawComparer : ComparerBase {
|
||||||
|
const char *_rhsData;
|
||||||
|
size_t _rhsSize;
|
||||||
|
|
||||||
|
explicit RawComparer(const char *rhsData, size_t rhsSize)
|
||||||
|
: _rhsData(rhsData), _rhsSize(rhsSize) {}
|
||||||
|
|
||||||
|
void visitRawJson(const char *lhsData, size_t lhsSize) {
|
||||||
|
size_t size = _rhsSize < lhsSize ? _rhsSize : lhsSize;
|
||||||
|
int n = memcmp(lhsData, _rhsData, size);
|
||||||
|
if (n < 0)
|
||||||
|
result = COMPARE_RESULT_LESS;
|
||||||
|
else if (n > 0)
|
||||||
|
result = COMPARE_RESULT_GREATER;
|
||||||
|
else
|
||||||
|
result = COMPARE_RESULT_EQUAL;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
int VariantRefBase<TData>::compare(const T &rhs) const {
|
struct Comparer<T, typename enable_if<IsVisitable<T>::value>::type>
|
||||||
Comparer<T> comparer(rhs);
|
: ComparerBase {
|
||||||
if (_data)
|
T rhs;
|
||||||
_data->accept(comparer);
|
|
||||||
else
|
explicit Comparer(T value) : rhs(value) {}
|
||||||
comparer.visitNull();
|
|
||||||
|
void visitArray(const CollectionData &lhs) {
|
||||||
|
ArrayComparer comparer(lhs);
|
||||||
|
accept(comparer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitObject(const CollectionData &lhs) {
|
||||||
|
ObjectComparer comparer(lhs);
|
||||||
|
accept(comparer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitFloat(Float lhs) {
|
||||||
|
Comparer<Float> comparer(lhs);
|
||||||
|
accept(comparer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitString(const char *lhs) {
|
||||||
|
Comparer<const char *> comparer(lhs);
|
||||||
|
accept(comparer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitRawJson(const char *lhsData, size_t lhsSize) {
|
||||||
|
RawComparer comparer(lhsData, lhsSize);
|
||||||
|
accept(comparer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitNegativeInteger(UInt lhs) {
|
||||||
|
NegativeIntegerComparer comparer(lhs);
|
||||||
|
accept(comparer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitPositiveInteger(UInt lhs) {
|
||||||
|
Comparer<UInt> comparer(lhs);
|
||||||
|
accept(comparer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitBoolean(bool lhs) {
|
||||||
|
Comparer<bool> comparer(lhs);
|
||||||
|
accept(comparer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visitNull() {
|
||||||
|
NullComparer comparer;
|
||||||
|
accept(comparer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename TComparer>
|
||||||
|
void accept(TComparer &comparer) {
|
||||||
|
rhs.accept(comparer);
|
||||||
|
switch (comparer.result) {
|
||||||
|
case COMPARE_RESULT_GREATER:
|
||||||
|
result = COMPARE_RESULT_LESS;
|
||||||
|
break;
|
||||||
|
case COMPARE_RESULT_LESS:
|
||||||
|
result = COMPARE_RESULT_GREATER;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
result = comparer.result;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
CompareResult compare(const T1 &lhs, const T2 &rhs) {
|
||||||
|
Comparer<T2> comparer(rhs);
|
||||||
|
lhs.accept(comparer);
|
||||||
return comparer.result;
|
return comparer.result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline int variantCompare(const VariantData *a, const VariantData *b) {
|
||||||
|
return compare(VariantConstRef(a), VariantConstRef(b));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
|
@ -111,42 +111,6 @@ class VariantData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool equals(const VariantData &other) const {
|
|
||||||
// Check that variant have the same type, but ignore string ownership
|
|
||||||
if ((type() | VALUE_IS_OWNED) != (other.type() | VALUE_IS_OWNED))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
switch (type()) {
|
|
||||||
case VALUE_IS_LINKED_STRING:
|
|
||||||
case VALUE_IS_OWNED_STRING:
|
|
||||||
return !strcmp(_content.asString, other._content.asString);
|
|
||||||
|
|
||||||
case VALUE_IS_LINKED_RAW:
|
|
||||||
case VALUE_IS_OWNED_RAW:
|
|
||||||
return _content.asRaw.size == other._content.asRaw.size &&
|
|
||||||
!memcmp(_content.asRaw.data, other._content.asRaw.data,
|
|
||||||
_content.asRaw.size);
|
|
||||||
|
|
||||||
case VALUE_IS_BOOLEAN:
|
|
||||||
case VALUE_IS_POSITIVE_INTEGER:
|
|
||||||
case VALUE_IS_NEGATIVE_INTEGER:
|
|
||||||
return _content.asInteger == other._content.asInteger;
|
|
||||||
|
|
||||||
case VALUE_IS_ARRAY:
|
|
||||||
return _content.asCollection.equalsArray(other._content.asCollection);
|
|
||||||
|
|
||||||
case VALUE_IS_OBJECT:
|
|
||||||
return _content.asCollection.equalsObject(other._content.asCollection);
|
|
||||||
|
|
||||||
case VALUE_IS_FLOAT:
|
|
||||||
return _content.asFloat == other._content.asFloat;
|
|
||||||
|
|
||||||
case VALUE_IS_NULL:
|
|
||||||
default:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isArray() const {
|
bool isArray() const {
|
||||||
return (_flags & VALUE_IS_ARRAY) != 0;
|
return (_flags & VALUE_IS_ARRAY) != 0;
|
||||||
}
|
}
|
||||||
|
@ -40,13 +40,7 @@ inline bool variantCopyFrom(VariantData *dst, const VariantData *src,
|
|||||||
return dst->copyFrom(*src, pool);
|
return dst->copyFrom(*src, pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool variantEquals(const VariantData *a, const VariantData *b) {
|
inline int variantCompare(const VariantData *a, const VariantData *b);
|
||||||
if (a == b)
|
|
||||||
return true;
|
|
||||||
if (!a || !b)
|
|
||||||
return false;
|
|
||||||
return a->equals(*b);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool variantIsArray(const VariantData *var) {
|
inline bool variantIsArray(const VariantData *var) {
|
||||||
return var && var->isArray();
|
return var && var->isArray();
|
||||||
|
@ -5,12 +5,16 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <ArduinoJson/Misc/Visitable.hpp>
|
#include <ArduinoJson/Misc/Visitable.hpp>
|
||||||
|
#include <ArduinoJson/Numbers/arithmeticCompare.hpp>
|
||||||
#include <ArduinoJson/Polyfills/attributes.hpp>
|
#include <ArduinoJson/Polyfills/attributes.hpp>
|
||||||
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
#include <ArduinoJson/Polyfills/type_traits.hpp>
|
||||||
#include <ArduinoJson/Variant/VariantAs.hpp>
|
#include <ArduinoJson/Variant/VariantAs.hpp>
|
||||||
|
|
||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
CompareResult compare(const T1 &lhs, const T2 &rhs); // VariantCompare.cpp
|
||||||
|
|
||||||
template <typename TVariant>
|
template <typename TVariant>
|
||||||
struct VariantOperators {
|
struct VariantOperators {
|
||||||
// Returns the default value if the VariantRef is undefined of incompatible
|
// Returns the default value if the VariantRef is undefined of incompatible
|
||||||
@ -33,125 +37,127 @@ struct VariantOperators {
|
|||||||
// value == TVariant
|
// value == TVariant
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend bool operator==(T *lhs, TVariant rhs) {
|
friend bool operator==(T *lhs, TVariant rhs) {
|
||||||
return rhs.compare(lhs) == 0;
|
return compare(rhs, lhs) == COMPARE_RESULT_EQUAL;
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend typename enable_if<!IsVisitable<T>::value, bool>::type operator==(
|
friend bool operator==(const T &lhs, TVariant rhs) {
|
||||||
const T &lhs, TVariant rhs) {
|
return compare(rhs, lhs) == COMPARE_RESULT_EQUAL;
|
||||||
return rhs.compare(lhs) == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TVariant == value
|
// TVariant == value
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend bool operator==(TVariant lhs, T *rhs) {
|
friend bool operator==(TVariant lhs, T *rhs) {
|
||||||
return lhs.compare(rhs) == 0;
|
return compare(lhs, rhs) == COMPARE_RESULT_EQUAL;
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend typename enable_if<!IsVisitable<T>::value, bool>::type operator==(
|
friend typename enable_if<!IsVisitable<T>::value, bool>::type operator==(
|
||||||
TVariant lhs, const T &rhs) {
|
TVariant lhs, const T &rhs) {
|
||||||
return lhs.compare(rhs) == 0;
|
return compare(lhs, rhs) == COMPARE_RESULT_EQUAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// value != TVariant
|
// value != TVariant
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend bool operator!=(T *lhs, TVariant rhs) {
|
friend bool operator!=(T *lhs, TVariant rhs) {
|
||||||
return rhs.compare(lhs) != 0;
|
return compare(rhs, lhs) != COMPARE_RESULT_EQUAL;
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend typename enable_if<!IsVisitable<T>::value, bool>::type operator!=(
|
friend bool operator!=(const T &lhs, TVariant rhs) {
|
||||||
const T &lhs, TVariant rhs) {
|
return compare(rhs, lhs) != COMPARE_RESULT_EQUAL;
|
||||||
return rhs.compare(lhs) != 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TVariant != value
|
// TVariant != value
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend bool operator!=(TVariant lhs, T *rhs) {
|
friend bool operator!=(TVariant lhs, T *rhs) {
|
||||||
return lhs.compare(rhs) != 0;
|
return compare(lhs, rhs) != COMPARE_RESULT_EQUAL;
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend typename enable_if<!IsVisitable<T>::value, bool>::type operator!=(
|
friend typename enable_if<!IsVisitable<T>::value, bool>::type operator!=(
|
||||||
TVariant lhs, const T &rhs) {
|
TVariant lhs, const T &rhs) {
|
||||||
return lhs.compare(rhs) != 0;
|
return compare(lhs, rhs) != COMPARE_RESULT_EQUAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// value < TVariant
|
// value < TVariant
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend bool operator<(T *lhs, TVariant rhs) {
|
friend bool operator<(T *lhs, TVariant rhs) {
|
||||||
return rhs.compare(lhs) > 0;
|
return compare(rhs, lhs) == COMPARE_RESULT_GREATER;
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend bool operator<(const T &lhs, TVariant rhs) {
|
friend bool operator<(const T &lhs, TVariant rhs) {
|
||||||
return rhs.compare(lhs) > 0;
|
return compare(rhs, lhs) == COMPARE_RESULT_GREATER;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TVariant < value
|
// TVariant < value
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend bool operator<(TVariant lhs, T *rhs) {
|
friend bool operator<(TVariant lhs, T *rhs) {
|
||||||
return lhs.compare(rhs) < 0;
|
return compare(lhs, rhs) == COMPARE_RESULT_LESS;
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend bool operator<(TVariant lhs, const T &rhs) {
|
friend typename enable_if<!IsVisitable<T>::value, bool>::type operator<(
|
||||||
return lhs.compare(rhs) < 0;
|
TVariant lhs, const T &rhs) {
|
||||||
|
return compare(lhs, rhs) == COMPARE_RESULT_LESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// value <= TVariant
|
// value <= TVariant
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend bool operator<=(T *lhs, TVariant rhs) {
|
friend bool operator<=(T *lhs, TVariant rhs) {
|
||||||
return rhs.compare(lhs) >= 0;
|
return (compare(rhs, lhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0;
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend bool operator<=(const T &lhs, TVariant rhs) {
|
friend bool operator<=(const T &lhs, TVariant rhs) {
|
||||||
return rhs.compare(lhs) >= 0;
|
return (compare(rhs, lhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TVariant <= value
|
// TVariant <= value
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend bool operator<=(TVariant lhs, T *rhs) {
|
friend bool operator<=(TVariant lhs, T *rhs) {
|
||||||
return lhs.compare(rhs) <= 0;
|
return (compare(lhs, rhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0;
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend bool operator<=(TVariant lhs, const T &rhs) {
|
friend typename enable_if<!IsVisitable<T>::value, bool>::type operator<=(
|
||||||
return lhs.compare(rhs) <= 0;
|
TVariant lhs, const T &rhs) {
|
||||||
|
return (compare(lhs, rhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// value > TVariant
|
// value > TVariant
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend bool operator>(T *lhs, TVariant rhs) {
|
friend bool operator>(T *lhs, TVariant rhs) {
|
||||||
return rhs.compare(lhs) < 0;
|
return compare(rhs, lhs) == COMPARE_RESULT_LESS;
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend bool operator>(const T &lhs, TVariant rhs) {
|
friend bool operator>(const T &lhs, TVariant rhs) {
|
||||||
return rhs.compare(lhs) < 0;
|
return compare(rhs, lhs) == COMPARE_RESULT_LESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TVariant > value
|
// TVariant > value
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend bool operator>(TVariant lhs, T *rhs) {
|
friend bool operator>(TVariant lhs, T *rhs) {
|
||||||
return lhs.compare(rhs) > 0;
|
return compare(lhs, rhs) == COMPARE_RESULT_GREATER;
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend bool operator>(TVariant lhs, const T &rhs) {
|
friend typename enable_if<!IsVisitable<T>::value, bool>::type operator>(
|
||||||
return lhs.compare(rhs) > 0;
|
TVariant lhs, const T &rhs) {
|
||||||
|
return compare(lhs, rhs) == COMPARE_RESULT_GREATER;
|
||||||
}
|
}
|
||||||
|
|
||||||
// value >= TVariant
|
// value >= TVariant
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend bool operator>=(T *lhs, TVariant rhs) {
|
friend bool operator>=(T *lhs, TVariant rhs) {
|
||||||
return rhs.compare(lhs) <= 0;
|
return (compare(rhs, lhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0;
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend bool operator>=(const T &lhs, TVariant rhs) {
|
friend bool operator>=(const T &lhs, TVariant rhs) {
|
||||||
return rhs.compare(lhs) <= 0;
|
return (compare(rhs, lhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TVariant >= value
|
// TVariant >= value
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend bool operator>=(TVariant lhs, T *rhs) {
|
friend bool operator>=(TVariant lhs, T *rhs) {
|
||||||
return lhs.compare(rhs) >= 0;
|
return (compare(lhs, rhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0;
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
friend bool operator>=(TVariant lhs, const T &rhs) {
|
friend typename enable_if<!IsVisitable<T>::value, bool>::type operator>=(
|
||||||
return lhs.compare(rhs) >= 0;
|
TVariant lhs, const T &rhs) {
|
||||||
|
return (compare(lhs, rhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
|
@ -42,8 +42,10 @@ class VariantRefBase {
|
|||||||
// bool is<unsigned int>() const;
|
// bool is<unsigned int>() const;
|
||||||
// bool is<unsigned long>() const;
|
// bool is<unsigned long>() const;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
FORCE_INLINE typename enable_if<is_integral<T>::value, bool>::type is()
|
FORCE_INLINE
|
||||||
const {
|
typename enable_if<is_integral<T>::value && !is_same<bool, T>::value,
|
||||||
|
bool>::type
|
||||||
|
is() const {
|
||||||
return variantIsInteger<T>(_data);
|
return variantIsInteger<T>(_data);
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
@ -108,9 +110,6 @@ class VariantRefBase {
|
|||||||
return variantIsInteger<int>(_data);
|
return variantIsInteger<int>(_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
int compare(const T &) const; // VariantCompare.cpp
|
|
||||||
|
|
||||||
FORCE_INLINE bool isNull() const {
|
FORCE_INLINE bool isNull() const {
|
||||||
return variantIsNull(_data);
|
return variantIsNull(_data);
|
||||||
}
|
}
|
||||||
@ -188,7 +187,8 @@ class VariantRef : public VariantRefBase<VariantData>,
|
|||||||
// set(unsigned long)
|
// set(unsigned long)
|
||||||
template <typename T>
|
template <typename T>
|
||||||
FORCE_INLINE bool set(
|
FORCE_INLINE bool set(
|
||||||
T value, typename enable_if<is_integral<T>::value>::type * = 0) const {
|
T value, typename enable_if<is_integral<T>::value &&
|
||||||
|
!is_same<bool, T>::value>::type * = 0) const {
|
||||||
return variantSetInteger<T>(_data, value);
|
return variantSetInteger<T>(_data, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,14 +262,6 @@ class VariantRef : public VariantRefBase<VariantData>,
|
|||||||
variantAccept(_data, visitor);
|
variantAccept(_data, visitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE bool operator==(VariantRef lhs) const {
|
|
||||||
return variantEquals(_data, lhs._data);
|
|
||||||
}
|
|
||||||
|
|
||||||
FORCE_INLINE bool operator!=(VariantRef lhs) const {
|
|
||||||
return !variantEquals(_data, lhs._data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Change the type of the variant
|
// Change the type of the variant
|
||||||
//
|
//
|
||||||
// ArrayRef to<ArrayRef>()
|
// ArrayRef to<ArrayRef>()
|
||||||
@ -407,13 +399,5 @@ class VariantConstRef : public VariantRefBase<const VariantData>,
|
|||||||
operator[](TChar *key) const {
|
operator[](TChar *key) const {
|
||||||
return getMember(key);
|
return getMember(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE bool operator==(VariantConstRef lhs) const {
|
|
||||||
return variantEquals(_data, lhs._data);
|
|
||||||
}
|
|
||||||
|
|
||||||
FORCE_INLINE bool operator!=(VariantConstRef lhs) const {
|
|
||||||
return !variantEquals(_data, lhs._data);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
|
Reference in New Issue
Block a user