diff --git a/CHANGELOG.md b/CHANGELOG.md index 682dcc7c..a6637e6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ ArduinoJson: change log ======================= +HEAD +---- + +* Added comparisons (`>`, `>=`, `==`, `!=`, `<`, and `<=`) between `JsonVariant`s + v6.15.2 (2020-05-15) ------- diff --git a/extras/tests/ElementProxy/compare.cpp b/extras/tests/ElementProxy/compare.cpp index 2348eb2b..0023bf2c 100644 --- a/extras/tests/ElementProxy/compare.cpp +++ b/extras/tests/ElementProxy/compare.cpp @@ -10,19 +10,39 @@ using namespace ARDUINOJSON_NAMESPACE; TEST_CASE("ElementProxy::operator==()") { DynamicJsonDocument doc(4096); - SECTION("same value") { + SECTION("1 vs 1") { doc.add(1); doc.add(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("different values") { + SECTION("1 vs 2") { doc.add(1); 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_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]); } } diff --git a/extras/tests/JsonVariant/compare.cpp b/extras/tests/JsonVariant/compare.cpp index 3e5f54cf..d021296b 100644 --- a/extras/tests/JsonVariant/compare.cpp +++ b/extras/tests/JsonVariant/compare.cpp @@ -5,460 +5,276 @@ #include #include -template -void checkEquals(T a, T b) { - DynamicJsonDocument doc(4096); - JsonVariant variant = doc.to(); - variant.set(a); +// Most code is already covered by arithmeticCompare.cpp. +// Here, we're just filling the holes - REQUIRE(b == variant); - 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 -void checkGreater(T a, T b) { - DynamicJsonDocument doc(4096); - JsonVariant variant = doc.to(); - 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 -void checkLower(T a, T b) { - DynamicJsonDocument doc(4096); - JsonVariant variant = doc.to(); - 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 -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(123.44, 123.45, 123.46); - } - - SECTION("Float") { - checkComparisons(123.44f, 123.45f, 123.46f); - } - - SECTION("SChar") { - checkComparisons(122, 123, 124); - } - - SECTION("SInt") { - checkComparisons(122, 123, 124); - } - - SECTION("SLong") { - checkComparisons(122L, 123L, 124L); - } - - SECTION("SShort") { - checkComparisons(122, 123, 124); - } - - SECTION("UChar") { - checkComparisons(122, 123, 124); - } - - SECTION("UInt") { - checkComparisons(122, 123, 124); - } - - SECTION("ULong") { - checkComparisons(122L, 123L, 124L); - } - - SECTION("UShort") { - checkComparisons(122, 123, 124); - } - - SECTION("null") { - DynamicJsonDocument doc(4096); - JsonVariant variant = doc.to(); - 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(); - - 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(); - 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(); - 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(); - 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 variant2 = doc2.to(); - JsonVariant variant3 = doc3.to(); - - 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 array2 = variant2.to(); - - 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 obj2 = variant2.to(); - - obj1["hello"] = "world"; - obj2["hello"] = "world"; - - REQUIRE(variant1 == variant2); - REQUIRE_FALSE(variant1 != variant2); - - REQUIRE(variant1 != variant3); - REQUIRE_FALSE(variant1 == variant3); - } -} - -class VariantComparisionFixture { - private: +TEST_CASE("Compare JsonVariant with value") { StaticJsonDocument<256> doc; - JsonVariant variant; + JsonVariant a = doc.addElement(); - public: - VariantComparisionFixture() : variant(doc.to()) {} + SECTION("null vs (char*)0") { + char* b = 0; - protected: - template - void setValue(const T& value) { - variant.set(value); + CHECK(a == b); + CHECK(a <= b); + CHECK(a >= b); + CHECK_FALSE(a != b); + CHECK_FALSE(a < b); + CHECK_FALSE(a > b); } - template - void assertEqualsTo(const T& value) { - REQUIRE(variant == value); - REQUIRE(value == variant); + SECTION("42 vs 42") { + a.set(42); + int b = 42; - REQUIRE_FALSE(variant != value); - REQUIRE_FALSE(value != variant); - } - - template - void assertDiffersFrom(const T& value) { - REQUIRE(variant != value); - REQUIRE(value != variant); - - REQUIRE_FALSE(variant == value); - REQUIRE_FALSE(value == variant); - } - - template - void assertGreaterThan(const T& value) { - REQUIRE((variant > value)); - REQUIRE((variant >= value)); - REQUIRE(value < variant); - REQUIRE(value <= variant); - - REQUIRE_FALSE((variant < value)); - REQUIRE_FALSE((variant <= value)); - REQUIRE_FALSE(value > variant); - REQUIRE_FALSE(value >= variant); - } - - template - void assertLowerThan(const T& value) { - REQUIRE(variant < value); - REQUIRE(variant <= value); - REQUIRE(value > variant); - REQUIRE(value >= variant); - - REQUIRE_FALSE(variant > value); - REQUIRE_FALSE(variant >= value); - REQUIRE_FALSE(value < variant); - REQUIRE_FALSE(value <= variant); - } -}; - -TEST_CASE_METHOD(VariantComparisionFixture, - "Compare variant with another type") { - SECTION("null") { - assertDiffersFrom(3); - assertDiffersFrom("world"); - } - - SECTION("string") { - setValue("hello"); - assertEqualsTo("hello"); - assertDiffersFrom(3); - assertDiffersFrom("world"); - assertGreaterThan("helln"); - assertLowerThan("hellp"); - } - - SECTION("positive integer") { - setValue(42); - assertEqualsTo(42); - assertDiffersFrom(43); - assertGreaterThan(41); - assertLowerThan(43); - assertDiffersFrom("world"); - } - - SECTION("negative integer") { - setValue(-42); - assertEqualsTo(-42); - assertDiffersFrom(42); - assertGreaterThan(-43); - assertLowerThan(-41); - assertDiffersFrom("world"); - } - - SECTION("double") { - setValue(42.0); - assertEqualsTo(42.0); - assertDiffersFrom(42.1); - assertGreaterThan(41.0); - assertLowerThan(43.0); - assertDiffersFrom("42.0"); - } - - SECTION("true") { - setValue(true); - assertEqualsTo(true); - assertDiffersFrom(false); - assertDiffersFrom(1); - assertDiffersFrom("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); + } +} + +TEST_CASE("Compare JsonVariant with JsonVariant") { + StaticJsonDocument<256> doc; + JsonVariant a = doc.addElement(); + JsonVariant b = doc.addElement(); + + SECTION("'abc' vs 'abc'") { + a.set("abc"); + b.set("abc"); + + CHECK(a == b); + CHECK(a <= b); + CHECK(a >= b); + CHECK_FALSE(a != b); + CHECK_FALSE(a < b); + CHECK_FALSE(a > b); + } + + SECTION("'abc' vs 'bcd'") { + a.set("abc"); + b.set("bcd"); + + CHECK(a != b); + CHECK(a < b); + CHECK(a <= b); + CHECK_FALSE(a == b); + CHECK_FALSE(a > b); + CHECK_FALSE(a >= b); + } + + SECTION("'bcd' vs 'abc'") { + a.set("bcd"); + b.set("abc"); + + CHECK(a != b); + CHECK(a > b); + CHECK(a >= b); + CHECK_FALSE(a < b); + CHECK_FALSE(a <= b); + CHECK_FALSE(a == b); + } + + SECTION("serialized('abc') vs serialized('abc')") { + a.set(serialized("abc")); + b.set(serialized("abc")); + + CHECK(a == b); + CHECK(a <= b); + CHECK(a >= b); + CHECK_FALSE(a != b); + CHECK_FALSE(a < b); + CHECK_FALSE(a > b); + } + + SECTION("serialized('abc') vs serialized('bcd')") { + a.set(serialized("abc")); + b.set(serialized("bcd")); + + CHECK(a != b); + CHECK(a < b); + CHECK(a <= b); + CHECK_FALSE(a == b); + CHECK_FALSE(a > b); + CHECK_FALSE(a >= b); + } + + SECTION("serialized('bcd') vs serialized('abc')") { + a.set(serialized("bcd")); + b.set(serialized("abc")); + + CHECK(a != b); + CHECK(a > b); + CHECK(a >= b); + CHECK_FALSE(a < b); + CHECK_FALSE(a <= b); + CHECK_FALSE(a == b); + } + + SECTION("false vs true") { + a.set(false); + b.set(true); + + 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); } } diff --git a/extras/tests/MemberProxy/compare.cpp b/extras/tests/MemberProxy/compare.cpp index 0f646035..2c3c3ef2 100644 --- a/extras/tests/MemberProxy/compare.cpp +++ b/extras/tests/MemberProxy/compare.cpp @@ -10,17 +10,39 @@ using namespace ARDUINOJSON_NAMESPACE; TEST_CASE("MemberProxy::operator==()") { DynamicJsonDocument doc(4096); - SECTION("same values") { - doc["key1"] = "value"; - doc["key2"] = "value"; - REQUIRE(doc["key1"] == doc["key2"]); - REQUIRE_FALSE(doc["key1"] != doc["key2"]); + SECTION("1 vs 1") { + doc["a"] = 1; + doc["b"] = 1; + + 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") { - doc["key1"] = "value1"; - doc["key2"] = "value2"; - REQUIRE_FALSE(doc["key1"] == doc["key2"]); - REQUIRE(doc["key1"] != doc["key2"]); + SECTION("1 vs 2") { + doc["a"] = 1; + doc["b"] = 2; + + 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"]); } } diff --git a/extras/tests/Misc/CMakeLists.txt b/extras/tests/Misc/CMakeLists.txt index a983004b..042264a4 100644 --- a/extras/tests/Misc/CMakeLists.txt +++ b/extras/tests/Misc/CMakeLists.txt @@ -3,6 +3,7 @@ # MIT License add_executable(MiscTests + arithmeticCompare.cpp conflicts.cpp FloatParts.cpp Readers.cpp diff --git a/extras/tests/Misc/TypeTraits.cpp b/extras/tests/Misc/TypeTraits.cpp index 4566a26a..59511ec4 100644 --- a/extras/tests/Misc/TypeTraits.cpp +++ b/extras/tests/Misc/TypeTraits.cpp @@ -29,6 +29,24 @@ TEST_CASE("Polyfills/type_traits") { CHECK(is_const::value == true); } + SECTION("is_integral") { + CHECK(is_integral::value == false); + CHECK(is_integral::value == false); + + CHECK(is_integral::value == true); + CHECK(is_integral::value == true); + CHECK(is_integral::value == true); + CHECK(is_integral::value == true); + CHECK(is_integral::value == true); + CHECK(is_integral::value == true); + CHECK(is_integral::value == true); + CHECK(is_integral::value == true); + CHECK(is_integral::value == true); + CHECK(is_integral::value == true); + + CHECK(is_integral::value == true); + } + SECTION("is_signed") { CHECK(is_signed::value == true); CHECK(is_signed::value == true); diff --git a/extras/tests/Misc/arithmeticCompare.cpp b/extras/tests/Misc/arithmeticCompare.cpp new file mode 100644 index 00000000..90f4c186 --- /dev/null +++ b/extras/tests/Misc/arithmeticCompare.cpp @@ -0,0 +1,103 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#include +#include + +using namespace ARDUINOJSON_NAMESPACE; + +TEST_CASE("arithmeticCompare()") { + SECTION("int vs uint8_t") { + CHECK((arithmeticCompare(256, 1) == COMPARE_RESULT_GREATER)); + CHECK((arithmeticCompare(41, 42) == COMPARE_RESULT_LESS)); + CHECK((arithmeticCompare(42, 42) == COMPARE_RESULT_EQUAL)); + CHECK((arithmeticCompare(43, 42) == COMPARE_RESULT_GREATER)); + } + + SECTION("unsigned vs int") { + CHECK((arithmeticCompare(0, -1) == COMPARE_RESULT_GREATER)); + CHECK((arithmeticCompare(42, 41) == COMPARE_RESULT_GREATER)); + CHECK((arithmeticCompare(42, 42) == COMPARE_RESULT_EQUAL)); + CHECK((arithmeticCompare(42, 43) == COMPARE_RESULT_LESS)); + } + + SECTION("float vs int") { + CHECK((arithmeticCompare(42, 41) == COMPARE_RESULT_GREATER)); + CHECK((arithmeticCompare(42, 42) == COMPARE_RESULT_EQUAL)); + CHECK((arithmeticCompare(42, 43) == COMPARE_RESULT_LESS)); + } + + SECTION("int vs unsigned") { + CHECK((arithmeticCompare(-1, 0) == COMPARE_RESULT_LESS)); + CHECK((arithmeticCompare(0, 0) == COMPARE_RESULT_EQUAL)); + CHECK((arithmeticCompare(1, 0) == COMPARE_RESULT_GREATER)); + CHECK((arithmeticCompare(42, 41) == COMPARE_RESULT_GREATER)); + CHECK((arithmeticCompare(42, 42) == COMPARE_RESULT_EQUAL)); + CHECK((arithmeticCompare(42, 43) == COMPARE_RESULT_LESS)); + } + + SECTION("unsigned vs unsigned") { + CHECK((arithmeticCompare(42, 41) == + COMPARE_RESULT_GREATER)); + CHECK((arithmeticCompare(42, 42) == + COMPARE_RESULT_EQUAL)); + CHECK( + (arithmeticCompare(42, 43) == COMPARE_RESULT_LESS)); + } + + SECTION("bool vs bool") { + CHECK( + (arithmeticCompare(false, false) == COMPARE_RESULT_EQUAL)); + CHECK((arithmeticCompare(true, true) == COMPARE_RESULT_EQUAL)); + CHECK((arithmeticCompare(false, true) == COMPARE_RESULT_LESS)); + CHECK( + (arithmeticCompare(true, false) == COMPARE_RESULT_GREATER)); + } + + SECTION("bool vs int") { + CHECK((arithmeticCompare(false, -1) == COMPARE_RESULT_GREATER)); + CHECK((arithmeticCompare(false, 0) == COMPARE_RESULT_EQUAL)); + CHECK((arithmeticCompare(false, 1) == COMPARE_RESULT_LESS)); + CHECK((arithmeticCompare(true, 0) == COMPARE_RESULT_GREATER)); + CHECK((arithmeticCompare(true, 1) == COMPARE_RESULT_EQUAL)); + CHECK((arithmeticCompare(true, 2) == COMPARE_RESULT_LESS)); + } + + SECTION("bool vs int") { + CHECK((arithmeticCompare(0, false) == COMPARE_RESULT_EQUAL)); + CHECK((arithmeticCompare(1, true) == COMPARE_RESULT_EQUAL)); + CHECK((arithmeticCompare(1, false) == COMPARE_RESULT_GREATER)); + CHECK((arithmeticCompare(0, true) == COMPARE_RESULT_LESS)); + } +} + +TEST_CASE("arithmeticCompareNegateLeft()") { + SECTION("unsigned vs int") { + CHECK((arithmeticCompareNegateLeft(0, 1) == COMPARE_RESULT_LESS)); + CHECK((arithmeticCompareNegateLeft(42, -41) == COMPARE_RESULT_LESS)); + CHECK((arithmeticCompareNegateLeft(42, -42) == COMPARE_RESULT_EQUAL)); + CHECK( + (arithmeticCompareNegateLeft(42, -43) == COMPARE_RESULT_GREATER)); + } + + SECTION("unsigned vs unsigned") { + CHECK( + (arithmeticCompareNegateLeft(42, 42) == COMPARE_RESULT_LESS)); + } +} + +TEST_CASE("arithmeticCompareNegateRight()") { + SECTION("int vs unsigned") { + CHECK((arithmeticCompareNegateRight(1, 0) == COMPARE_RESULT_GREATER)); + CHECK( + (arithmeticCompareNegateRight(-41, 42) == COMPARE_RESULT_GREATER)); + CHECK((arithmeticCompareNegateRight(-42, 42) == COMPARE_RESULT_EQUAL)); + CHECK((arithmeticCompareNegateRight(-43, 42) == COMPARE_RESULT_LESS)); + } + + SECTION("unsigned vs unsigned") { + CHECK((arithmeticCompareNegateRight(42, 42) == + COMPARE_RESULT_GREATER)); + } +} diff --git a/src/ArduinoJson/Array/ElementProxy.hpp b/src/ArduinoJson/Array/ElementProxy.hpp index 6d5cfdf4..0d0c821e 100644 --- a/src/ArduinoJson/Array/ElementProxy.hpp +++ b/src/ArduinoJson/Array/ElementProxy.hpp @@ -53,14 +53,6 @@ class ElementProxy : public VariantOperators >, return *this; } - FORCE_INLINE bool operator==(VariantConstRef rhs) const { - return static_cast(getUpstreamElement()) == rhs; - } - - FORCE_INLINE bool operator!=(VariantConstRef rhs) const { - return static_cast(getUpstreamElement()) != rhs; - } - FORCE_INLINE void clear() const { getUpstreamElement().clear(); } @@ -79,11 +71,6 @@ class ElementProxy : public VariantOperators >, return getUpstreamElement(); } - template - FORCE_INLINE int compare(const T& rhs) const { - return getUpstreamElement().template compare(rhs); - } - template FORCE_INLINE bool is() const { return getUpstreamElement().template is(); diff --git a/src/ArduinoJson/Collection/CollectionImpl.hpp b/src/ArduinoJson/Collection/CollectionImpl.hpp index 910a2a62..34975442 100644 --- a/src/ArduinoJson/Collection/CollectionImpl.hpp +++ b/src/ArduinoJson/Collection/CollectionImpl.hpp @@ -9,6 +9,10 @@ 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) { VariantSlot* slot = pool->allocVariant(); if (!slot) diff --git a/src/ArduinoJson/Numbers/arithmeticCompare.hpp b/src/ArduinoJson/Numbers/arithmeticCompare.hpp new file mode 100644 index 00000000..df30d172 --- /dev/null +++ b/src/ArduinoJson/Numbers/arithmeticCompare.hpp @@ -0,0 +1,121 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include +#include + +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 +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 +CompareResult arithmeticCompare( + const T1 &lhs, const T2 &rhs, + typename enable_if::value && is_integral::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(static_cast(lhs), rhs); +} + +template +CompareResult arithmeticCompare( + const T1 &lhs, const T2 &rhs, + typename enable_if::value && is_integral::value && + sizeof(T2) < sizeof(T1)>::type * = 0) { + return arithmeticCompare(lhs, static_cast(rhs)); +} + +template +CompareResult arithmeticCompare( + const T1 &lhs, const T2 &rhs, + typename enable_if::value && is_integral::value && + is_signed::value == is_signed::value && + sizeof(T2) == sizeof(T1)>::type * = 0) { + return arithmeticCompare(lhs, static_cast(rhs)); +} + +template +CompareResult arithmeticCompare( + const T1 &lhs, const T2 &rhs, + typename enable_if::value && is_integral::value && + is_unsigned::value && is_signed::value && + sizeof(T2) == sizeof(T1)>::type * = 0) { + if (rhs < 0) + return COMPARE_RESULT_GREATER; + return arithmeticCompare(lhs, static_cast(rhs)); +} + +template +CompareResult arithmeticCompare( + const T1 &lhs, const T2 &rhs, + typename enable_if::value && is_integral::value && + is_signed::value && is_unsigned::value && + sizeof(T2) == sizeof(T1)>::type * = 0) { + if (lhs < 0) + return COMPARE_RESULT_LESS; + return arithmeticCompare(static_cast(lhs), rhs); +} + +template +CompareResult arithmeticCompare( + const T1 &lhs, const T2 &rhs, + typename enable_if::value || + is_floating_point::value>::type * = 0) { + return arithmeticCompare(static_cast(lhs), + static_cast(rhs)); +} + +template +CompareResult arithmeticCompareNegateLeft( + UInt, const T2 &, typename enable_if::value>::type * = 0) { + return COMPARE_RESULT_LESS; +} + +template +CompareResult arithmeticCompareNegateLeft( + UInt lhs, const T2 &rhs, + typename enable_if::value>::type * = 0) { + if (rhs > 0) + return COMPARE_RESULT_LESS; + return arithmeticCompare(-rhs, static_cast(lhs)); +} + +template +CompareResult arithmeticCompareNegateRight( + const T1 &, UInt, typename enable_if::value>::type * = 0) { + return COMPARE_RESULT_GREATER; +} + +template +CompareResult arithmeticCompareNegateRight( + const T1 &lhs, UInt rhs, + typename enable_if::value>::type * = 0) { + if (lhs > 0) + return COMPARE_RESULT_GREATER; + return arithmeticCompare(static_cast(rhs), -lhs); +} + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Object/MemberProxy.hpp b/src/ArduinoJson/Object/MemberProxy.hpp index 49602b93..46f4beab 100644 --- a/src/ArduinoJson/Object/MemberProxy.hpp +++ b/src/ArduinoJson/Object/MemberProxy.hpp @@ -56,14 +56,6 @@ class MemberProxy : public VariantOperators >, return *this; } - FORCE_INLINE bool operator==(VariantConstRef rhs) const { - return static_cast(getUpstreamMember()) == rhs; - } - - FORCE_INLINE bool operator!=(VariantConstRef rhs) const { - return static_cast(getUpstreamMember()) != rhs; - } - FORCE_INLINE void clear() const { getUpstreamMember().clear(); } @@ -82,11 +74,6 @@ class MemberProxy : public VariantOperators >, return getUpstreamMember(); } - template - FORCE_INLINE int compare(const T &rhs) const { - return getUpstreamMember().template compare(rhs); - } - template FORCE_INLINE bool is() const { return getUpstreamMember().template is(); diff --git a/src/ArduinoJson/Polyfills/type_traits/is_enum.hpp b/src/ArduinoJson/Polyfills/type_traits/is_enum.hpp index 8ef57d8f..ed33a6cd 100644 --- a/src/ArduinoJson/Polyfills/type_traits/is_enum.hpp +++ b/src/ArduinoJson/Polyfills/type_traits/is_enum.hpp @@ -16,8 +16,7 @@ template struct is_enum { static const bool value = is_convertible::value && !is_class::value && !is_integral::value && - !is_floating_point::value && - !is_same::value; + !is_floating_point::value; }; } // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Polyfills/type_traits/is_integral.hpp b/src/ArduinoJson/Polyfills/type_traits/is_integral.hpp index b45a8636..9c6f0976 100644 --- a/src/ArduinoJson/Polyfills/type_traits/is_integral.hpp +++ b/src/ArduinoJson/Polyfills/type_traits/is_integral.hpp @@ -25,9 +25,7 @@ struct is_integral { is_same::value || is_same::value || #endif - is_same::value; - - // CAUTION: differs from std::is_integral as it doesn't include bool + is_same::value || is_same::value; }; template diff --git a/src/ArduinoJson/Variant/VariantAs.hpp b/src/ArduinoJson/Variant/VariantAs.hpp index e1c44151..9e046bef 100644 --- a/src/ArduinoJson/Variant/VariantAs.hpp +++ b/src/ArduinoJson/Variant/VariantAs.hpp @@ -53,8 +53,9 @@ struct VariantConstAs { // --- template -inline typename enable_if::value, T>::type variantAs( - const VariantData* data) { +inline typename enable_if::value && !is_same::value, + T>::type +variantAs(const VariantData* data) { ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T); return data != 0 ? data->asIntegral() : T(0); } diff --git a/src/ArduinoJson/Variant/VariantCompare.hpp b/src/ArduinoJson/Variant/VariantCompare.hpp index 8cc60159..986e5648 100644 --- a/src/ArduinoJson/Variant/VariantCompare.hpp +++ b/src/ArduinoJson/Variant/VariantCompare.hpp @@ -6,8 +6,7 @@ #include #include -#include -#include +#include #include #include @@ -15,115 +14,228 @@ namespace ARDUINOJSON_NAMESPACE { 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 struct Comparer; template -struct Comparer::value>::type> { +struct Comparer::value>::type> + : ComparerBase { 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) { - 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() { - result = adaptString(rhs).compare(NULL); + if (adaptString(rhs).isNull()) + result = COMPARE_RESULT_EQUAL; } }; -template -typename enable_if::value, int>::type sign2(const T &value) { - return value < 0 ? -1 : value > 0 ? 1 : 0; -} - -template -typename enable_if::value, int>::type sign2(const T &value) { - return value > 0 ? 1 : 0; -} template struct Comparer::value || - is_floating_point::value>::type> { + is_floating_point::value>::type> + : ComparerBase { 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) { - result = sign2(lhs - static_cast(rhs)); + result = arithmeticCompare(lhs, rhs); } - void visitString(const char *) {} - void visitRawJson(const char *, size_t) {} + void visitNegativeInteger(UInt lhs) { - result = -sign2(static_cast(lhs) + rhs); + result = arithmeticCompareNegateLeft(lhs, rhs); } + void visitPositiveInteger(UInt lhs) { - result = static_cast(lhs) < rhs ? -1 : static_cast(lhs) > rhs ? 1 : 0; + result = arithmeticCompare(lhs, rhs); + } + + void visitBoolean(bool lhs) { + visitPositiveInteger(static_cast(lhs)); } - void visitBoolean(bool) {} - void visitNull() {} }; -template <> -struct Comparer { - bool rhs; - 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(lhs - rhs); +struct NullComparer : ComparerBase { + void visitNull() { + result = COMPARE_RESULT_EQUAL; } - void visitNull() {} }; #if ARDUINOJSON_HAS_NULLPTR template <> -struct Comparer { - int result; - - 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; - } +struct Comparer : NullComparer { + explicit Comparer(decltype(nullptr)) : NullComparer() {} }; #endif -template +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 -int VariantRefBase::compare(const T &rhs) const { - Comparer comparer(rhs); - if (_data) - _data->accept(comparer); - else - comparer.visitNull(); +struct Comparer::value>::type> + : ComparerBase { + T rhs; + + explicit Comparer(T value) : rhs(value) {} + + 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 comparer(lhs); + accept(comparer); + } + + void visitString(const char *lhs) { + Comparer 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 comparer(lhs); + accept(comparer); + } + + void visitBoolean(bool lhs) { + Comparer comparer(lhs); + accept(comparer); + } + + void visitNull() { + NullComparer comparer; + accept(comparer); + } + + private: + template + 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 +CompareResult compare(const T1 &lhs, const T2 &rhs) { + Comparer comparer(rhs); + lhs.accept(comparer); return comparer.result; } +inline int variantCompare(const VariantData *a, const VariantData *b) { + return compare(VariantConstRef(a), VariantConstRef(b)); +} + } // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Variant/VariantData.hpp b/src/ArduinoJson/Variant/VariantData.hpp index 31e2efaa..c411446e 100644 --- a/src/ArduinoJson/Variant/VariantData.hpp +++ b/src/ArduinoJson/Variant/VariantData.hpp @@ -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 { return (_flags & VALUE_IS_ARRAY) != 0; } diff --git a/src/ArduinoJson/Variant/VariantFunctions.hpp b/src/ArduinoJson/Variant/VariantFunctions.hpp index eeef4c11..e95448a2 100644 --- a/src/ArduinoJson/Variant/VariantFunctions.hpp +++ b/src/ArduinoJson/Variant/VariantFunctions.hpp @@ -40,13 +40,7 @@ inline bool variantCopyFrom(VariantData *dst, const VariantData *src, return dst->copyFrom(*src, pool); } -inline bool variantEquals(const VariantData *a, const VariantData *b) { - if (a == b) - return true; - if (!a || !b) - return false; - return a->equals(*b); -} +inline int variantCompare(const VariantData *a, const VariantData *b); inline bool variantIsArray(const VariantData *var) { return var && var->isArray(); diff --git a/src/ArduinoJson/Variant/VariantOperators.hpp b/src/ArduinoJson/Variant/VariantOperators.hpp index 377c61c5..67a0f7c5 100644 --- a/src/ArduinoJson/Variant/VariantOperators.hpp +++ b/src/ArduinoJson/Variant/VariantOperators.hpp @@ -5,12 +5,16 @@ #pragma once #include +#include #include #include #include namespace ARDUINOJSON_NAMESPACE { +template +CompareResult compare(const T1 &lhs, const T2 &rhs); // VariantCompare.cpp + template struct VariantOperators { // Returns the default value if the VariantRef is undefined of incompatible @@ -33,125 +37,127 @@ struct VariantOperators { // value == TVariant template friend bool operator==(T *lhs, TVariant rhs) { - return rhs.compare(lhs) == 0; + return compare(rhs, lhs) == COMPARE_RESULT_EQUAL; } template - friend typename enable_if::value, bool>::type operator==( - const T &lhs, TVariant rhs) { - return rhs.compare(lhs) == 0; + friend bool operator==(const T &lhs, TVariant rhs) { + return compare(rhs, lhs) == COMPARE_RESULT_EQUAL; } // TVariant == value template friend bool operator==(TVariant lhs, T *rhs) { - return lhs.compare(rhs) == 0; + return compare(lhs, rhs) == COMPARE_RESULT_EQUAL; } template friend typename enable_if::value, bool>::type operator==( TVariant lhs, const T &rhs) { - return lhs.compare(rhs) == 0; + return compare(lhs, rhs) == COMPARE_RESULT_EQUAL; } // value != TVariant template friend bool operator!=(T *lhs, TVariant rhs) { - return rhs.compare(lhs) != 0; + return compare(rhs, lhs) != COMPARE_RESULT_EQUAL; } template - friend typename enable_if::value, bool>::type operator!=( - const T &lhs, TVariant rhs) { - return rhs.compare(lhs) != 0; + friend bool operator!=(const T &lhs, TVariant rhs) { + return compare(rhs, lhs) != COMPARE_RESULT_EQUAL; } // TVariant != value template friend bool operator!=(TVariant lhs, T *rhs) { - return lhs.compare(rhs) != 0; + return compare(lhs, rhs) != COMPARE_RESULT_EQUAL; } template friend typename enable_if::value, bool>::type operator!=( TVariant lhs, const T &rhs) { - return lhs.compare(rhs) != 0; + return compare(lhs, rhs) != COMPARE_RESULT_EQUAL; } // value < TVariant template friend bool operator<(T *lhs, TVariant rhs) { - return rhs.compare(lhs) > 0; + return compare(rhs, lhs) == COMPARE_RESULT_GREATER; } template friend bool operator<(const T &lhs, TVariant rhs) { - return rhs.compare(lhs) > 0; + return compare(rhs, lhs) == COMPARE_RESULT_GREATER; } // TVariant < value template friend bool operator<(TVariant lhs, T *rhs) { - return lhs.compare(rhs) < 0; + return compare(lhs, rhs) == COMPARE_RESULT_LESS; } template - friend bool operator<(TVariant lhs, const T &rhs) { - return lhs.compare(rhs) < 0; + friend typename enable_if::value, bool>::type operator<( + TVariant lhs, const T &rhs) { + return compare(lhs, rhs) == COMPARE_RESULT_LESS; } // value <= TVariant template friend bool operator<=(T *lhs, TVariant rhs) { - return rhs.compare(lhs) >= 0; + return (compare(rhs, lhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; } template 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 template friend bool operator<=(TVariant lhs, T *rhs) { - return lhs.compare(rhs) <= 0; + return (compare(lhs, rhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; } template - friend bool operator<=(TVariant lhs, const T &rhs) { - return lhs.compare(rhs) <= 0; + friend typename enable_if::value, bool>::type operator<=( + TVariant lhs, const T &rhs) { + return (compare(lhs, rhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; } // value > TVariant template friend bool operator>(T *lhs, TVariant rhs) { - return rhs.compare(lhs) < 0; + return compare(rhs, lhs) == COMPARE_RESULT_LESS; } template friend bool operator>(const T &lhs, TVariant rhs) { - return rhs.compare(lhs) < 0; + return compare(rhs, lhs) == COMPARE_RESULT_LESS; } // TVariant > value template friend bool operator>(TVariant lhs, T *rhs) { - return lhs.compare(rhs) > 0; + return compare(lhs, rhs) == COMPARE_RESULT_GREATER; } template - friend bool operator>(TVariant lhs, const T &rhs) { - return lhs.compare(rhs) > 0; + friend typename enable_if::value, bool>::type operator>( + TVariant lhs, const T &rhs) { + return compare(lhs, rhs) == COMPARE_RESULT_GREATER; } // value >= TVariant template friend bool operator>=(T *lhs, TVariant rhs) { - return rhs.compare(lhs) <= 0; + return (compare(rhs, lhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; } template 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 template friend bool operator>=(TVariant lhs, T *rhs) { - return lhs.compare(rhs) >= 0; + return (compare(lhs, rhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; } template - friend bool operator>=(TVariant lhs, const T &rhs) { - return lhs.compare(rhs) >= 0; + friend typename enable_if::value, bool>::type operator>=( + TVariant lhs, const T &rhs) { + return (compare(lhs, rhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; } }; } // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Variant/VariantRef.hpp b/src/ArduinoJson/Variant/VariantRef.hpp index 9bbfb8a6..3eaeec2f 100644 --- a/src/ArduinoJson/Variant/VariantRef.hpp +++ b/src/ArduinoJson/Variant/VariantRef.hpp @@ -42,8 +42,10 @@ class VariantRefBase { // bool is() const; // bool is() const; template - FORCE_INLINE typename enable_if::value, bool>::type is() - const { + FORCE_INLINE + typename enable_if::value && !is_same::value, + bool>::type + is() const { return variantIsInteger(_data); } // @@ -108,9 +110,6 @@ class VariantRefBase { return variantIsInteger(_data); } - template - int compare(const T &) const; // VariantCompare.cpp - FORCE_INLINE bool isNull() const { return variantIsNull(_data); } @@ -188,7 +187,8 @@ class VariantRef : public VariantRefBase, // set(unsigned long) template FORCE_INLINE bool set( - T value, typename enable_if::value>::type * = 0) const { + T value, typename enable_if::value && + !is_same::value>::type * = 0) const { return variantSetInteger(_data, value); } @@ -262,14 +262,6 @@ class VariantRef : public VariantRefBase, 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 // // ArrayRef to() @@ -407,13 +399,5 @@ class VariantConstRef : public VariantRefBase, operator[](TChar *key) const { 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