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;
}
};
+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<>>
})};
}
+ // 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;
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>
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++;
}