浏览代码

refactor: replace PropertiesContraint and DependenciesConstraint members w/ unordered_map

Sam Jaffe 1 月之前
父节点
当前提交
e3acbe59f8

+ 14 - 15
include/jvalidate/constraint.h

@@ -1154,12 +1154,12 @@ public:
   static auto properties(detail::ParserContext<A> const & context) {
     EXPECT(context.schema.type() == adapter::Type::Object);
 
-    std::map<std::string, schema::Node const *> rval;
+    constraint::PropertiesConstraint rval;
     for (auto [prop, subschema] : context.schema.as_object()) {
-      rval.emplace(prop, context.child(subschema, prop).node());
+      rval.properties.emplace(prop, context.child(subschema, prop).node());
     }
 
-    return ptr(constraint::PropertiesConstraint{rval});
+    return ptr(std::move(rval));
   }
 
   /**
@@ -1310,26 +1310,25 @@ public:
   static auto dependencies(detail::ParserContext<A> const & context) {
     EXPECT(context.schema.type() == adapter::Type::Object);
 
-    std::map<std::string, schema::Node const *> schemas;
-    std::map<std::string, std::unordered_set<std::string>> required;
+    constraint::DependenciesConstraint rval;
     for (auto [prop, subschema] : context.schema.as_object()) {
       if (subschema.type() == adapter::Type::Array) {
         // Option 1) dependentRequired
         for (auto key : subschema.as_array()) {
           EXPECT(key.type() == adapter::Type::String);
-          required[prop].insert(key.as_string());
+          rval.required[prop].insert(key.as_string());
         }
       } else if (context.vocab->version() <= schema::Version::Draft03 &&
                  subschema.type() == adapter::Type::String) {
         // Option 2) Special single-element dependentRequired in Draft03
-        required[prop].insert(subschema.as_string());
+        rval.required[prop].insert(subschema.as_string());
       } else {
         // Option 3) dependentSchemas
-        schemas.emplace(prop, context.child(subschema, prop).node());
+        rval.subschemas.emplace(prop, context.child(subschema, prop).node());
       }
     }
 
-    return ptr(constraint::DependenciesConstraint{.subschemas = schemas, .required = required});
+    return ptr(std::move(rval));
   }
 
   /**
@@ -1355,12 +1354,12 @@ public:
   static auto dependentSchemas(detail::ParserContext<A> const & context) {
     EXPECT(context.schema.type() == adapter::Type::Object);
 
-    std::map<std::string, schema::Node const *> rval;
+    constraint::DependenciesConstraint rval;
     for (auto [prop, subschema] : context.schema.as_object()) {
-      rval.emplace(prop, context.child(subschema, prop).node());
+      rval.subschemas.emplace(prop, context.child(subschema, prop).node());
     }
 
-    return ptr(constraint::DependenciesConstraint{.subschemas = rval});
+    return ptr(std::move(rval));
   }
 
   /**
@@ -1385,16 +1384,16 @@ public:
   static auto dependentRequired(detail::ParserContext<A> const & context) {
     EXPECT(context.schema.type() == adapter::Type::Object);
 
-    std::map<std::string, std::unordered_set<std::string>> rval;
+    constraint::DependenciesConstraint rval;
     for (auto [prop, subschema] : context.schema.as_object()) {
       EXPECT(subschema.type() == adapter::Type::Array);
       for (auto key : subschema.as_array()) {
         EXPECT(key.type() == adapter::Type::String);
-        rval[prop].insert(key.as_string());
+        rval.required[prop].insert(key.as_string());
       }
     }
 
-    return ptr(constraint::DependenciesConstraint{.subschemas = {}, .required = rval});
+    return ptr(std::move(rval));
   }
 };
 }

+ 3 - 3
include/jvalidate/constraint/object_constraint.h

@@ -38,8 +38,8 @@ struct AdditionalPropertiesConstraint {
  * https://json-schema.org/draft/2020-12/json-schema-validation#section-6.5.4
  */
 struct DependenciesConstraint {
-  std::map<std::string, schema::Node const *> subschemas;
-  std::map<std::string, std::unordered_set<std::string>> required;
+  std::unordered_map<std::string, schema::Node const *> subschemas;
+  std::unordered_map<std::string, std::unordered_set<std::string>> required;
 };
 
 /**
@@ -87,7 +87,7 @@ struct PatternPropertiesConstraint {
  * https://json-schema.org/draft/2020-12/json-schema-core#section-10.3.2.1
  */
 struct PropertiesConstraint {
-  std::map<std::string, schema::Node const *> properties;
+  std::unordered_map<std::string, schema::Node const *> properties;
 };
 
 /**

+ 0 - 1
include/jvalidate/detail/dynamic_reference_context.h

@@ -2,7 +2,6 @@
 
 #include <cstdlib>
 #include <deque>
-#include <map>
 #include <optional>
 
 #include <jvalidate/detail/anchor.h>

+ 5 - 8
include/jvalidate/validation_result.h

@@ -2,7 +2,6 @@
 
 #include <algorithm>
 #include <cstdlib>
-#include <map>
 #include <ostream>
 #include <string>
 #include <unordered_map>
@@ -87,14 +86,11 @@ public:
    * }
    */
   friend std::ostream & operator<<(std::ostream & os, ValidationResult const & result) {
-    auto sorted = []<typename K, typename V>(std::unordered_map<K, V> const & container) {
-      return std::map<K, V const &>(container.begin(), container.end());
-    };
     char const * div = "\n";
     os << "{\n" << indent(1) << R"("valid": )" << (result.valid_ ? "true" : "false") << ',' << '\n';
     os << indent(1) << R"("details": [)";
-    for (auto const & [doc_path, by_schema] : sorted(result.results_)) {
-      for (auto const & [schema_path, local] : sorted(by_schema)) {
+    for (auto const & [doc_path, by_schema] : result.results_) {
+      for (auto const & [schema_path, local] : by_schema) {
         os << std::exchange(div, ",\n") << indent(2) << '{' << '\n';
         os << indent(3) << R"("valid": )" << (local.valid ? "true" : "false") << ',' << '\n';
         os << indent(3) << R"("evaluationPath": ")" << schema_path << '"' << ',' << '\n';
@@ -227,8 +223,9 @@ public:
 
 private:
   /**
-   * @brief Transfer the contents of another ValidationResult into this one using
-   * {@see std::map::merge} to transfer the data minimizing the need for copy/move.
+   * @brief Transfer the contents of another ValidationResult into this one
+   * using {@see std::unordered_map::merge} to transfer the data minimizing the
+   * need for copy/move.
    *
    * @param result The ValidationResult being consumed
    */

+ 12 - 17
include/jvalidate/validation_visitor.h

@@ -485,28 +485,23 @@ private:
                Adapter auto const & document) const {
     NOOP_UNLESS_TYPE(Object);
 
-    auto object = document.as_object();
     Status rval = Status::Accept;
-    for (auto const & [key, subschema] : cons.subschemas) {
-      if (not object.contains(key)) {
-        continue;
-      }
-
-      rval &= validate_subschema(subschema, document, key);
-      BREAK_EARLY_IF_NO_RESULT_TREE();
-    }
 
-    for (auto [key, required] : cons.required) {
-      if (not object.contains(key)) {
-        continue;
+    std::unordered_set<std::string> properties;
+    for (auto const & [key, child] : document.as_object()) {
+      properties.insert(key);
+      if (auto it = cons.subschemas.find(key); it != cons.subschemas.end()) {
+        rval &= validate_subschema(it->second, document, key);
+        BREAK_EARLY_IF_NO_RESULT_TREE();
       }
+    }
 
-      for (auto const & [key, _] : object) {
-        required.erase(key);
+    auto has_property = [&properties](auto const & key) { return properties.contains(key); };
+    for (auto const & [key, required] : cons.required) {
+      if (has_property(key) and not std::ranges::all_of(required, has_property)) {
+        rval &= required.empty();
+        BREAK_EARLY_IF_NO_RESULT_TREE();
       }
-
-      rval &= required.empty();
-      BREAK_EARLY_IF_NO_RESULT_TREE();
     }
 
     return rval;