mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 08:42:39 +01:00 
			
		
		
		
	Added comparisons between JsonVariants
				
					
				
			This commit is contained in:
		| @@ -1,6 +1,11 @@ | ||||
| ArduinoJson: change log | ||||
| ======================= | ||||
|  | ||||
| HEAD | ||||
| ---- | ||||
|  | ||||
| * Added comparisons (`>`, `>=`, `==`, `!=`, `<`, and `<=`) between `JsonVariant`s | ||||
|  | ||||
| v6.15.2 (2020-05-15) | ||||
| ------- | ||||
|  | ||||
|   | ||||
| @@ -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]); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -5,460 +5,276 @@ | ||||
| #include <ArduinoJson.h> | ||||
| #include <catch.hpp> | ||||
|  | ||||
| template <typename T> | ||||
| void checkEquals(T a, T b) { | ||||
|   DynamicJsonDocument doc(4096); | ||||
|   JsonVariant variant = doc.to<JsonVariant>(); | ||||
|   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 <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: | ||||
| TEST_CASE("Compare JsonVariant with value") { | ||||
|   StaticJsonDocument<256> doc; | ||||
|   JsonVariant variant; | ||||
|   JsonVariant a = doc.addElement(); | ||||
|  | ||||
|  public: | ||||
|   VariantComparisionFixture() : variant(doc.to<JsonVariant>()) {} | ||||
|   SECTION("null vs (char*)0") { | ||||
|     char* b = 0; | ||||
|  | ||||
|  protected: | ||||
|   template <typename T> | ||||
|   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 <typename T> | ||||
|   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 <typename T> | ||||
|   void assertDiffersFrom(const T& value) { | ||||
|     REQUIRE(variant != value); | ||||
|     REQUIRE(value != variant); | ||||
|  | ||||
|     REQUIRE_FALSE(variant == value); | ||||
|     REQUIRE_FALSE(value == variant); | ||||
|   } | ||||
|  | ||||
|   template <typename T> | ||||
|   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 <typename T> | ||||
|   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); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -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"]); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
| # MIT License | ||||
|  | ||||
| add_executable(MiscTests | ||||
| 	arithmeticCompare.cpp | ||||
| 	conflicts.cpp | ||||
| 	FloatParts.cpp | ||||
| 	Readers.cpp | ||||
|   | ||||
| @@ -29,6 +29,24 @@ TEST_CASE("Polyfills/type_traits") { | ||||
|     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") { | ||||
|     CHECK(is_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; | ||||
|   } | ||||
|  | ||||
|   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 { | ||||
|     getUpstreamElement().clear(); | ||||
|   } | ||||
| @@ -79,11 +71,6 @@ class ElementProxy : public VariantOperators<ElementProxy<TArray> >, | ||||
|     return getUpstreamElement(); | ||||
|   } | ||||
|  | ||||
|   template <typename T> | ||||
|   FORCE_INLINE int compare(const T& rhs) const { | ||||
|     return getUpstreamElement().template compare<T>(rhs); | ||||
|   } | ||||
|  | ||||
|   template <typename T> | ||||
|   FORCE_INLINE bool is() const { | ||||
|     return getUpstreamElement().template is<T>(); | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
							
								
								
									
										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; | ||||
|   } | ||||
|  | ||||
|   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 { | ||||
|     getUpstreamMember().clear(); | ||||
|   } | ||||
| @@ -82,11 +74,6 @@ class MemberProxy : public VariantOperators<MemberProxy<TObject, TStringRef> >, | ||||
|     return getUpstreamMember(); | ||||
|   } | ||||
|  | ||||
|   template <typename T> | ||||
|   FORCE_INLINE int compare(const T &rhs) const { | ||||
|     return getUpstreamMember().template compare<T>(rhs); | ||||
|   } | ||||
|  | ||||
|   template <typename TValue> | ||||
|   FORCE_INLINE bool is() const { | ||||
|     return getUpstreamMember().template is<TValue>(); | ||||
|   | ||||
| @@ -16,8 +16,7 @@ template <typename T> | ||||
| struct is_enum { | ||||
|   static const bool value = is_convertible<T, int>::value && | ||||
|                             !is_class<T>::value && !is_integral<T>::value && | ||||
|                             !is_floating_point<T>::value && | ||||
|                             !is_same<T, bool>::value; | ||||
|                             !is_floating_point<T>::value; | ||||
| }; | ||||
|  | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
|   | ||||
| @@ -25,9 +25,7 @@ struct is_integral { | ||||
|       is_same<T, signed __int64>::value || | ||||
|       is_same<T, unsigned __int64>::value || | ||||
| #endif | ||||
|       is_same<T, char>::value; | ||||
|  | ||||
|   // CAUTION: differs from std::is_integral as it doesn't include bool | ||||
|       is_same<T, char>::value || is_same<T, bool>::value; | ||||
| }; | ||||
|  | ||||
| template <typename T> | ||||
|   | ||||
| @@ -53,8 +53,9 @@ struct VariantConstAs<ArrayRef> { | ||||
| // --- | ||||
|  | ||||
| template <typename T> | ||||
| inline typename enable_if<is_integral<T>::value, T>::type variantAs( | ||||
|     const VariantData* data) { | ||||
| inline typename enable_if<is_integral<T>::value && !is_same<bool, T>::value, | ||||
|                           T>::type | ||||
| variantAs(const VariantData* data) { | ||||
|   ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T); | ||||
|   return data != 0 ? data->asIntegral<T>() : T(0); | ||||
| } | ||||
|   | ||||
| @@ -6,8 +6,7 @@ | ||||
|  | ||||
| #include <ArduinoJson/Configuration.hpp> | ||||
| #include <ArduinoJson/Misc/Visitable.hpp> | ||||
| #include <ArduinoJson/Numbers/Float.hpp> | ||||
| #include <ArduinoJson/Numbers/Integer.hpp> | ||||
| #include <ArduinoJson/Numbers/arithmeticCompare.hpp> | ||||
| #include <ArduinoJson/Polyfills/type_traits.hpp> | ||||
| #include <ArduinoJson/Strings/IsString.hpp> | ||||
|  | ||||
| @@ -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 <typename T, typename Enable = void> | ||||
| struct Comparer; | ||||
|  | ||||
| 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; | ||||
|   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 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> | ||||
| 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; | ||||
|   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<Float>(rhs)); | ||||
|     result = arithmeticCompare(lhs, rhs); | ||||
|   } | ||||
|   void visitString(const char *) {} | ||||
|   void visitRawJson(const char *, size_t) {} | ||||
|  | ||||
|   void visitNegativeInteger(UInt lhs) { | ||||
|     result = -sign2(static_cast<T>(lhs) + rhs); | ||||
|     result = arithmeticCompareNegateLeft(lhs, rhs); | ||||
|   } | ||||
|  | ||||
|   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 Comparer<bool, void> { | ||||
|   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<int>(lhs - rhs); | ||||
| struct NullComparer : ComparerBase { | ||||
|   void visitNull() { | ||||
|     result = COMPARE_RESULT_EQUAL; | ||||
|   } | ||||
|   void visitNull() {} | ||||
| }; | ||||
|  | ||||
| #if ARDUINOJSON_HAS_NULLPTR | ||||
| template <> | ||||
| struct Comparer<decltype(nullptr), void> { | ||||
|   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<decltype(nullptr), void> : NullComparer { | ||||
|   explicit Comparer(decltype(nullptr)) : NullComparer() {} | ||||
| }; | ||||
| #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> | ||||
| int VariantRefBase<TData>::compare(const T &rhs) const { | ||||
|   Comparer<T> comparer(rhs); | ||||
|   if (_data) | ||||
|     _data->accept(comparer); | ||||
|   else | ||||
|     comparer.visitNull(); | ||||
| struct Comparer<T, typename enable_if<IsVisitable<T>::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<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; | ||||
| } | ||||
|  | ||||
| inline int variantCompare(const VariantData *a, const VariantData *b) { | ||||
|   return compare(VariantConstRef(a), VariantConstRef(b)); | ||||
| } | ||||
|  | ||||
| }  // 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 { | ||||
|     return (_flags & VALUE_IS_ARRAY) != 0; | ||||
|   } | ||||
|   | ||||
| @@ -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(); | ||||
|   | ||||
| @@ -5,12 +5,16 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <ArduinoJson/Misc/Visitable.hpp> | ||||
| #include <ArduinoJson/Numbers/arithmeticCompare.hpp> | ||||
| #include <ArduinoJson/Polyfills/attributes.hpp> | ||||
| #include <ArduinoJson/Polyfills/type_traits.hpp> | ||||
| #include <ArduinoJson/Variant/VariantAs.hpp> | ||||
|  | ||||
| namespace ARDUINOJSON_NAMESPACE { | ||||
|  | ||||
| template <typename T1, typename T2> | ||||
| CompareResult compare(const T1 &lhs, const T2 &rhs);  // VariantCompare.cpp | ||||
|  | ||||
| template <typename TVariant> | ||||
| struct VariantOperators { | ||||
|   // Returns the default value if the VariantRef is undefined of incompatible | ||||
| @@ -33,125 +37,127 @@ struct VariantOperators { | ||||
|   // value == TVariant | ||||
|   template <typename T> | ||||
|   friend bool operator==(T *lhs, TVariant rhs) { | ||||
|     return rhs.compare(lhs) == 0; | ||||
|     return compare(rhs, lhs) == COMPARE_RESULT_EQUAL; | ||||
|   } | ||||
|   template <typename T> | ||||
|   friend typename enable_if<!IsVisitable<T>::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 <typename T> | ||||
|   friend bool operator==(TVariant lhs, T *rhs) { | ||||
|     return lhs.compare(rhs) == 0; | ||||
|     return compare(lhs, rhs) == COMPARE_RESULT_EQUAL; | ||||
|   } | ||||
|   template <typename T> | ||||
|   friend typename enable_if<!IsVisitable<T>::value, bool>::type operator==( | ||||
|       TVariant lhs, const T &rhs) { | ||||
|     return lhs.compare(rhs) == 0; | ||||
|     return compare(lhs, rhs) == COMPARE_RESULT_EQUAL; | ||||
|   } | ||||
|  | ||||
|   // value != TVariant | ||||
|   template <typename T> | ||||
|   friend bool operator!=(T *lhs, TVariant rhs) { | ||||
|     return rhs.compare(lhs) != 0; | ||||
|     return compare(rhs, lhs) != COMPARE_RESULT_EQUAL; | ||||
|   } | ||||
|   template <typename T> | ||||
|   friend typename enable_if<!IsVisitable<T>::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 <typename T> | ||||
|   friend bool operator!=(TVariant lhs, T *rhs) { | ||||
|     return lhs.compare(rhs) != 0; | ||||
|     return compare(lhs, rhs) != COMPARE_RESULT_EQUAL; | ||||
|   } | ||||
|   template <typename T> | ||||
|   friend typename enable_if<!IsVisitable<T>::value, bool>::type operator!=( | ||||
|       TVariant lhs, const T &rhs) { | ||||
|     return lhs.compare(rhs) != 0; | ||||
|     return compare(lhs, rhs) != COMPARE_RESULT_EQUAL; | ||||
|   } | ||||
|  | ||||
|   // value < TVariant | ||||
|   template <typename T> | ||||
|   friend bool operator<(T *lhs, TVariant rhs) { | ||||
|     return rhs.compare(lhs) > 0; | ||||
|     return compare(rhs, lhs) == COMPARE_RESULT_GREATER; | ||||
|   } | ||||
|   template <typename T> | ||||
|   friend bool operator<(const T &lhs, TVariant rhs) { | ||||
|     return rhs.compare(lhs) > 0; | ||||
|     return compare(rhs, lhs) == COMPARE_RESULT_GREATER; | ||||
|   } | ||||
|  | ||||
|   // TVariant < value | ||||
|   template <typename T> | ||||
|   friend bool operator<(TVariant lhs, T *rhs) { | ||||
|     return lhs.compare(rhs) < 0; | ||||
|     return compare(lhs, rhs) == COMPARE_RESULT_LESS; | ||||
|   } | ||||
|   template <typename T> | ||||
|   friend bool operator<(TVariant lhs, const T &rhs) { | ||||
|     return lhs.compare(rhs) < 0; | ||||
|   friend typename enable_if<!IsVisitable<T>::value, bool>::type operator<( | ||||
|       TVariant lhs, const T &rhs) { | ||||
|     return compare(lhs, rhs) == COMPARE_RESULT_LESS; | ||||
|   } | ||||
|  | ||||
|   // value <= TVariant | ||||
|   template <typename T> | ||||
|   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> | ||||
|   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 <typename T> | ||||
|   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> | ||||
|   friend bool operator<=(TVariant lhs, const T &rhs) { | ||||
|     return lhs.compare(rhs) <= 0; | ||||
|   friend typename enable_if<!IsVisitable<T>::value, bool>::type operator<=( | ||||
|       TVariant lhs, const T &rhs) { | ||||
|     return (compare(lhs, rhs) & COMPARE_RESULT_LESS_OR_EQUAL) != 0; | ||||
|   } | ||||
|  | ||||
|   // value > TVariant | ||||
|   template <typename T> | ||||
|   friend bool operator>(T *lhs, TVariant rhs) { | ||||
|     return rhs.compare(lhs) < 0; | ||||
|     return compare(rhs, lhs) == COMPARE_RESULT_LESS; | ||||
|   } | ||||
|   template <typename T> | ||||
|   friend bool operator>(const T &lhs, TVariant rhs) { | ||||
|     return rhs.compare(lhs) < 0; | ||||
|     return compare(rhs, lhs) == COMPARE_RESULT_LESS; | ||||
|   } | ||||
|  | ||||
|   // TVariant > value | ||||
|   template <typename T> | ||||
|   friend bool operator>(TVariant lhs, T *rhs) { | ||||
|     return lhs.compare(rhs) > 0; | ||||
|     return compare(lhs, rhs) == COMPARE_RESULT_GREATER; | ||||
|   } | ||||
|   template <typename T> | ||||
|   friend bool operator>(TVariant lhs, const T &rhs) { | ||||
|     return lhs.compare(rhs) > 0; | ||||
|   friend typename enable_if<!IsVisitable<T>::value, bool>::type operator>( | ||||
|       TVariant lhs, const T &rhs) { | ||||
|     return compare(lhs, rhs) == COMPARE_RESULT_GREATER; | ||||
|   } | ||||
|  | ||||
|   // value >= TVariant | ||||
|   template <typename T> | ||||
|   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> | ||||
|   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 <typename T> | ||||
|   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> | ||||
|   friend bool operator>=(TVariant lhs, const T &rhs) { | ||||
|     return lhs.compare(rhs) >= 0; | ||||
|   friend typename enable_if<!IsVisitable<T>::value, bool>::type operator>=( | ||||
|       TVariant lhs, const T &rhs) { | ||||
|     return (compare(lhs, rhs) & COMPARE_RESULT_GREATER_OR_EQUAL) != 0; | ||||
|   } | ||||
| }; | ||||
| }  // namespace ARDUINOJSON_NAMESPACE | ||||
|   | ||||
| @@ -42,8 +42,10 @@ class VariantRefBase { | ||||
|   // bool is<unsigned int>() const; | ||||
|   // bool is<unsigned long>() const; | ||||
|   template <typename T> | ||||
|   FORCE_INLINE typename enable_if<is_integral<T>::value, bool>::type is() | ||||
|       const { | ||||
|   FORCE_INLINE | ||||
|       typename enable_if<is_integral<T>::value && !is_same<bool, T>::value, | ||||
|                          bool>::type | ||||
|       is() const { | ||||
|     return variantIsInteger<T>(_data); | ||||
|   } | ||||
|   // | ||||
| @@ -108,9 +110,6 @@ class VariantRefBase { | ||||
|     return variantIsInteger<int>(_data); | ||||
|   } | ||||
|  | ||||
|   template <typename T> | ||||
|   int compare(const T &) const;  // VariantCompare.cpp | ||||
|  | ||||
|   FORCE_INLINE bool isNull() const { | ||||
|     return variantIsNull(_data); | ||||
|   } | ||||
| @@ -188,7 +187,8 @@ class VariantRef : public VariantRefBase<VariantData>, | ||||
|   // set(unsigned long) | ||||
|   template <typename T> | ||||
|   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); | ||||
|   } | ||||
|  | ||||
| @@ -262,14 +262,6 @@ class VariantRef : public VariantRefBase<VariantData>, | ||||
|     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<ArrayRef>() | ||||
| @@ -407,13 +399,5 @@ class VariantConstRef : public VariantRefBase<const VariantData>, | ||||
|       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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user