Просмотр исходного кода

Merge branch 'master' into refactor/results/track-error-and-success

# Conflicts:
#	include/jvalidate/validation_visitor.h
Sam Jaffe 1 год назад
Родитель
Сommit
a8d66b5326

+ 16 - 24
include/jvalidate/constraint.h

@@ -14,6 +14,7 @@
 #include <jvalidate/constraint/object_constraint.h>
 #include <jvalidate/constraint/string_constraint.h>
 
+#include <jvalidate/detail/enumerate.h>
 #include <jvalidate/detail/expect.h>
 #include <jvalidate/detail/parser_context.h>
 #include <jvalidate/detail/vocabulary.h>
@@ -190,8 +191,7 @@ public:
     std::vector<schema::Node const *> children;
 
     std::set<adapter::Type> types;
-    size_t index = 0;
-    for (auto subschema : context.schema.as_array()) {
+    for (auto const & [index, subschema] : detail::enumerate(context.schema.as_array())) {
       if (subschema.type() != adapter::Type::String) {
         children.push_back(context.child(subschema, index).node());
       } else if (subschema.as_string() == "any") {
@@ -199,16 +199,15 @@ public:
       } else {
         types.insert(to_type(subschema.as_string()));
       }
-      ++index;
     }
 
-    return constraint::PolyConstraint::AnyOf(
-        std::make_unique<constraint::TypeConstraint>(types),
-        std::make_unique<constraint::AnyOfConstraint>(children));
+    auto rval = std::make_unique<constraint::AnyOfConstraint>(children);
+    rval->children.push_back(std::make_unique<constraint::TypeConstraint>(types));
+    return rval;
   }
 
   static pConstraint disallowDraft3(detail::ParserContext<A> const & context) {
-    return constraint::PolyConstraint::Not(typeDraft3(context));
+    return std::make_unique<constraint::NotConstraint>(typeDraft3(context));
   }
 
   static pConstraint extendsDraft3(detail::ParserContext<A> const & context) {
@@ -218,10 +217,8 @@ public:
       children.push_back(context.node());
       break;
     case adapter::Type::Array: {
-      size_t index = 0;
-      for (auto const & subschema : context.schema.as_array()) {
+      for (auto const & [index, subschema] : detail::enumerate(context.schema.as_array())) {
         children.push_back(context.child(subschema, index).node());
-        ++index;
       }
       break;
     }
@@ -265,10 +262,8 @@ public:
     EXPECT(context.schema.type() == adapter::Type::Array);
 
     std::vector<schema::Node const *> rval;
-    size_t index = 0;
-    for (auto subschema : context.schema.as_array()) {
+    for (auto const & [index, subschema] : detail::enumerate(context.schema.as_array())) {
       rval.push_back(context.child(subschema, index).node());
-      ++index;
     }
 
     return std::make_unique<constraint::AllOfConstraint>(rval);
@@ -278,10 +273,8 @@ public:
     EXPECT(context.schema.type() == adapter::Type::Array);
 
     std::vector<schema::Node const *> rval;
-    size_t index = 0;
-    for (auto subschema : context.schema.as_array()) {
+    for (auto const & [index, subschema] : detail::enumerate(context.schema.as_array())) {
       rval.push_back(context.child(subschema, index).node());
-      ++index;
     }
 
     return std::make_unique<constraint::AnyOfConstraint>(rval);
@@ -291,10 +284,8 @@ public:
     EXPECT(context.schema.type() == adapter::Type::Array);
 
     std::vector<schema::Node const *> rval;
-    size_t index = 0;
-    for (auto subschema : context.schema.as_array()) {
+    for (auto const & [index, subschema] : detail::enumerate(context.schema.as_array())) {
       rval.push_back(context.child(subschema, index).node());
-      ++index;
     }
 
     return std::make_unique<constraint::OneOfConstraint>(rval);
@@ -401,10 +392,8 @@ public:
     EXPECT(context.schema.type() == adapter::Type::Array);
 
     std::vector<schema::Node const *> rval;
-    size_t index = 0;
-    for (auto subschema : context.schema.as_array()) {
+    for (auto const & [index, subschema] : detail::enumerate(context.schema.as_array())) {
       rval.push_back(context.child(subschema, index).node());
-      ++index;
     }
 
     return std::make_unique<constraint::TupleConstraint>(rval);
@@ -521,8 +510,11 @@ public:
     if (required.empty()) {
       return properties(context);
     }
-    return constraint::PolyConstraint::AllOf(
-        properties(context), std::make_unique<constraint::RequiredConstraint>(std::move(required)));
+
+    std::vector<pConstraint> rval;
+    rval.push_back(properties(context));
+    rval.push_back(std::make_unique<constraint::RequiredConstraint>(std::move(required)));
+    return std::make_unique<constraint::AllOfConstraint>(std::move(rval));
   }
 
   static auto propertyNames(detail::ParserContext<A> const & context) {

+ 5 - 0
include/jvalidate/constraint/constraint.h

@@ -1,5 +1,7 @@
 #pragma once
 
+#include <variant>
+
 #include <jvalidate/constraint/visitor.h>
 #include <jvalidate/detail/pointer.h>
 #include <jvalidate/enum.h>
@@ -8,6 +10,9 @@
 
 namespace jvalidate::constraint {
 class Constraint {
+public:
+  using SubConstraint = std::variant<schema::Node const *, std::unique_ptr<Constraint>>;
+
 public:
   virtual ~Constraint() = default;
   virtual Status accept(ConstraintVisitor const & visitor) const = 0;

+ 19 - 43
include/jvalidate/constraint/general_constraint.h

@@ -10,59 +10,34 @@
 #include <jvalidate/status.h>
 
 namespace jvalidate::constraint {
-class PolyConstraint : public Constraint {
-private:
-  std::vector<std::unique_ptr<Constraint>> children_;
-  bool match_all_;
-  bool invert_{false};
-
+class AllOfConstraint : public SimpleConstraint<AllOfConstraint> {
 public:
-  template <typename... Cs> static auto AllOf(Cs &&... cs) {
-    return std::make_unique<PolyConstraint>(PolyConstraint(true, false, std::forward<Cs>(cs)...));
-  }
-
-  template <typename... Cs> static auto AnyOf(Cs &&... cs) {
-    return std::make_unique<PolyConstraint>(PolyConstraint(false, false, std::forward<Cs>(cs)...));
-  }
+  std::vector<SubConstraint> children;
 
-  static auto Not(std::unique_ptr<Constraint> child) {
-    return std::make_unique<PolyConstraint>(PolyConstraint(false, true, std::move(child)));
-  }
+public:
+  AllOfConstraint(std::vector<schema::Node const *> const & children)
+      : children(children.begin(), children.end()) {}
 
-  Status accept(ConstraintVisitor const & visitor) const final {
-    Status rval = Status::Noop;
-    for (auto const & child : children_) {
-      if (match_all_) {
-        rval &= child->accept(visitor);
-      } else {
-        rval |= child->accept(visitor);
-      }
+  AllOfConstraint(std::vector<std::unique_ptr<Constraint>> && children) {
+    for (auto && child : children) {
+      this->children.push_back(std::move(child));
     }
-    return invert_ ? !rval : rval;
   }
-
-private:
-  template <typename... Cs>
-  PolyConstraint(bool match_all, bool invert, Cs &&... cs)
-      : match_all_(match_all), invert_(invert) {
-    (children_.push_back(std::forward<Cs>(cs)), ...);
-  }
-};
-
-class AllOfConstraint : public SimpleConstraint<AllOfConstraint> {
-public:
-  std::vector<schema::Node const *> children;
-
-public:
-  AllOfConstraint(std::vector<schema::Node const *> const & children) : children(children) {}
 };
 
 class AnyOfConstraint : public SimpleConstraint<AnyOfConstraint> {
 public:
-  std::vector<schema::Node const *> children;
+  std::vector<SubConstraint> children;
 
 public:
-  AnyOfConstraint(std::vector<schema::Node const *> const & children) : children(children) {}
+  AnyOfConstraint(std::vector<schema::Node const *> const & children)
+      : children(children.begin(), children.end()) {}
+
+  AnyOfConstraint(std::vector<std::unique_ptr<Constraint>> && children) {
+    for (auto && child : children) {
+      this->children.push_back(std::move(child));
+    }
+  }
 };
 
 class EnumConstraint : public SimpleConstraint<EnumConstraint> {
@@ -101,10 +76,11 @@ public:
 
 class NotConstraint : public SimpleConstraint<NotConstraint> {
 public:
-  schema::Node const * child;
+  SubConstraint child;
 
 public:
   NotConstraint(schema::Node const * child) : child(child) {}
+  NotConstraint(std::unique_ptr<Constraint> && child) : child(std::move(child)) {}
 };
 
 class TypeConstraint : public SimpleConstraint<TypeConstraint> {

+ 67 - 0
include/jvalidate/detail/enumerate.h

@@ -0,0 +1,67 @@
+#pragma once
+
+#if __cplusplus >= 202302L
+#include <ranges>
+#if __cpp_lib_ranges_enumerate >= 202302L
+#define JVALIDATE_USE_STD_RANGES_ENUMERATE
+#endif
+#endif
+
+#ifdef JVALIDATE_USE_STD_RANGES_ENUMERATE
+namespace jvalidate::detail {
+using std::ranges::views::enumerate;
+}
+#else
+
+#include <iterator>
+#include <utility>
+
+#include <jvalidate/detail/deref_proxy.h>
+
+namespace jvalidate::detail {
+
+template <typename It> class enumurate_iterator {
+public:
+  using traits_t = std::iterator_traits<It>;
+
+  using value_type = std::pair<size_t, typename traits_t::value_type>;
+  using reference = std::pair<size_t const &, typename traits_t::reference>;
+  using pointer = DerefProxy<reference>;
+  using difference_type = typename traits_t::difference_type;
+  using iterator_category = typename traits_t::iterator_category;
+
+private:
+  size_t index_ = 0;
+  It iter_;
+
+public:
+  enumurate_iterator(It iter) : iter_(iter) {}
+
+  reference operator*() const { return {index_, *iter_}; }
+  pointer operator->() const { return operator*(); }
+
+  enumurate_iterator & operator++() {
+    ++index_;
+    ++iter_;
+    return *this;
+  }
+
+  friend bool operator==(enumurate_iterator<It> rhs, enumurate_iterator<It> lhs) {
+    return rhs.iter_ == lhs.iter_;
+  }
+  friend bool operator!=(enumurate_iterator<It> rhs, enumurate_iterator<It> lhs) {
+    return rhs.iter_ != lhs.iter_;
+  }
+};
+
+template <typename C> auto enumerate(C && container) {
+  struct {
+    auto begin() const { return enumurate_iterator(c.begin()); }
+    auto end() const { return enumurate_iterator(c.end()); }
+
+    C c;
+  } rval{std::forward<C>(container)};
+  return rval;
+}
+}
+#endif

+ 20 - 15
include/jvalidate/validation_visitor.h

@@ -9,6 +9,7 @@
 #include <jvalidate/constraint/object_constraint.h>
 #include <jvalidate/constraint/string_constraint.h>
 #include <jvalidate/constraint/visitor.h>
+#include <jvalidate/detail/enumerate.h>
 #include <jvalidate/detail/expect.h>
 #include <jvalidate/detail/iostream.h>
 #include <jvalidate/detail/number.h>
@@ -98,13 +99,11 @@ public:
     Status rval = Status::Accept;
 
     std::set<size_t> unmatched;
-    size_t i = 0;
-    for (schema::Node const * subschema : cons.children) {
-      if (auto stat = validate_subschema(subschema, i); stat == Status::Reject) {
+    for (auto const & [index, subschema] : detail::enumerate(cons.children)) {
+      if (auto stat = validate_subschema(subschema, index); stat == Status::Reject) {
         rval = Status::Reject;
-        unmatched.insert(i);
+        unmatched.insert(index);
       }
-      ++i;
       BREAK_EARLY_IF_NO_RESULT_TREE();
     }
 
@@ -115,17 +114,15 @@ public:
   }
 
   Status visit(constraint::AnyOfConstraint const & cons) const {
-    size_t i = 0;
-
     Status rval = Status::Reject;
-    for (schema::Node const * subschema : cons.children) {
-      if (validate_subschema(subschema, i)) {
+
+    for (auto const & [index, subschema] : detail::enumerate(cons.children)) {
+      if (validate_subschema(subschema, index)) {
         rval = Status::Accept;
       }
       if (not visited_ && rval == Status::Accept) {
         break;
       }
-      ++i;
     }
 
     if (rval == Status::Reject) {
@@ -138,12 +135,10 @@ public:
     scoped_state(tracking_, StoreResults::ForAnything);
     std::set<size_t> matches;
 
-    size_t i = 0;
-    for (schema::Node const * subschema : cons.children) {
-      if (validate_subschema(subschema, i)) {
-        matches.insert(i);
+    for (auto const & [index, subschema] : detail::enumerate(cons.children)) {
+      if (validate_subschema(subschema, index)) {
+        matches.insert(index);
       }
-      ++i;
     }
 
     if (matches.size() == 1) {
@@ -612,6 +607,16 @@ private:
     to.insert(from.begin(), from.end());
   }
 
+  template <typename... K>
+  Status validate_subschema(constraint::Constraint::SubConstraint const & subschema,
+                            K const &... keys) const {
+    if (schema::Node const * const * ppschema = std::get_if<0>(&subschema)) {
+      return validate_subschema(*ppschema, keys...);
+    } else {
+      return std::get<1>(subschema)->accept(*this);
+    }
+  }
+
   template <typename... K>
   Status validate_subschema(schema::Node const * subschema, K const &... keys) const {
     VisitedAnnotation annotate;