mirror of https://github.com/trapexit/mergerfs.git
Browse Source
thread_pool.hpp
thread_pool.hpp
14 changed files with 772 additions and 324 deletions
-
2Makefile
-
2libfuse/Makefile
-
346libfuse/include/invocable.h
-
493libfuse/include/thread_pool.hpp
-
114libfuse/lib/fuse_loop.cpp
-
14mkdocs/docs/config/func_readdir.md
-
32mkdocs/docs/config/threads.md
-
1mkdocs/mkdocs.yml
-
2src/config.cpp
-
2src/fuse_readdir_base.hpp
-
5src/fuse_readdir_cor.cpp
-
4src/fuse_readdir_cor.hpp
-
4src/fuse_readdir_cosr.cpp
-
73src/fuse_readdir_factory.cpp
@ -0,0 +1,346 @@ |
|||
#ifndef _ANY_INVOKABLE_H_ |
|||
#define _ANY_INVOKABLE_H_ |
|||
|
|||
#include <functional> |
|||
#include <memory> |
|||
#include <type_traits> |
|||
|
|||
// clang-format off |
|||
/* |
|||
namespace std { |
|||
template<class Sig> class any_invocable; // never defined |
|||
|
|||
template<class R, class... ArgTypes> |
|||
class any_invocable<R(ArgTypes...) cv ref noexcept(noex)> { |
|||
public: |
|||
using result_type = R; |
|||
|
|||
// SECTION.3, construct/copy/destroy |
|||
any_invocable() noexcept; |
|||
any_invocable(nullptr_t) noexcept; |
|||
any_invocable(any_invocable&&) noexcept; |
|||
template<class F> any_invocable(F&&); |
|||
|
|||
template<class T, class... Args> |
|||
explicit any_invocable(in_place_type_t<T>, Args&&...); |
|||
template<class T, class U, class... Args> |
|||
explicit any_invocable(in_place_type_t<T>, initializer_list<U>, Args&&...); |
|||
|
|||
any_invocable& operator=(any_invocable&&) noexcept; |
|||
any_invocable& operator=(nullptr_t) noexcept; |
|||
template<class F> any_invocable& operator=(F&&); |
|||
template<class F> any_invocable& operator=(reference_wrapper<F>) noexcept; |
|||
|
|||
~any_invocable(); |
|||
|
|||
// SECTION.4, any_invocable modifiers |
|||
void swap(any_invocable&) noexcept; |
|||
|
|||
// SECTION.5, any_invocable capacity |
|||
explicit operator bool() const noexcept; |
|||
|
|||
// SECTION.6, any_invocable invocation |
|||
R operator()(ArgTypes...) cv ref noexcept(noex); |
|||
|
|||
// SECTION.7, null pointer comparisons |
|||
friend bool operator==(const any_invocable&, nullptr_t) noexcept; |
|||
|
|||
// SECTION.8, specialized algorithms |
|||
friend void swap(any_invocable&, any_invocable&) noexcept; |
|||
}; |
|||
} |
|||
*/ |
|||
// clang-format on |
|||
|
|||
namespace ofats { |
|||
|
|||
namespace any_detail { |
|||
|
|||
using buffer = std::aligned_storage_t<sizeof(void*) * 2, alignof(void*)>; |
|||
|
|||
template <class T> |
|||
inline constexpr bool is_small_object_v = |
|||
sizeof(T) <= sizeof(buffer) && alignof(buffer) % alignof(T) == 0 && |
|||
std::is_nothrow_move_constructible_v<T>; |
|||
|
|||
union storage { |
|||
void* ptr_ = nullptr; |
|||
buffer buf_; |
|||
}; |
|||
|
|||
enum class action { destroy, move }; |
|||
|
|||
template <class R, class... ArgTypes> |
|||
struct handler_traits { |
|||
template <class Derived> |
|||
struct handler_base { |
|||
static void handle(action act, storage* current, storage* other = nullptr) { |
|||
switch (act) { |
|||
case (action::destroy): |
|||
Derived::destroy(*current); |
|||
break; |
|||
case (action::move): |
|||
Derived::move(*current, *other); |
|||
break; |
|||
} |
|||
} |
|||
}; |
|||
|
|||
template <class T> |
|||
struct small_handler : handler_base<small_handler<T>> { |
|||
template <class... Args> |
|||
static void create(storage& s, Args&&... args) { |
|||
new (static_cast<void*>(&s.buf_)) T(std::forward<Args>(args)...); |
|||
} |
|||
|
|||
static void destroy(storage& s) noexcept { |
|||
T& value = *static_cast<T*>(static_cast<void*>(&s.buf_)); |
|||
value.~T(); |
|||
} |
|||
|
|||
static void move(storage& dst, storage& src) noexcept { |
|||
create(dst, std::move(*static_cast<T*>(static_cast<void*>(&src.buf_)))); |
|||
destroy(src); |
|||
} |
|||
|
|||
static R call(const storage& s, ArgTypes... args) { |
|||
return std::invoke( |
|||
*static_cast<T*>(static_cast<void*>(&const_cast<storage&>(s).buf_)), |
|||
std::forward<ArgTypes>(args)...); |
|||
} |
|||
}; |
|||
|
|||
template <class T> |
|||
struct large_handler : handler_base<large_handler<T>> { |
|||
template <class... Args> |
|||
static void create(storage& s, Args&&... args) { |
|||
s.ptr_ = new T(std::forward<Args>(args)...); |
|||
} |
|||
|
|||
static void destroy(storage& s) noexcept { delete static_cast<T*>(s.ptr_); } |
|||
|
|||
static void move(storage& dst, storage& src) noexcept { |
|||
dst.ptr_ = src.ptr_; |
|||
} |
|||
|
|||
static R call(const storage& s, ArgTypes... args) { |
|||
return std::invoke(*static_cast<T*>(s.ptr_), |
|||
std::forward<ArgTypes>(args)...); |
|||
} |
|||
}; |
|||
|
|||
template <class T> |
|||
using handler = std::conditional_t<is_small_object_v<T>, small_handler<T>, |
|||
large_handler<T>>; |
|||
}; |
|||
|
|||
template <class T> |
|||
struct is_in_place_type : std::false_type {}; |
|||
|
|||
template <class T> |
|||
struct is_in_place_type<std::in_place_type_t<T>> : std::true_type {}; |
|||
|
|||
template <class T> |
|||
inline constexpr auto is_in_place_type_v = is_in_place_type<T>::value; |
|||
|
|||
template <class R, bool is_noexcept, class... ArgTypes> |
|||
class any_invocable_impl { |
|||
template <class T> |
|||
using handler = |
|||
typename any_detail::handler_traits<R, ArgTypes...>::template handler<T>; |
|||
|
|||
using storage = any_detail::storage; |
|||
using action = any_detail::action; |
|||
using handle_func = void (*)(any_detail::action, any_detail::storage*, |
|||
any_detail::storage*); |
|||
using call_func = R (*)(const any_detail::storage&, ArgTypes...); |
|||
|
|||
public: |
|||
using result_type = R; |
|||
|
|||
any_invocable_impl() noexcept = default; |
|||
any_invocable_impl(std::nullptr_t) noexcept {} |
|||
any_invocable_impl(any_invocable_impl&& rhs) noexcept { |
|||
if (rhs.handle_) { |
|||
handle_ = rhs.handle_; |
|||
handle_(action::move, &storage_, &rhs.storage_); |
|||
call_ = rhs.call_; |
|||
rhs.handle_ = nullptr; |
|||
} |
|||
} |
|||
|
|||
any_invocable_impl& operator=(any_invocable_impl&& rhs) noexcept { |
|||
any_invocable_impl{std::move(rhs)}.swap(*this); |
|||
return *this; |
|||
} |
|||
any_invocable_impl& operator=(std::nullptr_t) noexcept { |
|||
destroy(); |
|||
return *this; |
|||
} |
|||
|
|||
~any_invocable_impl() { destroy(); } |
|||
|
|||
void swap(any_invocable_impl& rhs) noexcept { |
|||
if (handle_) { |
|||
if (rhs.handle_) { |
|||
storage tmp; |
|||
handle_(action::move, &tmp, &storage_); |
|||
rhs.handle_(action::move, &storage_, &rhs.storage_); |
|||
handle_(action::move, &rhs.storage_, &tmp); |
|||
std::swap(handle_, rhs.handle_); |
|||
std::swap(call_, rhs.call_); |
|||
} else { |
|||
rhs.swap(*this); |
|||
} |
|||
} else if (rhs.handle_) { |
|||
rhs.handle_(action::move, &storage_, &rhs.storage_); |
|||
handle_ = rhs.handle_; |
|||
call_ = rhs.call_; |
|||
rhs.handle_ = nullptr; |
|||
} |
|||
} |
|||
|
|||
explicit operator bool() const noexcept { return handle_ != nullptr; } |
|||
|
|||
protected: |
|||
template <class F, class... Args> |
|||
void create(Args&&... args) { |
|||
using hdl = handler<F>; |
|||
hdl::create(storage_, std::forward<Args>(args)...); |
|||
handle_ = &hdl::handle; |
|||
call_ = &hdl::call; |
|||
} |
|||
|
|||
void destroy() noexcept { |
|||
if (handle_) { |
|||
handle_(action::destroy, &storage_, nullptr); |
|||
handle_ = nullptr; |
|||
} |
|||
} |
|||
|
|||
R call(ArgTypes... args) const noexcept(is_noexcept) { |
|||
return call_(storage_, std::forward<ArgTypes>(args)...); |
|||
} |
|||
|
|||
friend bool operator==(const any_invocable_impl& f, std::nullptr_t) noexcept { |
|||
return !f; |
|||
} |
|||
friend bool operator==(std::nullptr_t, const any_invocable_impl& f) noexcept { |
|||
return !f; |
|||
} |
|||
friend bool operator!=(const any_invocable_impl& f, std::nullptr_t) noexcept { |
|||
return static_cast<bool>(f); |
|||
} |
|||
friend bool operator!=(std::nullptr_t, const any_invocable_impl& f) noexcept { |
|||
return static_cast<bool>(f); |
|||
} |
|||
|
|||
friend void swap(any_invocable_impl& lhs, any_invocable_impl& rhs) noexcept { |
|||
lhs.swap(rhs); |
|||
} |
|||
|
|||
private: |
|||
storage storage_; |
|||
handle_func handle_ = nullptr; |
|||
call_func call_; |
|||
}; |
|||
|
|||
template <class T> |
|||
using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>; |
|||
|
|||
template <class AI, class F, bool noex, class R, class FCall, class... ArgTypes> |
|||
using can_convert = std::conjunction< |
|||
std::negation<std::is_same<remove_cvref_t<F>, AI>>, |
|||
std::negation<any_detail::is_in_place_type<remove_cvref_t<F>>>, |
|||
std::is_invocable_r<R, FCall, ArgTypes...>, |
|||
std::bool_constant<(!noex || |
|||
std::is_nothrow_invocable_r_v<R, FCall, ArgTypes...>)>, |
|||
std::is_constructible<std::decay_t<F>, F>>; |
|||
|
|||
} // namespace any_detail |
|||
|
|||
template <class Signature> |
|||
class any_invocable; |
|||
|
|||
#define __OFATS_ANY_INVOCABLE(cv, ref, noex, inv_quals) \ |
|||
template <class R, class... ArgTypes> \ |
|||
class any_invocable<R(ArgTypes...) cv ref noexcept(noex)> final \ |
|||
: public any_detail::any_invocable_impl<R, noex, ArgTypes...> { \ |
|||
using base_type = any_detail::any_invocable_impl<R, noex, ArgTypes...>; \ |
|||
\ |
|||
public: \ |
|||
using base_type::base_type; \ |
|||
\ |
|||
template < \ |
|||
class F, \ |
|||
class = std::enable_if_t<any_detail::can_convert< \ |
|||
any_invocable, F, noex, R, F inv_quals, ArgTypes...>::value>> \ |
|||
any_invocable(F&& f) { \ |
|||
base_type::template create<std::decay_t<F>>(std::forward<F>(f)); \ |
|||
} \ |
|||
\ |
|||
template <class T, class... Args, class VT = std::decay_t<T>, \ |
|||
class = std::enable_if_t< \ |
|||
std::is_move_constructible_v<VT> && \ |
|||
std::is_constructible_v<VT, Args...> && \ |
|||
std::is_invocable_r_v<R, VT inv_quals, ArgTypes...> && \ |
|||
(!noex || std::is_nothrow_invocable_r_v<R, VT inv_quals, \ |
|||
ArgTypes...>)>> \ |
|||
explicit any_invocable(std::in_place_type_t<T>, Args&&... args) { \ |
|||
base_type::template create<VT>(std::forward<Args>(args)...); \ |
|||
} \ |
|||
\ |
|||
template < \ |
|||
class T, class U, class... Args, class VT = std::decay_t<T>, \ |
|||
class = std::enable_if_t< \ |
|||
std::is_move_constructible_v<VT> && \ |
|||
std::is_constructible_v<VT, std::initializer_list<U>&, Args...> && \ |
|||
std::is_invocable_r_v<R, VT inv_quals, ArgTypes...> && \ |
|||
(!noex || \ |
|||
std::is_nothrow_invocable_r_v<R, VT inv_quals, ArgTypes...>)>> \ |
|||
explicit any_invocable(std::in_place_type_t<T>, \ |
|||
std::initializer_list<U> il, Args&&... args) { \ |
|||
base_type::template create<VT>(il, std::forward<Args>(args)...); \ |
|||
} \ |
|||
\ |
|||
template <class F, class FDec = std::decay_t<F>> \ |
|||
std::enable_if_t<!std::is_same_v<FDec, any_invocable> && \ |
|||
std::is_move_constructible_v<FDec>, \ |
|||
any_invocable&> \ |
|||
operator=(F&& f) { \ |
|||
any_invocable{std::forward<F>(f)}.swap(*this); \ |
|||
return *this; \ |
|||
} \ |
|||
template <class F> \ |
|||
any_invocable& operator=(std::reference_wrapper<F> f) { \ |
|||
any_invocable{f}.swap(*this); \ |
|||
return *this; \ |
|||
} \ |
|||
\ |
|||
R operator()(ArgTypes... args) cv ref noexcept(noex) { \ |
|||
return base_type::call(std::forward<ArgTypes>(args)...); \ |
|||
} \ |
|||
} |
|||
|
|||
// cv -> {`empty`, const} |
|||
// ref -> {`empty`, &, &&} |
|||
// noex -> {true, false} |
|||
// inv_quals -> (is_empty(ref) ? & : ref) |
|||
__OFATS_ANY_INVOCABLE(, , false, &); // 000 |
|||
__OFATS_ANY_INVOCABLE(, , true, &); // 001 |
|||
__OFATS_ANY_INVOCABLE(, &, false, &); // 010 |
|||
__OFATS_ANY_INVOCABLE(, &, true, &); // 011 |
|||
__OFATS_ANY_INVOCABLE(, &&, false, &&); // 020 |
|||
__OFATS_ANY_INVOCABLE(, &&, true, &&); // 021 |
|||
__OFATS_ANY_INVOCABLE(const, , false, const&); // 100 |
|||
__OFATS_ANY_INVOCABLE(const, , true, const&); // 101 |
|||
__OFATS_ANY_INVOCABLE(const, &, false, const&); // 110 |
|||
__OFATS_ANY_INVOCABLE(const, &, true, const&); // 111 |
|||
__OFATS_ANY_INVOCABLE(const, &&, false, const&&); // 120 |
|||
__OFATS_ANY_INVOCABLE(const, &&, true, const&&); // 121 |
|||
|
|||
#undef __OFATS_ANY_INVOCABLE |
|||
|
|||
} // namespace ofats |
|||
|
|||
#endif // _ANY_INVOKABLE_H_ |
Write
Preview
Loading…
Cancel
Save
Reference in new issue