3#include <Common/assertion.h>
4#include <Common/config.h>
5#include <Common/exceptions.h>
6#include <Common/memory.h>
18namespace function_detail
21template<
typename T, std::
size_t MIN_SIZE_HINT = 0>
26 static_assert(std::is_function_v<T>,
27 "Invalid function signature.");
30template<
auto Func,
typename R,
typename... Args>
32 std::is_function_v<std::remove_pointer_t<
decltype(Func)>> &&
33 std::is_invocable_r_v<R,
decltype(Func), Args...>;
35template<
auto Func,
typename Class,
typename R,
typename... Args>
37 std::is_member_function_pointer_v<
decltype(Func)> &&
38 std::is_invocable_r_v<R,
decltype(Func),
const Class*, Args...>;
40template<
auto Func,
typename Class,
typename R,
typename... Args>
42 std::is_member_function_pointer_v<
decltype(Func)> &&
43 std::is_invocable_r_v<R,
decltype(Func), Class*, Args...>;
45template<
typename Func,
typename R,
typename... Args>
47 std::is_empty_v<std::decay_t<Func>> &&
48 std::is_default_constructible_v<std::decay_t<Func>> &&
49 std::is_invocable_r_v<R, std::decay_t<Func>, Args...>;
51template<
typename Func,
typename R,
typename... Args>
53 !std::is_empty_v<std::decay_t<Func>> &&
54 !std::is_function_v<std::remove_pointer_t<std::decay_t<Func>>> &&
56 std::is_constructible_v<std::decay_t<Func>, Func&&> ||
57 std::is_trivially_copyable_v<std::decay_t<Func>>
59 std::is_trivially_destructible_v<std::decay_t<Func>> &&
60 std::is_invocable_r_v<R,
const std::decay_t<Func>&, Args...>;
80template<
typename R,
typename... Args, std::size_t MIN_SIZE_HINT>
84 using UnifiedCaller = R(*)(
const TFunction*, Args...);
88 constexpr static std::size_t BUFFER_ALIGNMENT =
alignof(
void*);
90 constexpr static std::size_t BUFFER_SIZE = MIN_SIZE_HINT >
sizeof(UnifiedCaller) +
sizeof(
void*)
91 ? MIN_SIZE_HINT -
sizeof(UnifiedCaller)
97 template<
typename Func>
99 sizeof(std::decay_t<Func>) <= BUFFER_SIZE &&
100 alignof(std::decay_t<Func>) <= BUFFER_ALIGNMENT>;
116 template<auto Func,
typename Class>
124 template<auto Func,
typename Class>
132 template<
typename Func>
139 template<
typename Func>
144 sizeof(std::decay_t<Func>) <= BUFFER_SIZE
151 template<
typename Func>
169 template<
typename Func>
171 requires (!std::is_same_v<std::decay_t<Func>,
TFunction>)
181 "Cannot direct-init TFunction with the input functor. Possible cause of errors: "
182 "(1) sizeof functor exceeds current limit, reduce functor size or increase the limit; "
183 "(2) Invalid/mismatched functor signature; "
184 "(3) The direct-init ctor only works for functors. For other function types, please use setters.");
186 set<Func>(std::forward<Func>(func));
199 template<
typename... DeducedArgs>
200 inline R operator () (DeducedArgs&&... args)
const
201 requires std::is_invocable_v<R(Args...), DeducedArgs...>
203 return (*m_caller)(
this, std::forward<DeducedArgs>(args)...);
212 m_data.u_emptyStruct = EmptyStruct{};
213 m_caller = &freeFunctionCaller<Func>;
220 template<auto Func,
typename Class>
224 PH_ASSERT(instancePtr);
226 m_data.u_constInstance = instancePtr;
227 m_caller = &constCallableMethodCaller<Func, Class>;
234 template<auto Func,
typename Class>
238 PH_ASSERT(instancePtr);
240 m_data.u_nonConstInstance = instancePtr;
241 m_caller = &nonConstCallableMethodCaller<Func, Class>;
248 template<
typename Func>
252 m_data.u_emptyStruct = EmptyStruct{};
253 m_caller = &emptyFunctorCaller<std::decay_t<Func>>;
260 template<
typename Func>
269 template<
typename Func>
273 using Functor = std::decay_t<Func>;
276 if constexpr(std::is_constructible_v<Functor, Func&&>)
279 Functor*
const storage = start_implicit_lifetime_as<Functor>(m_data.u_buffer);
281 std::construct_at(storage, std::forward<Func>(func));
282 m_caller = &nonEmptyConstructedFunctorCaller<Functor>;
286 static_assert(std::is_trivially_copyable_v<Functor>);
288 std::copy_n(
reinterpret_cast<const std::byte*
>(&func),
sizeof(Functor), m_data.u_buffer);
289 m_caller = &nonEmptyCopiedFunctorCaller<Functor>();
299 return m_caller != &invalidFunctionCaller;
304 inline operator bool ()
const
314 m_caller = &invalidFunctionCaller;
319 inline static R freeFunctionCaller(
const TFunction* , Args... args)
320 requires TIsFreeFunction<Func>::value
322 return (*Func)(std::forward<Args>(args)...);
325 template<auto Func,
typename Class>
326 inline static R constCallableMethodCaller(
const TFunction*
const self, Args... args)
327 requires TIsConstCallableMethod<Func, Class>::value
329 const auto*
const instancePtr =
static_cast<const Class*
>(self->m_data.u_constInstance);
330 return (instancePtr->*Func)(std::forward<Args>(args)...);
333 template<auto Func,
typename Class>
334 inline static R nonConstCallableMethodCaller(
const TFunction*
const self, Args... args)
335 requires TIsNonConstCallableMethod<Func, Class>::value
337 auto*
const instancePtr =
static_cast<Class*
>(self->m_data.u_nonConstInstance);
339 return (instancePtr->*Func)(std::forward<Args>(args)...);
342 template<
typename Func>
343 inline static R emptyFunctorCaller(
const TFunction* , Args... args)
344 requires TIsEmptyFunctor<Func>::value
348 return Func{}(std::forward<Args>(args)...);
351 template<
typename Func>
352 inline static R nonEmptyConstructedFunctorCaller(
const TFunction*
const self, Args... args)
356 const auto& func = *std::launder(
reinterpret_cast<const Func*
>(self->m_data.u_buffer));
358 return func(std::forward<Args>(args)...);
361 template<
typename Func>
362 inline static R nonEmptyCopiedFunctorCaller(
const TFunction*
const self, Args... args)
364 static_assert(std::is_trivially_copyable_v<Func> && std::is_default_constructible_v<Func>,
365 "Current implementation of copied functor caller requires default constructible functor "
366 "to copy bytes into.");
369 std::copy_n(self->m_data.u_buffer,
sizeof(Func),
reinterpret_cast<std::byte*
>(&func));
371 return func(std::forward<Args>(args)...);
375 inline static R invalidFunctionCaller(
const TFunction* , Args... args)
377 throw UninitializedObjectException(
"Invalid function call: function is not set");
387 EmptyStruct u_emptyStruct;
390 const void* u_constInstance;
393 void* u_nonConstInstance;
396 alignas(BUFFER_ALIGNMENT) std::byte u_buffer[BUFFER_SIZE];
400 static_assert(
alignof(Data) == BUFFER_ALIGNMENT);
405 Data m_data = {EmptyStruct{}};
408 UnifiedCaller m_caller = &invalidFunctionCaller;
413template<
typename Func, std::
size_t MIN_SIZE_HINT = PH_TFUNCTION_DEFAULT_MIN_SIZE_IN_BYTES>
418static_assert(
sizeof(
TFunction<int(
int,
int)>) == PH_TFUNCTION_DEFAULT_MIN_SIZE_IN_BYTES);
TFunction & set(const Class *const instancePtr)
Set a method callable using a const instance.
Definition TFunction.h:221
std::bool_constant< CNonEmptyFunctorForm< Func, R, Args... > &&( TCanFitBuffer< Func >::value|| sizeof(std::decay_t< Func >)<=BUFFER_SIZE)> TIsNonEmptyFunctor
Check if the type Func is a functor with member variable and can be stored internally....
Definition TFunction.h:140
TFunction(const TFunction &other)=default
TFunction()=default
Creates an invalid function that cannot be called.
TFunction(Func &&func)
Creates a function from functors (including lambdas).
Definition TFunction.h:170
TFunction & set()
Set a free function.
Definition TFunction.h:209
TFunction & set(Class *const instancePtr)
Set a method callable using a non-const instance.
Definition TFunction.h:235
TFunction(TFunction &&other) noexcept=default
void unset()
Clear the stored function. The function becomes invalid after this call.
Definition TFunction.h:312
bool isValid() const
Check if this function can be called.
Definition TFunction.h:297
TFunction & set(const Func &)
Set an empty functor or lambda without capture from object.
Definition TFunction.h:261
std::bool_constant< CNonConstCallableMethodForm< Func, Class, R, Args... > > TIsNonConstCallableMethod
Test if the target Func is a method and is invocable with a non-const object. Note that the test is f...
Definition TFunction.h:125
std::bool_constant< TIsEmptyFunctor< Func >::value|| TIsNonEmptyFunctor< Func >::value > TIsStorableFunctor
Convenient helper that checks whether Func is a supported functor form.
Definition TFunction.h:152
std::bool_constant< CConstCallableMethodForm< Func, Class, R, Args... > > TIsConstCallableMethod
Test if the target Func is a method and is invocable with a const object. Note that the test is for w...
Definition TFunction.h:117
std::bool_constant< CFreeFunctionForm< Func, R, Args... > > TIsFreeFunction
Main callable target traits. Test whether the target is of specific form and is invocable using Args ...
Definition TFunction.h:110
TFunction(std::nullptr_t)
Creates an invalid function that cannot be called.
Definition TFunction.h:163
TFunction & set()
Set an empty functor or lambda without capture.
Definition TFunction.h:249
std::bool_constant< sizeof(std::decay_t< Func >)<=BUFFER_SIZE && alignof(std::decay_t< Func >)<=BUFFER_ALIGNMENT > TCanFitBuffer
Check whether the type Func is small enough to be stored in the internal buffer.
Definition TFunction.h:98
std::bool_constant< CEmptyFunctorForm< Func, R, Args... > > TIsEmptyFunctor
Check if the type Func is a functor type without member variable. The type Func must also be default-...
Definition TFunction.h:133
TFunction & set(Func &&func)
Set and store a functor or lambda with captures.
Definition TFunction.h:270
Definition TFunction.h:23
The root for all renderer implementations.
Definition EEngineProject.h:6
function_detail::TFunction< Func, MIN_SIZE_HINT > TFunction
Definition TFunction.h:414