Add JsonVariantVisitor and use it for comparisons

This commit is contained in:
Benoit Blanchon
2023-07-10 17:34:11 +02:00
parent 7a9feb4d6e
commit 5a9d3422f5
2 changed files with 142 additions and 32 deletions

View File

@ -0,0 +1,115 @@
// ArduinoJson - https://arduinojson.org
// Copyright © 2014-2023, Benoit BLANCHON
// MIT License
#pragma once
#include <ArduinoJson/Array/JsonArray.hpp>
#include <ArduinoJson/Object/JsonObject.hpp>
#include <ArduinoJson/Variant/JsonVariant.hpp>
#include <ArduinoJson/Variant/VariantDataVisitor.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
template <typename TResult>
struct JsonVariantVisitor {
typedef TResult result_type;
TResult visitArray(JsonArrayConst) {
return TResult();
}
TResult visitBoolean(bool) {
return TResult();
}
TResult visitFloat(JsonFloat) {
return TResult();
}
TResult visitSignedInteger(JsonInteger) {
return TResult();
}
TResult visitNull() {
return TResult();
}
TResult visitObject(JsonObjectConst) {
return TResult();
}
TResult visitUnsignedInteger(JsonUInt) {
return TResult();
}
TResult visitRawString(const char*, size_t) {
return TResult();
}
TResult visitString(const char*, size_t) {
return TResult();
}
};
template <typename TVisitor>
class VisitorAdapter {
public:
using result_type = typename TVisitor::result_type;
VisitorAdapter(TVisitor& visitor, const ResourceManager* resources)
: visitor_(&visitor), resources_(resources) {}
result_type visitArray(const ArrayData& array) {
return visitor_->visitArray(JsonArrayConst(&array, resources_));
}
result_type visitObject(const ObjectData& object) {
return visitor_->visitObject(JsonObjectConst(&object, resources_));
}
result_type visitFloat(JsonFloat value) {
return visitor_->visitFloat(value);
}
result_type visitString(const char* s, size_t n) {
return visitor_->visitString(s, n);
}
result_type visitRawString(const char* p, size_t n) {
return visitor_->visitRawString(p, n);
}
result_type visitSignedInteger(JsonInteger value) {
return visitor_->visitSignedInteger(value);
}
result_type visitUnsignedInteger(JsonUInt value) {
return visitor_->visitUnsignedInteger(value);
}
result_type visitBoolean(bool value) {
return visitor_->visitBoolean(value);
}
result_type visitNull() {
return visitor_->visitNull();
}
private:
TVisitor* visitor_;
const ResourceManager* resources_;
};
template <typename TVisitor>
typename TVisitor::result_type accept(JsonVariantConst variant,
TVisitor& visitor) {
auto data = VariantAttorney::getData(variant);
if (!data)
return visitor.visitNull();
auto resources = VariantAttorney::getResourceManager(variant);
VisitorAdapter<TVisitor> adapter(visitor, resources);
return data->accept(adapter);
}
ARDUINOJSON_END_PRIVATE_NAMESPACE

View File

@ -8,11 +8,11 @@
#include <ArduinoJson/Numbers/arithmeticCompare.hpp>
#include <ArduinoJson/Polyfills/type_traits.hpp>
#include <ArduinoJson/Strings/StringAdapters.hpp>
#include <ArduinoJson/Variant/VariantDataVisitor.hpp>
#include <ArduinoJson/Variant/JsonVariantVisitor.hpp>
ARDUINOJSON_BEGIN_PRIVATE_NAMESPACE
struct ComparerBase : VariantDataVisitor<CompareResult> {};
struct ComparerBase : JsonVariantVisitor<CompareResult> {};
template <typename T, typename Enable = void>
struct Comparer;
@ -79,12 +79,12 @@ struct Comparer<decltype(nullptr), void> : NullComparer {
};
struct ArrayComparer : ComparerBase {
const ArrayData* rhs_;
JsonArrayConst rhs_;
explicit ArrayComparer(const ArrayData& rhs) : rhs_(&rhs) {}
explicit ArrayComparer(JsonArrayConst rhs) : rhs_(rhs) {}
CompareResult visitArray(const ArrayData& lhs) {
if (JsonArrayConst(&lhs, nullptr) == JsonArrayConst(rhs_, nullptr))
CompareResult visitArray(JsonArrayConst lhs) {
if (rhs_ == lhs)
return COMPARE_RESULT_EQUAL;
else
return COMPARE_RESULT_DIFFER;
@ -92,12 +92,12 @@ struct ArrayComparer : ComparerBase {
};
struct ObjectComparer : ComparerBase {
const ObjectData* rhs_;
JsonObjectConst rhs_;
explicit ObjectComparer(const ObjectData& rhs) : rhs_(&rhs) {}
explicit ObjectComparer(JsonObjectConst rhs) : rhs_(rhs) {}
CompareResult visitObject(const ObjectData& lhs) {
if (JsonObjectConst(&lhs, nullptr) == JsonObjectConst(rhs_, nullptr))
CompareResult visitObject(JsonObjectConst lhs) {
if (lhs == rhs_)
return COMPARE_RESULT_EQUAL;
else
return COMPARE_RESULT_DIFFER;
@ -124,59 +124,59 @@ struct RawComparer : ComparerBase {
};
struct VariantComparer : ComparerBase {
const VariantData* rhs;
JsonVariantConst rhs;
explicit VariantComparer(const VariantData* value) : rhs(value) {}
explicit VariantComparer(JsonVariantConst value) : rhs(value) {}
CompareResult visitArray(const ArrayData& lhs) {
CompareResult visitArray(JsonArrayConst lhs) {
ArrayComparer comparer(lhs);
return accept(comparer);
return reverseResult(comparer);
}
CompareResult visitObject(const ObjectData& lhs) {
CompareResult visitObject(JsonObjectConst lhs) {
ObjectComparer comparer(lhs);
return accept(comparer);
return reverseResult(comparer);
}
CompareResult visitFloat(JsonFloat lhs) {
Comparer<JsonFloat> comparer(lhs);
return accept(comparer);
return reverseResult(comparer);
}
CompareResult visitString(const char* lhs, size_t) {
Comparer<const char*> comparer(lhs);
return accept(comparer);
return reverseResult(comparer);
}
CompareResult visitRawString(const char* lhsData, size_t lhsSize) {
RawComparer comparer(lhsData, lhsSize);
return accept(comparer);
return reverseResult(comparer);
}
CompareResult visitSignedInteger(JsonInteger lhs) {
Comparer<JsonInteger> comparer(lhs);
return accept(comparer);
return reverseResult(comparer);
}
CompareResult visitUnsignedInteger(JsonUInt lhs) {
Comparer<JsonUInt> comparer(lhs);
return accept(comparer);
return reverseResult(comparer);
}
CompareResult visitBoolean(bool lhs) {
Comparer<bool> comparer(lhs);
return accept(comparer);
return reverseResult(comparer);
}
CompareResult visitNull() {
NullComparer comparer;
return accept(comparer);
return reverseResult(comparer);
}
private:
template <typename TComparer>
CompareResult accept(TComparer& comparer) {
CompareResult reversedResult = VariantData::accept(rhs, comparer);
CompareResult reverseResult(TComparer& comparer) {
CompareResult reversedResult = accept(rhs, comparer);
switch (reversedResult) {
case COMPARE_RESULT_GREATER:
return COMPARE_RESULT_LESS;
@ -193,18 +193,13 @@ struct Comparer<T, typename enable_if<is_convertible<
T, ArduinoJson::JsonVariantConst>::value>::type>
: VariantComparer {
explicit Comparer(const T& value)
: VariantComparer(VariantAttorney::getData(value)) {}
: VariantComparer(static_cast<JsonVariantConst>(value)) {}
};
template <typename T>
CompareResult compare(ArduinoJson::JsonVariantConst lhs, const T& rhs) {
Comparer<T> comparer(rhs);
return VariantData::accept(VariantAttorney::getData(lhs), comparer);
}
inline CompareResult compare(const VariantData* lhs, const VariantData* rhs) {
VariantComparer comparer(rhs);
return VariantData::accept(lhs, comparer);
return accept(lhs, comparer);
}
ARDUINOJSON_END_PRIVATE_NAMESPACE