]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
crimson: introduce syntactic sugar for visiting errorator.
authorRadoslaw Zarzynski <rzarzyns@redhat.com>
Thu, 12 Sep 2019 23:02:56 +0000 (01:02 +0200)
committerRadoslaw Zarzynski <rzarzyns@redhat.com>
Wed, 20 Nov 2019 19:37:40 +0000 (20:37 +0100)
Signed-off-by: Radoslaw Zarzynski <rzarzyns@redhat.com>
src/crimson/common/errorator.h
src/crimson/osd/pg_backend.cc

index 2820f25ca7719b0a2f6ae54b3b182eeace544ecd..faa714afc94b66d311717d0fdb9ca48d57d1f01b 100644 (file)
@@ -31,6 +31,15 @@ struct unthrowable_wrapper {
     return instance;
   }
 
+  template<class Func>
+  static auto handle(Func&& func) {
+    return [
+      func = std::forward<Func>(func)
+    ] (const unthrowable_wrapper&) mutable -> decltype(auto) {
+      return std::invoke(std::forward<Func>(func));
+    };
+  }
+
 private:
   // can be used only to initialize the `instance` member
   explicit unthrowable_wrapper() = default;
@@ -99,6 +108,34 @@ public:
   }
 };
 
+namespace _impl {
+  template <class T> struct always_false : std::false_type {};
+};
+
+template <class FuncHead, class... FuncTail>
+static constexpr auto composer(FuncHead&& head, FuncTail&&... tail) {
+  return [
+    head = std::forward<FuncHead>(head),
+    // perfect forwarding in lambda's closure isn't availble in C++17
+    // using tuple as workaround; see: https://stackoverflow.com/a/49902823
+    tail = std::make_tuple(std::forward<FuncTail>(tail)...)
+  ] (auto&&... args) mutable -> decltype(auto) {
+    if constexpr (std::is_invocable_v<FuncHead, decltype(args)...>) {
+      return std::invoke(std::forward<FuncHead>(head),
+                         std::forward<decltype(args)>(args)...);
+    } else if constexpr (sizeof...(FuncTail) > 0) {
+      using next_composer_t = decltype(composer<FuncTail...>);
+      auto&& next = std::apply<next_composer_t>(composer<FuncTail...>,
+                                                std::move(tail));
+      return std::invoke(std::move(next),
+                         std::forward<decltype(args)>(args)...);
+    } else {
+      static_assert(
+        _impl::always_false<FuncHead>::value, "composition is not exhaustive");
+    }
+  };
+}
+
 template <class... AllowedErrors>
 struct errorator {
   template <class T, class = std::void_t<>>
@@ -270,6 +307,23 @@ struct errorator {
         })};
     }
 
+    // taking ErrorFuncOne and ErrorFuncTwo separately from ErrorFuncTail
+    // to avoid SFINAE
+    template <class ValueFunc,
+              class ErrorFuncOne,
+              class ErrorFuncTwo,
+              class... ErrorFuncTail>
+    auto safe_then(ValueFunc&& value_func,
+                   ErrorFuncOne&& error_func_one,
+                   ErrorFuncTwo&& error_func_two,
+                   ErrorFuncTail&&... error_func_tail) {
+      return safe_then(
+        std::forward<ValueFunc>(value_func),
+        composer(std::forward<ErrorFuncOne>(error_func_one),
+                 std::forward<ErrorFuncTwo>(error_func_two),
+                 std::forward<ErrorFuncTail>(error_func_tail)...));
+    }
+
     template <class Func>
     void then(Func&&) = delete;
 
index b20c2ae3c4d8a8ff260056f17a406586003b072c..dec2fb84b60f2808a658596e44832a75a0c38e83 100644 (file)
@@ -125,17 +125,16 @@ PGBackend::_load_os(const hobject_t& oid)
         os_cache.insert(oid,
           std::make_unique<ObjectState>(object_info_t{bl}, true /* exists */)));
     },
-    [oid, this] (const auto& e) {
-      using T = std::decay_t<decltype(e)>;
-      if constexpr (std::is_same_v<T, crimson::ct_error::enoent> ||
-                    std::is_same_v<T, crimson::ct_error::enodata>) {
-        return seastar::make_ready_future<cached_os_t>(
-          os_cache.insert(oid,
-            std::make_unique<ObjectState>(object_info_t{oid}, false)));
-      } else {
-        static_assert(always_false<T>::value, "non-exhaustive visitor!");
-      }
-    });
+    crimson::ct_error::enoent::handle([oid, this] {
+      return seastar::make_ready_future<cached_os_t>(
+        os_cache.insert(oid,
+          std::make_unique<ObjectState>(object_info_t{oid}, false)));
+    }),
+    crimson::ct_error::enodata::handle([oid, this] {
+      return seastar::make_ready_future<cached_os_t>(
+        os_cache.insert(oid,
+          std::make_unique<ObjectState>(object_info_t{oid}, false)));
+    }));
 }
 
 seastar::future<PGBackend::cached_ss_t>
@@ -493,16 +492,11 @@ seastar::future<> PGBackend::getxattr(
     osd_op.op.xattr.value_len = osd_op.outdata.length();
     return seastar::now();
     //ctx->delta_stats.num_rd_kb += shift_round_up(osd_op.outdata.length(), 10);
-  }, [] (const auto& e) {
-    using T = std::decay_t<decltype(e)>;
-    if constexpr (std::is_same_v<T, crimson::ct_error::enoent>) {
-      return seastar::make_exception_future<>(crimson::osd::object_not_found{});
-    } else if constexpr (std::is_same_v<T, crimson::ct_error::enodata>) {
-      return seastar::make_exception_future<>(crimson::osd::no_message_available{});
-    } else {
-      static_assert(always_false<T>::value, "non-exhaustive visitor!");
-    }
-  });
+  }, crimson::ct_error::enoent::handle([] {
+    return seastar::make_exception_future<>(crimson::osd::object_not_found{});
+  }), crimson::ct_error::enodata::handle([] {
+    return seastar::make_exception_future<>(crimson::osd::no_message_available{});
+  }));
   //ctx->delta_stats.num_rd++;
 }