4#include "../Foundation/TypeTraits.h"
18template <
typename FuncType,
int LAMBDA_SIZE = sizeof(
void*) * 2>
21template <
int LAMBDA_SIZE,
typename R,
typename... Args>
22struct Function<R(Args...), LAMBDA_SIZE>
31 using ExecuteFunction = R (*)(
const void*
const*,
typename TypeTraits::AddPointer<Args>::type...);
32 using OperationFunction = void (*)(Operation operation,
const void** other,
const void*
const*);
36 ExecuteFunction execute;
37 OperationFunction operation;
44 const void* classInstance;
45 char lambdaMemory[LAMBDA_SIZE] = {0};
48 void checkedOperation(Operation operation,
const void** other)
const
51 vtable->operation(operation, other, &classInstance);
58 static_assert(
sizeof(Function) ==
sizeof(
void*) + LAMBDA_SIZE,
"Function Size");
67 typename =
typename TypeTraits::EnableIf<
68 not TypeTraits::IsSame<typename TypeTraits::RemoveReference<Lambda>::type, Function>::value,
void>::type>
69 Function(Lambda&& lambda)
72 bind(
forward<
typename TypeTraits::RemoveReference<Lambda>::type>(lambda));
76 ~Function() { checkedOperation(Operation::Destruct,
nullptr); }
80 Function(Function&& other)
82 vtable = other.vtable;
83 classInstance = other.classInstance;
84 other.checkedOperation(Operation::MoveConstruct, &classInstance);
85 other.checkedOperation(Operation::Destruct,
nullptr);
86 other.vtable =
nullptr;
91 Function(
const Function& other)
93 vtable = other.vtable;
94 other.checkedOperation(Operation::CopyConstruct, &classInstance);
99 Function& operator=(
const Function& other)
101 checkedOperation(Operation::Destruct,
nullptr);
102 vtable = other.vtable;
103 other.checkedOperation(Operation::CopyConstruct, &classInstance);
109 Function& operator=(Function&& other)
noexcept
111 checkedOperation(Operation::Destruct,
nullptr);
112 vtable = other.vtable;
113 other.checkedOperation(Operation::MoveConstruct, &classInstance);
114 other.checkedOperation(Operation::Destruct,
nullptr);
115 other.vtable =
nullptr;
121 [[nodiscard]]
bool isValid()
const {
return vtable !=
nullptr; }
124 [[nodiscard]]
bool isBoundToClassInstance(
void* instance)
const {
return classInstance == instance; }
126 bool operator==(
const Function& other)
const
128 return vtable == other.vtable and classInstance == other.classInstance;
134 template <
typename Lambda>
135 void bind(Lambda&& lambda)
137 checkedOperation(Operation::Destruct,
nullptr);
140 vtable = getVTableForLambda<Lambda>();
144 template <
typename Lambda>
145 static auto getVTableForLambda()
147 static_assert(
sizeof(Lambda) <=
sizeof(lambdaMemory),
"Lambda is too big");
148 static SC_LANGUAGE_IF_CONSTEXPR
const VTable staticVTable = {
149 [](
const void*
const* p,
typename TypeTraits::AddPointer<Args>::type... args) SC_LANGUAGE_IF_CONSTEXPR
151 Lambda& lambda = *
reinterpret_cast<Lambda*
>(
const_cast<void**
>(p));
152 return lambda(*args...);
154 [](Operation operation,
const void** other,
const void*
const* p) SC_LANGUAGE_IF_CONSTEXPR
156 Lambda& lambda = *
reinterpret_cast<Lambda*
>(
const_cast<void**
>(p));
157 if (operation == Operation::Destruct)
159 else if (operation == Operation::CopyConstruct)
160 new (other, PlacementNew()) Lambda(lambda);
161 else if (operation == Operation::MoveConstruct)
162 new (other, PlacementNew()) Lambda(
move(lambda));
164 return &staticVTable;
172 template <
typename Lambda>
173 Lambda* dynamicCastTo()
const
175 if (getVTableForLambda<Lambda>() != vtable)
178 return &
const_cast<Lambda&
>(
reinterpret_cast<const Lambda&
>(classInstance));
183 template <R (*FreeFunction)(Args...)>
186 checkedOperation(Operation::Destruct,
nullptr);
187 static SC_LANGUAGE_IF_CONSTEXPR
const VTable staticVTable = {
188 [](
const void*
const*,
typename TypeTraits::RemoveReference<Args>::type*... args) SC_LANGUAGE_IF_CONSTEXPR
189 {
return FreeFunction(*args...); },
190 [](Operation,
const void**,
const void*
const*) SC_LANGUAGE_IF_CONSTEXPR {}};
191 vtable = &staticVTable;
192 classInstance =
nullptr;
199 template <
typename Class, R (Class::*MemberFunction)(Args...)
const>
200 void bind(
const Class& c)
202 checkedOperation(Operation::Destruct,
nullptr);
203 static SC_LANGUAGE_IF_CONSTEXPR
const VTable staticVTable = {
204 [](
const void*
const* p,
typename TypeTraits::RemoveReference<Args>::type*... args) SC_LANGUAGE_IF_CONSTEXPR
206 const Class* cls =
static_cast<const Class*
>(*p);
207 return (cls->*MemberFunction)(*args...);
209 [](Operation operation,
const void** other,
const void*
const* p) SC_LANGUAGE_IF_CONSTEXPR
211 if (operation != Operation::Destruct)
214 vtable = &staticVTable;
222 template <
typename Class, R (Class::*MemberFunction)(Args...)>
225 checkedOperation(Operation::Destruct,
nullptr);
226 static SC_LANGUAGE_IF_CONSTEXPR
const VTable staticVTable = {
227 [](
const void*
const* p,
typename TypeTraits::RemoveReference<Args>::type*... args) SC_LANGUAGE_IF_CONSTEXPR
229 Class* cls =
const_cast<Class*
>(
static_cast<const Class*
>(*p));
230 return (cls->*MemberFunction)(*args...);
232 [](Operation operation,
const void** other,
const void*
const* p) SC_LANGUAGE_IF_CONSTEXPR
234 if (operation != Operation::Destruct)
237 vtable = &staticVTable;
243 [[nodiscard]] R operator()(Args... args)
const {
return vtable->execute(&classInstance, &args...); }
247using Delegate = Function<void(T)>;
248using Action = Function<void()>;
constexpr T && move(T &value)
Converts an lvalue to an rvalue reference.
Definition Compiler.h:264
constexpr T && forward(typename TypeTraits::RemoveReference< T >::type &value)
Forwards an lvalue or an rvalue as an rvalue reference.
Definition Compiler.h:267
Wraps function pointers, member functions and lambdas without ever allocating.
Definition Function.h:19