4#include "../Foundation/TypeTraits.h"
18template <
typename FuncType>
21template <
typename R,
typename... Args>
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;
40 static const int LAMBDA_SIZE =
sizeof(
void*) * 2;
46 const void* classInstance;
47 char lambdaMemory[LAMBDA_SIZE] = {0};
50 void checkedOperation(Operation operation,
const void** other)
const
53 vtable->operation(operation, other, &classInstance);
60 static_assert(
sizeof(Function) ==
sizeof(
void*) * 3,
"Function Size");
69 typename =
typename TypeTraits::EnableIf<
70 not TypeTraits::IsSame<typename TypeTraits::RemoveReference<Lambda>::type, Function>::value,
void>::type>
71 Function(Lambda&& lambda)
74 bind(
forward<
typename TypeTraits::RemoveReference<Lambda>::type>(lambda));
78 ~Function() { checkedOperation(Operation::Destruct,
nullptr); }
82 Function(Function&& other)
84 vtable = other.vtable;
85 classInstance = other.classInstance;
86 other.checkedOperation(Operation::MoveConstruct, &classInstance);
87 other.checkedOperation(Operation::Destruct,
nullptr);
88 other.vtable =
nullptr;
93 Function(
const Function& other)
95 vtable = other.vtable;
96 other.checkedOperation(Operation::CopyConstruct, &classInstance);
101 Function& operator=(
const Function& other)
103 checkedOperation(Operation::Destruct,
nullptr);
104 vtable = other.vtable;
105 other.checkedOperation(Operation::CopyConstruct, &classInstance);
111 Function& operator=(Function&& other)
noexcept
113 checkedOperation(Operation::Destruct,
nullptr);
114 vtable = other.vtable;
115 other.checkedOperation(Operation::MoveConstruct, &classInstance);
116 other.checkedOperation(Operation::Destruct,
nullptr);
117 other.vtable =
nullptr;
123 [[nodiscard]]
bool isValid()
const {
return vtable !=
nullptr; }
126 [[nodiscard]]
bool isBoundToClassInstance(
void* instance)
const {
return classInstance == instance; }
128 bool operator==(
const Function& other)
const
130 return vtable == other.vtable and classInstance == other.classInstance;
136 template <
typename Lambda>
137 void bind(Lambda&& lambda)
139 checkedOperation(Operation::Destruct,
nullptr);
141 new (&classInstance, PlacementNew()) Lambda(forward<Lambda>(lambda));
142 vtable = getVTableForLambda<Lambda>();
146 template <
typename Lambda>
147 static auto getVTableForLambda()
149 static_assert(
sizeof(Lambda) <=
sizeof(lambdaMemory),
"Lambda is too big");
150 static SC_LANGUAGE_IF_CONSTEXPR
const VTable staticVTable = {
151 [](
const void*
const* p,
typename TypeTraits::AddPointer<Args>::type... args) SC_LANGUAGE_IF_CONSTEXPR
153 Lambda& lambda = *
reinterpret_cast<Lambda*
>(
const_cast<void**
>(p));
154 return lambda(*args...);
156 [](Operation operation,
const void** other,
const void*
const* p) SC_LANGUAGE_IF_CONSTEXPR
158 Lambda& lambda = *
reinterpret_cast<Lambda*
>(
const_cast<void**
>(p));
159 if (operation == Operation::Destruct)
161 else if (operation == Operation::CopyConstruct)
162 new (other, PlacementNew()) Lambda(lambda);
163 else if (operation == Operation::MoveConstruct)
164 new (other, PlacementNew()) Lambda(
move(lambda));
166 return &staticVTable;
174 template <
typename Lambda>
175 Lambda* dynamicCastTo()
const
177 if (getVTableForLambda<Lambda>() != vtable)
180 return &
const_cast<Lambda&
>(
reinterpret_cast<const Lambda&
>(classInstance));
185 template <R (*FreeFunction)(Args...)>
188 checkedOperation(Operation::Destruct,
nullptr);
189 static SC_LANGUAGE_IF_CONSTEXPR
const VTable staticVTable = {
190 [](
const void*
const*,
typename TypeTraits::RemoveReference<Args>::type*... args) SC_LANGUAGE_IF_CONSTEXPR
191 {
return FreeFunction(*args...); },
192 [](Operation,
const void**,
const void*
const*) SC_LANGUAGE_IF_CONSTEXPR {}};
193 vtable = &staticVTable;
194 classInstance =
nullptr;
201 template <
typename Class, R (Class::*MemberFunction)(Args...)
const>
202 void bind(
const Class& c)
204 checkedOperation(Operation::Destruct,
nullptr);
205 static SC_LANGUAGE_IF_CONSTEXPR
const VTable staticVTable = {
206 [](
const void*
const* p,
typename TypeTraits::RemoveReference<Args>::type*... args) SC_LANGUAGE_IF_CONSTEXPR
208 const Class* cls =
static_cast<const Class*
>(*p);
209 return (cls->*MemberFunction)(*args...);
211 [](Operation operation,
const void** other,
const void*
const* p) SC_LANGUAGE_IF_CONSTEXPR
213 if (operation != Operation::Destruct)
216 vtable = &staticVTable;
224 template <
typename Class, R (Class::*MemberFunction)(Args...)>
227 checkedOperation(Operation::Destruct,
nullptr);
228 static SC_LANGUAGE_IF_CONSTEXPR
const VTable staticVTable = {
229 [](
const void*
const* p,
typename TypeTraits::RemoveReference<Args>::type*... args) SC_LANGUAGE_IF_CONSTEXPR
231 Class* cls =
const_cast<Class*
>(
static_cast<const Class*
>(*p));
232 return (cls->*MemberFunction)(*args...);
234 [](Operation operation,
const void** other,
const void*
const* p) SC_LANGUAGE_IF_CONSTEXPR
236 if (operation != Operation::Destruct)
239 vtable = &staticVTable;
245 [[nodiscard]] R operator()(Args... args)
const {
return vtable->execute(&classInstance, &args...); }
249using Delegate = Function<void(T)>;
250using Action = Function<void()>;
constexpr T && move(T &value)
Converts an lvalue to an rvalue reference.
Definition: Compiler.h:269
constexpr T && forward(typename TypeTraits::RemoveReference< T >::type &value)
Forwards an lvalue or an rvalue as an rvalue reference.
Definition: Compiler.h:272
Wraps function pointers, member functions and lambdas without ever allocating.
Definition: Function.h:19