|
|
@@ -93,7 +93,7 @@ public:
|
|
|
SimpleAdapter(JSON * value = nullptr) : value_(value) {}
|
|
|
SimpleAdapter(JSON & value) : value_(&value) {}
|
|
|
|
|
|
- size_t array_size() const { return self().as_array().size(); }
|
|
|
+ size_t array_size() const final { return self().as_array().size(); }
|
|
|
|
|
|
CRTP operator[](size_t index) const { return self().as_array()[index]; }
|
|
|
|
|
|
@@ -107,7 +107,7 @@ public:
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
- size_t object_size() const { return self().as_object().size(); }
|
|
|
+ size_t object_size() const final { return self().as_object().size(); }
|
|
|
|
|
|
bool contains(std::string const & key) const { return self().as_object().contains(key); }
|
|
|
|
|
|
@@ -127,6 +127,73 @@ public:
|
|
|
return std::make_unique<GenericConst<value_type>>(const_value());
|
|
|
}
|
|
|
|
|
|
+ template <typename Other>
|
|
|
+ requires std::totally_ordered_with<JSON, typename Other::value_type> std::strong_ordering
|
|
|
+ operator<=>(SimpleAdapter const & rhs) const {
|
|
|
+ using ord = std::strong_ordering;
|
|
|
+ if (value_ == rhs.value_) {
|
|
|
+ return std::strong_ordering::equal;
|
|
|
+ }
|
|
|
+ if (value_ && rhs.value_) {
|
|
|
+ return *value_ <=> *rhs.value_;
|
|
|
+ }
|
|
|
+ if (value_) {
|
|
|
+ return type() == Type::Null ? ord::equivalent : ord::greater;
|
|
|
+ }
|
|
|
+ return rhs.type() == Type::Null ? ord::equivalent : ord::less;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool equals(Adapter const & rhs, bool strict = false) const final {
|
|
|
+ Type const rhs_type = rhs.type();
|
|
|
+ if (strict && rhs_type != type()) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // TODO(samjaffe): Needs type coercion
|
|
|
+ switch (rhs_type) {
|
|
|
+ case Type::Null:
|
|
|
+ return const_value().isNull();
|
|
|
+ case Type::Boolean:
|
|
|
+ return rhs.as_boolean() == as_boolean();
|
|
|
+ case Type::Integer:
|
|
|
+ return rhs.as_integer() == as_integer();
|
|
|
+ case Type::Number:
|
|
|
+ return rhs.as_number() == as_number();
|
|
|
+ case Type::String:
|
|
|
+ return rhs.as_string() == as_string();
|
|
|
+ case Type::Array: {
|
|
|
+ auto array = this->as_array();
|
|
|
+ if (rhs.array_size() != array.size()) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool rval = true;
|
|
|
+ size_t index = 0;
|
|
|
+ rhs.apply_array([&, this](adapter::Adapter const & elem) {
|
|
|
+ // Short-Circuit OK
|
|
|
+ rval = rval && array[index].equals(elem, strict);
|
|
|
+ ++index;
|
|
|
+ return Status::Accept;
|
|
|
+ });
|
|
|
+ return rval;
|
|
|
+ }
|
|
|
+ case Type::Object: {
|
|
|
+ auto object = this->as_object();
|
|
|
+ if (rhs.object_size() != object.size()) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool rval = true;
|
|
|
+ rhs.apply_object([&, this](std::string const & key, adapter::Adapter const & elem) {
|
|
|
+ // Short-Circuit OK
|
|
|
+ rval = rval && object.contains(key) && object[key].equals(elem, strict);
|
|
|
+ return Status::Accept;
|
|
|
+ });
|
|
|
+ return rval;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
protected:
|
|
|
JSON * value() const { return value_; }
|
|
|
JSON const & const_value() const { return value_ ? *value_ : AdapterTraits<JSON>::const_empty(); }
|