فهرست منبع

refactor: forward-port enumerate for nicer flow

Sam Jaffe 1 سال پیش
والد
کامیت
f54b59f204
3فایلهای تغییر یافته به همراه85 افزوده شده و 33 حذف شده
  1. 7 18
      include/jvalidate/constraint.h
  2. 67 0
      include/jvalidate/detail/enumerate.h
  3. 11 15
      include/jvalidate/validation_visitor.h

+ 7 - 18
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,7 +199,6 @@ public:
       } else {
         types.insert(to_type(subschema.as_string()));
       }
-      ++index;
     }
 
     auto rval = std::make_unique<constraint::AnyOfConstraint>(children);
@@ -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);

+ 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

+ 11 - 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>
@@ -95,13 +96,11 @@ public:
     Status rval = Status::Accept;
 
     std::set<size_t> unmatched;
-    size_t i = 0;
-    for (auto 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();
     }
 
@@ -112,17 +111,15 @@ public:
   }
 
   Status visit(constraint::AnyOfConstraint const & cons) const {
-    size_t i = 0;
-
     Status rval = Status::Reject;
-    for (auto 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) {
@@ -133,12 +130,11 @@ public:
 
   Status visit(constraint::OneOfConstraint const & cons) const {
     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) {