8#ifndef SEN_CORE_BASE_MOVE_ONLY_FUNCTION_H
9#define SEN_CORE_BASE_MOVE_ONLY_FUNCTION_H
17#if defined(__cpp_lib_move_only_function)
20using std::move_only_function;
27template <
class R,
class F,
class... Args, std::enable_if_t<std::is_invocable_r_v<R, F, Args...>,
bool> =
true>
29constexpr R
invoke_r(F&& f, Args&&... args)
noexcept(std::is_nothrow_invocable_r_v<R, F, Args...>)
31 if constexpr (std::is_void_v<R>)
33 std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
37 return std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
51template <
typename... Signature>
59 template <
typename CallableType,
typename... ArgTypes>
62 if constexpr (isSmallSizeOptimized<CallableType>)
64 return std::is_nothrow_constructible_v<CallableType, ArgTypes...>;
70 template <
typename CallableType,
typename QualifiedThisType>
73 if constexpr (isSmallSizeOptimized<std::remove_const_t<CallableType>>)
75 return static_cast<CallableType*
>(thisPtr->buffer_.rawBufferAddress());
81 return static_cast<CallableType*
>(thisPtr->buffer_.ptrToStoredCallable);
89 resourceHandler_ = std::exchange(other.resourceHandler_, emptyResourceHandler);
90 resourceHandler_(buffer_, &other.buffer_);
93 template <
typename CallableType,
typename... ArgTypes>
96 if constexpr (isSmallSizeOptimized<CallableType>)
98 ::new (buffer_.rawBufferAddress()) CallableType(std::forward<ArgTypes>(args)...);
105 buffer_.ptrToStoredCallable =
new CallableType(std::forward<ArgTypes>(args)...);
108 resourceHandler_ = &callableResourceHandler<CallableType>;
113 resourceHandler_(buffer_,
nullptr);
114 resourceHandler_ = std::exchange(other.resourceHandler_, emptyResourceHandler);
115 resourceHandler_(buffer_, &other.buffer_);
121 resourceHandler_(buffer_,
nullptr);
122 resourceHandler_ = emptyResourceHandler;
130 SmallSizeBuffer storage;
131 other.resourceHandler_(storage, &other.buffer_);
132 resourceHandler_(other.buffer_, &buffer_);
133 other.resourceHandler_(buffer_, &storage);
134 std::swap(resourceHandler_, other.resourceHandler_);
138 struct SmallSizeBuffer
140 static constexpr size_t bufferSize = 3 *
sizeof(
void*);
141 static constexpr size_t bufferAlignment =
alignof(
void*);
146 alignas(bufferAlignment) std::byte
data[bufferSize];
149 [[nodiscard]]
void* rawBufferAddress()
153 [[nodiscard]]
const void* rawBufferAddress()
const
159 template <
typename CallableType>
160 static constexpr bool isSmallSizeOptimized =
161 alignof(CallableType) <= SmallSizeBuffer::bufferAlignment &&
162 sizeof(CallableType) <= SmallSizeBuffer::bufferSize &&
163 std::is_nothrow_move_constructible_v<CallableType>;
165 static void emptyResourceHandler(SmallSizeBuffer& target, SmallSizeBuffer* source)
noexcept
167 std::ignore = target;
168 std::ignore = source;
171 template <
typename CallableType>
172 static void callableResourceHandler(SmallSizeBuffer& target, SmallSizeBuffer* source)
noexcept
174 if constexpr (isSmallSizeOptimized<CallableType>)
178 auto* sourceCallable =
static_cast<CallableType*
>(source->rawBufferAddress());
179 ::new (target.rawBufferAddress()) CallableType(
std::move(*sourceCallable));
180 sourceCallable->~CallableType();
184 static_cast<CallableType*
>(target.rawBufferAddress())->~CallableType();
192 target.ptrToStoredCallable = source->ptrToStoredCallable;
199 delete static_cast<CallableType*
>(target.ptrToStoredCallable);
204 SmallSizeBuffer buffer_;
205 using ResourceHandlerFunctionType = void (*)(SmallSizeBuffer& target, SmallSizeBuffer* src)
noexcept;
206 ResourceHandlerFunctionType resourceHandler_;
209template <
typename FunctionType>
211template <
typename FunctionType>
218# define GENERATE_WITH_CV
219# define GENERATE_WITH_REF
220# define GENERATE_WITH_SELF_QUALIFIERS &
224# define GENERATE_WITH_CV const
225# define GENERATE_WITH_REF
226# define GENERATE_WITH_SELF_QUALIFIERS GENERATE_WITH_CV&
230# define GENERATE_WITH_CV
231# define GENERATE_WITH_REF &
232# define GENERATE_WITH_SELF_QUALIFIERS GENERATE_WITH_CV GENERATE_WITH_REF
236# define GENERATE_WITH_CV
237# define GENERATE_WITH_REF &&
238# define GENERATE_WITH_SELF_QUALIFIERS GENERATE_WITH_CV GENERATE_WITH_REF
242# define GENERATE_WITH_CV const
243# define GENERATE_WITH_REF &
244# define GENERATE_WITH_SELF_QUALIFIERS GENERATE_WITH_CV GENERATE_WITH_REF
248# define GENERATE_WITH_CV const
249# define GENERATE_WITH_REF &&
250# define GENERATE_WITH_SELF_QUALIFIERS GENERATE_WITH_CV GENERATE_WITH_REF
255template <
typename... FwdArgs>
MoveOnlyFunctionBase() noexcept
Definition move_only_function.h:86
static constexpr bool isNothrowInit() noexcept
Returns true if the given CallableType can be initialized without throwing given the specified ArgTyp...
Definition move_only_function.h:60
void * ptrToStoredCallable
void swap(MoveOnlyFunctionBase &other) noexcept
Definition move_only_function.h:128
std::byte data[bufferSize]
static CallableType * getCallableAs(QualifiedThisType *thisPtr) noexcept
Casts the smallsize/allocated callable into the specified type.
Definition move_only_function.h:71
~MoveOnlyFunctionBase()
Definition move_only_function.h:126
void initializeCallable(ArgTypes &&... args) noexcept(isNothrowInit< CallableType, ArgTypes... >())
Definition move_only_function.h:94
MoveOnlyFunctionBase & operator=(MoveOnlyFunctionBase &&other) noexcept
Definition move_only_function.h:111
MoveOnlyFunctionBase & operator=(std::nullptr_t) noexcept
Definition move_only_function.h:119
MoveOnlyFunctionBase(MoveOnlyFunctionBase &&other) noexcept
Definition move_only_function.h:87
Definition move_only_function_impl.h:21
constexpr bool is_move_only_function_v
Definition move_only_function.h:210
constexpr R invoke_r(F &&f, Args &&... args) noexcept(std::is_nothrow_invocable_r_v< R, F, Args... >)
Definition move_only_function.h:29
Definition move_only_function.h:52
detail::MoveOnlyFunctionImpl< FwdArgs... > move_only_function
Definition move_only_function.h:256
Definition move_only_function.h:43