4#include "../Foundation/TypeTraits.h"
49template <
typename FuncType>
52template <
typename R,
typename... Args>
56 enum class FunctionErasedOperation
62 using StubFunction = R (*)(
const void*
const*,
typename TypeTraits::AddPointer<Args>::type...);
63 using OperationFunction = void (*)(FunctionErasedOperation operation,
const void** other,
const void*
const*);
65 static const int LAMBDA_SIZE =
sizeof(
void*) * 2;
67 StubFunction functionStub;
68 OperationFunction functionOperation;
72 const void* classInstance;
73 char lambdaMemory[LAMBDA_SIZE] = {0};
76 void executeOperation(FunctionErasedOperation operation,
const void** other)
const
78 if (functionOperation)
79 (*functionOperation)(operation, other, &classInstance);
82 Function(
const void* instance, StubFunction stub, OperationFunction operation)
83 : functionStub(stub), functionOperation(operation)
85 classInstance = instance;
87 using FreeFunction = R (*)(Args...);
93 static_assert(
sizeof(Function) ==
sizeof(
void*) * 4,
"Function Size");
94 functionStub =
nullptr;
95 functionOperation =
nullptr;
103 typename =
typename TypeTraits::EnableIf<
104 not TypeTraits::IsSame<typename TypeTraits::RemoveReference<Lambda>::type, Function>::value,
void>::type>
105 Function(Lambda&& lambda)
107 functionStub =
nullptr;
108 functionOperation =
nullptr;
109 bind(
forward<
typename TypeTraits::RemoveReference<Lambda>::type>(lambda));
113 ~Function() { executeOperation(FunctionErasedOperation::Destruct,
nullptr); }
117 Function(Function&& other)
119 functionStub = other.functionStub;
120 functionOperation = other.functionOperation;
121 classInstance = other.classInstance;
122 other.executeOperation(FunctionErasedOperation::MoveConstruct, &classInstance);
123 other.executeOperation(FunctionErasedOperation::Destruct,
nullptr);
124 other.functionStub =
nullptr;
125 other.functionOperation =
nullptr;
130 Function(
const Function& other)
132 functionStub = other.functionStub;
133 functionOperation = other.functionOperation;
134 other.executeOperation(FunctionErasedOperation::CopyConstruct, &classInstance);
139 Function& operator=(
const Function& other)
141 executeOperation(FunctionErasedOperation::Destruct,
nullptr);
142 functionStub = other.functionStub;
143 functionOperation = other.functionOperation;
144 other.executeOperation(FunctionErasedOperation::CopyConstruct, &classInstance);
150 Function& operator=(Function&& other)
noexcept
152 executeOperation(FunctionErasedOperation::Destruct,
nullptr);
153 functionStub = other.functionStub;
154 functionOperation = other.functionOperation;
155 other.executeOperation(FunctionErasedOperation::MoveConstruct, &classInstance);
156 other.executeOperation(FunctionErasedOperation::Destruct,
nullptr);
157 other.functionStub =
nullptr;
163 [[nodiscard]]
bool isValid()
const {
return functionStub !=
nullptr; }
166 [[nodiscard]]
bool isBoundToClassInstance(
void* instance)
const {
return classInstance == instance; }
168 bool operator==(
const Function& other)
const
170 return functionStub == other.functionStub and functionOperation == other.functionOperation and
171 classInstance == other.classInstance;
176 template <
typename Lambda>
177 void bind(Lambda&& lambda)
179 executeOperation(FunctionErasedOperation::Destruct,
nullptr);
180 functionStub =
nullptr;
181 functionOperation =
nullptr;
183 new (&classInstance, PlacementNew()) Lambda(forward<Lambda>(lambda));
184 static_assert(
sizeof(Lambda) <=
sizeof(lambdaMemory),
"Lambda is too big");
185 functionStub = [](
const void*
const* p,
typename TypeTraits::AddPointer<Args>::type... args) -> R
187 Lambda& lambda = *
reinterpret_cast<Lambda*
>(
const_cast<void**
>(p));
188 return lambda(*args...);
190 functionOperation = [](FunctionErasedOperation operation,
const void** other,
const void*
const* p)
192 Lambda& lambda = *
reinterpret_cast<Lambda*
>(
const_cast<void**
>(p));
193 if (operation == FunctionErasedOperation::Destruct)
195 else if (operation == FunctionErasedOperation::CopyConstruct)
196 new (other, PlacementNew()) Lambda(lambda);
197 else if (operation == FunctionErasedOperation::MoveConstruct)
198 new (other, PlacementNew()) Lambda(
move(lambda));
203 __builtin_unreachable();
210 template <R (*FreeFunction)(Args...)>
213 executeOperation(FunctionErasedOperation::Destruct,
nullptr);
214 classInstance =
nullptr;
215 functionStub = &FunctionWrapper<FreeFunction>;
216 functionOperation = &FunctionOperation;
223 template <
typename Class, R (Class::*MemberFunction)(Args...)
const>
224 void bind(
const Class& c)
226 executeOperation(FunctionErasedOperation::Destruct,
nullptr);
228 functionStub = &MemberWrapper<Class, MemberFunction>;
229 functionOperation = &MemberOperation;
236 template <
typename Class, R (Class::*MemberFunction)(Args...)>
239 executeOperation(FunctionErasedOperation::Destruct,
nullptr);
241 functionStub = &MemberWrapper<Class, MemberFunction>;
242 functionOperation = &MemberOperation;
250 template <
typename Class, R (Class::*MemberFunction)(Args...)>
251 static Function fromMember(Class& c)
253 return Function(&c, &MemberWrapper<Class, MemberFunction>, &MemberOperation);
261 template <
typename Class, R (Class::*MemberFunction)(Args...)
const>
262 static Function fromMember(
const Class& c)
264 return Function(&c, &MemberWrapper<Class, MemberFunction>, &MemberOperation);
269 [[nodiscard]] R operator()(Args... args)
const {
return (*functionStub)(&classInstance, &args...); }
272 static void MemberOperation(FunctionErasedOperation operation,
const void** other,
const void*
const* p)
274 if (operation == FunctionErasedOperation::CopyConstruct or operation == FunctionErasedOperation::MoveConstruct)
278 template <
typename Class, R (Class::*MemberFunction)(Args...)>
279 static R MemberWrapper(
const void*
const* p,
typename TypeTraits::RemoveReference<Args>::type*... args)
281 Class* cls =
const_cast<Class*
>(
static_cast<const Class*
>(*p));
282 return (cls->*MemberFunction)(*args...);
285 template <
typename Class, R (Class::*MemberFunction)(Args...)
const>
286 static R MemberWrapper(
const void*
const* p,
typename TypeTraits::RemoveReference<Args>::type*... args)
288 const Class* cls =
static_cast<const Class*
>(*p);
289 return (cls->*MemberFunction)(*args...);
292 template <R (*FreeFunction)(Args...)>
293 static R FunctionWrapper(
const void*
const* p,
typename TypeTraits::RemoveReference<Args>::type*... args)
296 return FreeFunction(*args...);
298 static void FunctionOperation(FunctionErasedOperation,
const void**,
const void*
const*) {}
302using Delegate = Function<void(T)>;
303using Action = Function<void()>;
#define SC_COMPILER_UNUSED(param)
Silence an unused variable or unused parameter warning.
Definition: Compiler.h:139
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:50