diff --git a/src/ArduinoJson.hpp b/src/ArduinoJson.hpp index d2a1f630..a5da7a2e 100644 --- a/src/ArduinoJson.hpp +++ b/src/ArduinoJson.hpp @@ -28,6 +28,7 @@ #include "ArduinoJson/Object/MemberProxy.hpp" #include "ArduinoJson/Object/ObjectImpl.hpp" #include "ArduinoJson/Variant/VariantAsImpl.hpp" +#include "ArduinoJson/Variant/VariantCompare.hpp" #include "ArduinoJson/Variant/VariantImpl.hpp" #include "ArduinoJson/Json/JsonDeserializer.hpp" diff --git a/src/ArduinoJson/Array/ElementProxy.hpp b/src/ArduinoJson/Array/ElementProxy.hpp index 24cb1d45..6d5cfdf4 100644 --- a/src/ArduinoJson/Array/ElementProxy.hpp +++ b/src/ArduinoJson/Array/ElementProxy.hpp @@ -5,7 +5,8 @@ #pragma once #include -#include +#include +#include #include #ifdef _MSC_VER @@ -17,6 +18,7 @@ namespace ARDUINOJSON_NAMESPACE { template class ElementProxy : public VariantOperators >, + public VariantShortcuts >, public Visitable { typedef ElementProxy this_type; @@ -77,6 +79,11 @@ 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/Object/MemberProxy.hpp b/src/ArduinoJson/Object/MemberProxy.hpp index 82814250..49602b93 100644 --- a/src/ArduinoJson/Object/MemberProxy.hpp +++ b/src/ArduinoJson/Object/MemberProxy.hpp @@ -5,9 +5,10 @@ #pragma once #include -#include #include +#include #include +#include #include #ifdef _MSC_VER @@ -19,6 +20,7 @@ namespace ARDUINOJSON_NAMESPACE { template class MemberProxy : public VariantOperators >, + public VariantShortcuts >, public Visitable { typedef MemberProxy this_type; @@ -80,6 +82,11 @@ 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/Operators/VariantComparisons.hpp b/src/ArduinoJson/Operators/VariantComparisons.hpp deleted file mode 100644 index b0f93612..00000000 --- a/src/ArduinoJson/Operators/VariantComparisons.hpp +++ /dev/null @@ -1,255 +0,0 @@ -// ArduinoJson - arduinojson.org -// Copyright Benoit Blanchon 2014-2020 -// MIT License - -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace ARDUINOJSON_NAMESPACE { - -class CollectionData; - -template -struct Comparer; - -template -struct Comparer::value>::type> { - T rhs; - int result; - - explicit Comparer(T value) : rhs(value), result(1) {} - - void visitArray(const CollectionData &) {} - void visitObject(const CollectionData &) {} - void visitFloat(Float) {} - void visitString(const char *lhs) { - result = -adaptString(rhs).compare(lhs); - } - void visitRawJson(const char *, size_t) {} - void visitNegativeInteger(UInt) {} - void visitPositiveInteger(UInt) {} - void visitBoolean(bool) {} - void visitNull() { - result = adaptString(rhs).compare(NULL); - } -}; - -template -typename enable_if::value, int>::type sign(const T &value) { - return value < 0 ? -1 : value > 0 ? 1 : 0; -} - -template -typename enable_if::value, int>::type sign(const T &value) { - return value > 0 ? 1 : 0; -} - -template -struct Comparer::value || - is_floating_point::value>::type> { - T rhs; - int result; - - explicit Comparer(T value) : rhs(value), result(1) {} - - void visitArray(const CollectionData &) {} - void visitObject(const CollectionData &) {} - void visitFloat(Float lhs) { - result = sign(lhs - static_cast(rhs)); - } - void visitString(const char *) {} - void visitRawJson(const char *, size_t) {} - void visitNegativeInteger(UInt lhs) { - result = -sign(static_cast(lhs) + rhs); - } - void visitPositiveInteger(UInt lhs) { - result = static_cast(lhs) < rhs ? -1 : static_cast(lhs) > rhs ? 1 : 0; - } - 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); - } - 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; - } -}; -#endif - -template -class VariantComparisons { - private: - template - static int compare(TVariant lhs, const T &rhs) { - Comparer comparer(rhs); - lhs.accept(comparer); - return comparer.result; - } - - public: - // value == TVariant - template - friend bool operator==(T *lhs, TVariant rhs) { - return compare(rhs, lhs) == 0; - } - template - friend typename enable_if::value, bool>::type operator==( - const T &lhs, TVariant rhs) { - return compare(rhs, lhs) == 0; - } - - // TVariant == value - template - friend bool operator==(TVariant lhs, T *rhs) { - return compare(lhs, rhs) == 0; - } - template - friend typename enable_if::value, bool>::type operator==( - TVariant lhs, const T &rhs) { - return compare(lhs, rhs) == 0; - } - - // value != TVariant - template - friend bool operator!=(T *lhs, TVariant rhs) { - return compare(rhs, lhs) != 0; - } - template - friend typename enable_if::value, bool>::type operator!=( - const T &lhs, TVariant rhs) { - return compare(rhs, lhs) != 0; - } - - // TVariant != value - template - friend bool operator!=(TVariant lhs, T *rhs) { - return compare(lhs, rhs) != 0; - } - template - friend typename enable_if::value, bool>::type operator!=( - TVariant lhs, const T &rhs) { - return compare(lhs, rhs) != 0; - } - - // value < TVariant - template - friend bool operator<(T *lhs, TVariant rhs) { - return compare(rhs, lhs) > 0; - } - template - friend bool operator<(const T &lhs, TVariant rhs) { - return compare(rhs, lhs) > 0; - } - - // TVariant < value - template - friend bool operator<(TVariant lhs, T *rhs) { - return compare(lhs, rhs) < 0; - } - template - friend bool operator<(TVariant lhs, const T &rhs) { - return compare(lhs, rhs) < 0; - } - - // value <= TVariant - template - friend bool operator<=(T *lhs, TVariant rhs) { - return compare(rhs, lhs) >= 0; - } - template - friend bool operator<=(const T &lhs, TVariant rhs) { - return compare(rhs, lhs) >= 0; - } - - // TVariant <= value - template - friend bool operator<=(TVariant lhs, T *rhs) { - return compare(lhs, rhs) <= 0; - } - template - friend bool operator<=(TVariant lhs, const T &rhs) { - return compare(lhs, rhs) <= 0; - } - - // value > TVariant - template - friend bool operator>(T *lhs, TVariant rhs) { - return compare(rhs, lhs) < 0; - } - template - friend bool operator>(const T &lhs, TVariant rhs) { - return compare(rhs, lhs) < 0; - } - - // TVariant > value - template - friend bool operator>(TVariant lhs, T *rhs) { - return compare(lhs, rhs) > 0; - } - template - friend bool operator>(TVariant lhs, const T &rhs) { - return compare(lhs, rhs) > 0; - } - - // value >= TVariant - template - friend bool operator>=(T *lhs, TVariant rhs) { - return compare(rhs, lhs) <= 0; - } - template - friend bool operator>=(const T &lhs, TVariant rhs) { - return compare(rhs, lhs) <= 0; - } - - // TVariant >= value - template - friend bool operator>=(TVariant lhs, T *rhs) { - return compare(lhs, rhs) >= 0; - } - template - friend bool operator>=(TVariant lhs, const T &rhs) { - return compare(lhs, rhs) >= 0; - } -}; - -} // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Operators/VariantOperators.hpp b/src/ArduinoJson/Operators/VariantOperators.hpp deleted file mode 100644 index 9e455196..00000000 --- a/src/ArduinoJson/Operators/VariantOperators.hpp +++ /dev/null @@ -1,17 +0,0 @@ -// ArduinoJson - arduinojson.org -// Copyright Benoit Blanchon 2014-2020 -// MIT License - -#pragma once - -#include -#include -#include - -namespace ARDUINOJSON_NAMESPACE { - -template -class VariantOperators : public VariantComparisons, - public VariantOr, - public VariantShortcuts {}; -} // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Operators/VariantOr.hpp b/src/ArduinoJson/Operators/VariantOr.hpp deleted file mode 100644 index 46480872..00000000 --- a/src/ArduinoJson/Operators/VariantOr.hpp +++ /dev/null @@ -1,37 +0,0 @@ -// ArduinoJson - arduinojson.org -// Copyright Benoit Blanchon 2014-2020 -// MIT License - -#pragma once - -#include -#include -#include - -namespace ARDUINOJSON_NAMESPACE { - -template -class VariantOr { - public: - // Returns the default value if the VariantRef is undefined of incompatible - template - T operator|(const T &defaultValue) const { - if (impl()->template is()) - return impl()->template as(); - else - return defaultValue; - } - - // Returns the default value if the VariantRef is undefined of incompatible - // Special case for string: null is treated as undefined - const char *operator|(const char *defaultValue) const { - const char *value = impl()->template as(); - return value ? value : defaultValue; - } - - private: - const TImpl *impl() const { - return static_cast(this); - } -}; -} // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Variant/VariantCompare.hpp b/src/ArduinoJson/Variant/VariantCompare.hpp new file mode 100644 index 00000000..8cc60159 --- /dev/null +++ b/src/ArduinoJson/Variant/VariantCompare.hpp @@ -0,0 +1,129 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace ARDUINOJSON_NAMESPACE { + +class CollectionData; + +template +struct Comparer; + +template +struct Comparer::value>::type> { + T rhs; + int result; + + explicit Comparer(T value) : rhs(value), result(1) {} + + void visitArray(const CollectionData &) {} + void visitObject(const CollectionData &) {} + void visitFloat(Float) {} + void visitString(const char *lhs) { + result = -adaptString(rhs).compare(lhs); + } + void visitRawJson(const char *, size_t) {} + void visitNegativeInteger(UInt) {} + void visitPositiveInteger(UInt) {} + void visitBoolean(bool) {} + void visitNull() { + result = adaptString(rhs).compare(NULL); + } +}; +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> { + T rhs; + int result; + + explicit Comparer(T value) : rhs(value), result(1) {} + + void visitArray(const CollectionData &) {} + void visitObject(const CollectionData &) {} + void visitFloat(Float lhs) { + result = sign2(lhs - static_cast(rhs)); + } + void visitString(const char *) {} + void visitRawJson(const char *, size_t) {} + void visitNegativeInteger(UInt lhs) { + result = -sign2(static_cast(lhs) + rhs); + } + void visitPositiveInteger(UInt lhs) { + result = static_cast(lhs) < rhs ? -1 : static_cast(lhs) > rhs ? 1 : 0; + } + 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); + } + 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; + } +}; +#endif + +template +template +int VariantRefBase::compare(const T &rhs) const { + Comparer comparer(rhs); + if (_data) + _data->accept(comparer); + else + comparer.visitNull(); + return comparer.result; +} + +} // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Variant/VariantOperators.hpp b/src/ArduinoJson/Variant/VariantOperators.hpp new file mode 100644 index 00000000..377c61c5 --- /dev/null +++ b/src/ArduinoJson/Variant/VariantOperators.hpp @@ -0,0 +1,157 @@ +// ArduinoJson - arduinojson.org +// Copyright Benoit Blanchon 2014-2020 +// MIT License + +#pragma once + +#include +#include +#include +#include + +namespace ARDUINOJSON_NAMESPACE { + +template +struct VariantOperators { + // Returns the default value if the VariantRef is undefined of incompatible + template + friend T operator|(const TVariant &variant, const T &defaultValue) { + if (variant.template is()) + return variant.template as(); + else + return defaultValue; + } + + // Returns the default value if the VariantRef is undefined of incompatible + // Special case for string: null is treated as undefined + friend const char *operator|(const TVariant &variant, + const char *defaultValue) { + const char *value = variant.template as(); + return value ? value : defaultValue; + } + + // value == TVariant + template + friend bool operator==(T *lhs, TVariant rhs) { + return rhs.compare(lhs) == 0; + } + template + friend typename enable_if::value, bool>::type operator==( + const T &lhs, TVariant rhs) { + return rhs.compare(lhs) == 0; + } + + // TVariant == value + template + friend bool operator==(TVariant lhs, T *rhs) { + return lhs.compare(rhs) == 0; + } + template + friend typename enable_if::value, bool>::type operator==( + TVariant lhs, const T &rhs) { + return lhs.compare(rhs) == 0; + } + + // value != TVariant + template + friend bool operator!=(T *lhs, TVariant rhs) { + return rhs.compare(lhs) != 0; + } + template + friend typename enable_if::value, bool>::type operator!=( + const T &lhs, TVariant rhs) { + return rhs.compare(lhs) != 0; + } + + // TVariant != value + template + friend bool operator!=(TVariant lhs, T *rhs) { + return lhs.compare(rhs) != 0; + } + template + friend typename enable_if::value, bool>::type operator!=( + TVariant lhs, const T &rhs) { + return lhs.compare(rhs) != 0; + } + + // value < TVariant + template + friend bool operator<(T *lhs, TVariant rhs) { + return rhs.compare(lhs) > 0; + } + template + friend bool operator<(const T &lhs, TVariant rhs) { + return rhs.compare(lhs) > 0; + } + + // TVariant < value + template + friend bool operator<(TVariant lhs, T *rhs) { + return lhs.compare(rhs) < 0; + } + template + friend bool operator<(TVariant lhs, const T &rhs) { + return lhs.compare(rhs) < 0; + } + + // value <= TVariant + template + friend bool operator<=(T *lhs, TVariant rhs) { + return rhs.compare(lhs) >= 0; + } + template + friend bool operator<=(const T &lhs, TVariant rhs) { + return rhs.compare(lhs) >= 0; + } + + // TVariant <= value + template + friend bool operator<=(TVariant lhs, T *rhs) { + return lhs.compare(rhs) <= 0; + } + template + friend bool operator<=(TVariant lhs, const T &rhs) { + return lhs.compare(rhs) <= 0; + } + + // value > TVariant + template + friend bool operator>(T *lhs, TVariant rhs) { + return rhs.compare(lhs) < 0; + } + template + friend bool operator>(const T &lhs, TVariant rhs) { + return rhs.compare(lhs) < 0; + } + + // TVariant > value + template + friend bool operator>(TVariant lhs, T *rhs) { + return lhs.compare(rhs) > 0; + } + template + friend bool operator>(TVariant lhs, const T &rhs) { + return lhs.compare(rhs) > 0; + } + + // value >= TVariant + template + friend bool operator>=(T *lhs, TVariant rhs) { + return rhs.compare(lhs) <= 0; + } + template + friend bool operator>=(const T &lhs, TVariant rhs) { + return rhs.compare(lhs) <= 0; + } + + // TVariant >= value + template + friend bool operator>=(TVariant lhs, T *rhs) { + return lhs.compare(rhs) >= 0; + } + template + friend bool operator>=(TVariant lhs, const T &rhs) { + return lhs.compare(rhs) >= 0; + } +}; +} // namespace ARDUINOJSON_NAMESPACE diff --git a/src/ArduinoJson/Variant/VariantRef.hpp b/src/ArduinoJson/Variant/VariantRef.hpp index 6b2006ab..9bbfb8a6 100644 --- a/src/ArduinoJson/Variant/VariantRef.hpp +++ b/src/ArduinoJson/Variant/VariantRef.hpp @@ -9,11 +9,12 @@ #include #include -#include #include #include #include +#include #include +#include namespace ARDUINOJSON_NAMESPACE { @@ -107,6 +108,9 @@ class VariantRefBase { return variantIsInteger(_data); } + template + int compare(const T &) const; // VariantCompare.cpp + FORCE_INLINE bool isNull() const { return variantIsNull(_data); } @@ -141,6 +145,7 @@ class VariantRefBase { // - a reference to a ArrayRef or ObjectRef class VariantRef : public VariantRefBase, public VariantOperators, + public VariantShortcuts, public Visitable { typedef VariantRefBase base_type; friend class VariantConstRef; @@ -336,6 +341,7 @@ class VariantRef : public VariantRefBase, class VariantConstRef : public VariantRefBase, public VariantOperators, + public VariantShortcuts, public Visitable { typedef VariantRefBase base_type; friend class VariantRef; diff --git a/src/ArduinoJson/Operators/VariantShortcuts.hpp b/src/ArduinoJson/Variant/VariantShortcuts.hpp similarity index 100% rename from src/ArduinoJson/Operators/VariantShortcuts.hpp rename to src/ArduinoJson/Variant/VariantShortcuts.hpp