Quellcode durchsuchen

refactor: remove PolyConstraint by generalizing Not/AllOf/AnyOf constraints

Sam Jaffe vor 1 Jahr
Ursprung
Commit
d9d0c607f0

+ 9 - 6
include/jvalidate/constraint.h

@@ -202,13 +202,13 @@ public:
       ++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) {
@@ -521,8 +521,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> {

+ 13 - 3
include/jvalidate/validation_visitor.h

@@ -96,7 +96,7 @@ public:
 
     std::set<size_t> unmatched;
     size_t i = 0;
-    for (schema::Node const * subschema : cons.children) {
+    for (auto const & subschema : cons.children) {
       if (auto stat = validate_subschema(subschema, i); stat == Status::Reject) {
         rval = Status::Reject;
         unmatched.insert(i);
@@ -115,7 +115,7 @@ public:
     size_t i = 0;
 
     Status rval = Status::Reject;
-    for (schema::Node const * subschema : cons.children) {
+    for (auto const & subschema : cons.children) {
       if (validate_subschema(subschema, i)) {
         rval = Status::Accept;
       }
@@ -163,7 +163,7 @@ public:
   Status visit(constraint::ConditionalConstraint const & cons) const {
     VisitedAnnotation * suppress = nullptr;
     std::swap(suppress, visited_);
-    bool const if_result = validate_subschema(cons.if_constraint);
+    bool const if_result(validate_subschema(cons.if_constraint));
     std::swap(suppress, visited_);
 
     if (if_result) {
@@ -592,6 +592,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;