24#include <seastar/util/modules.hh>
25#include <seastar/util/used_size.hh>
36template <
typename Signature>
41class noncopyable_function_base {
43 noncopyable_function_base() =
default;
44 static constexpr size_t nr_direct = 32;
45 union [[gnu::may_alias]] storage {
46 char direct[nr_direct];
49 using move_type = void (*)(noncopyable_function_base* from, noncopyable_function_base* to);
50 using destroy_type = void (*)(noncopyable_function_base* func);
52 static void empty_move(noncopyable_function_base*, noncopyable_function_base*) {}
53 static void empty_destroy(noncopyable_function_base*) {}
55 static void indirect_move(noncopyable_function_base* from, noncopyable_function_base* to) {
56 using void_ptr =
void*;
57 new (&to->_storage.indirect) void_ptr(from->_storage.indirect);
61 static void trivial_direct_move(noncopyable_function_base* from, noncopyable_function_base* to) {
67#pragma GCC diagnostic push
68#pragma GCC diagnostic ignored "-Wuninitialized"
70 for (
unsigned i = 0; i != N; ++i) {
71 to->_storage.direct[i] = from->_storage.direct[i];
73#pragma GCC diagnostic pop
76 static void trivial_direct_destroy(noncopyable_function_base*) {
82 template <
typename Signature>
86template<
typename FirstArg = void,
typename... RemainingArgs>
87struct is_nothrow_if_object {
88 static constexpr bool value = is_nothrow_if_object<FirstArg>::value && is_nothrow_if_object<RemainingArgs...>::value;
92struct is_nothrow_if_object<Arg> {
93 static constexpr bool value = !std::is_object_v<Arg> || std::is_nothrow_move_constructible_v<Arg>;
97struct is_nothrow_if_object<> {
98 static constexpr bool value =
true;
106template <
typename Ret,
typename... Args,
bool Noexcept>
110 const call_type call;
111 const move_type move;
112 const destroy_type destroy;
115 const vtable* _vtable;
118 throw std::bad_function_call();
121 static constexpr vtable _s_empty_vtable = {empty_call, empty_move, empty_destroy};
123 template <
typename Func>
124 struct direct_vtable_for {
125 static Func* access(
noncopyable_function* func) {
return reinterpret_cast<Func*
>(func->_storage.direct); }
126 static const Func* access(
const noncopyable_function* func) {
return reinterpret_cast<const Func*
>(func->_storage.direct); }
127 static Func* access(noncopyable_function_base* func) {
return access(
static_cast<noncopyable_function*
>(func)); }
131 static void move(noncopyable_function_base* from, noncopyable_function_base* to) {
132 new (access(to)) Func(std::move(*access(from)));
135 static constexpr move_type select_move_thunk() {
136 bool can_trivially_move = std::is_trivially_move_constructible_v<Func>
137 && std::is_trivially_destructible_v<Func>;
138 return can_trivially_move ? trivial_direct_move<internal::used_size<Func>::value> : move;
140 static void destroy(noncopyable_function_base* func) {
141 access(func)->~Func();
143 static constexpr destroy_type select_destroy_thunk() {
144 return std::is_trivially_destructible_v<Func> ? trivial_direct_destroy : destroy;
147 new (access(to)) Func(std::move(from));
149 static constexpr vtable make_vtable() {
return { call, select_move_thunk(), select_destroy_thunk() }; }
150 static const vtable s_vtable;
152 template <
typename Func>
153 struct indirect_vtable_for {
154 static Func* access(
noncopyable_function* func) {
return reinterpret_cast<Func*
>(func->_storage.indirect); }
155 static const Func* access(
const noncopyable_function* func) {
return reinterpret_cast<const Func*
>(func->_storage.indirect); }
156 static Func* access(noncopyable_function_base* func) {
return access(
static_cast<noncopyable_function*
>(func)); }
160 static void destroy(noncopyable_function_base* func) {
164 to->_storage.indirect =
new Func(std::move(from));
166 static constexpr vtable make_vtable() {
return { call, indirect_move, destroy }; }
167 static const vtable s_vtable;
169 template <
typename Func,
bool Direct = true>
170 struct select_vtable_for : direct_vtable_for<Func> {};
171 template <
typename Func>
172 struct select_vtable_for<Func, false> : indirect_vtable_for<Func> {};
173 template <
typename Func>
174 static constexpr bool is_direct() {
175 return sizeof(Func) <= nr_direct &&
alignof(Func) <=
alignof(storage)
176 && std::is_nothrow_move_constructible_v<Func>;
178 template <
typename Func>
179 struct vtable_for : select_vtable_for<Func, is_direct<Func>()> {};
182 template <
typename Func>
183 requires std::is_invocable_r_v<Ret, Func, Args...>
185 static_assert(!Noexcept ||
noexcept(std::declval<Func>()(std::declval<Args>()...)));
186 vtable_for<Func>::initialize(std::move(func),
this);
187 _vtable = &vtable_for<Func>::s_vtable;
189 template <
typename Object,
typename... AllButFirstArg>
191 template <
typename Object,
typename... AllButFirstArg>
195 _vtable->destroy(
this);
202 _vtable->move(&x,
this);
207 this->~noncopyable_function();
213 Ret operator()(Args... args)
const noexcept(Noexcept) {
214 static_assert(!Noexcept || internal::is_nothrow_if_object<Args...>::value);
215 return _vtable->call(
this, std::forward<Args>(args)...);
218 explicit operator bool()
const {
219 return _vtable != &_s_empty_vtable;
224template <
typename Ret,
typename... Args,
bool Noexcept>
225template <
typename Func>
227 =
noncopyable_function<Ret (Args...) noexcept(Noexcept)>::direct_vtable_for<Func>::make_vtable();
230template <typename Ret, typename... Args,
bool Noexcept>
231template <typename Func>
233 =
noncopyable_function<Ret (Args...) noexcept(Noexcept)>::indirect_vtable_for<Func>::make_vtable();
Seastar API namespace.
Definition: abort_on_ebadf.hh:26
Definition: noncopyable_function.hh:37