| #include <cdefs.h> |
| #include <functional> |
| #include <tuple> |
| |
| /** |
| * Base template for `FunctionWrapper`, never used. |
| */ |
| template<typename FnType> |
| class FunctionWrapper; |
| |
| /** |
| * A non-owning type-erased reference to a callable object. This is used |
| * to pass lambdas (and similar) down the stack without increasing code |
| * size by template specialisation. Instances of this class must not be |
| * stored, they should be used only for passing type-erased callable objects |
| * down the stack. |
| * |
| * Instances of this class are two words: a reference to the lambda, and a |
| * wrapper callback that invokes the lambda. |
| * |
| * This is similar to `std::function` but is non-owning and so is guaranteed |
| * not to allocate memory (the called function may capture memory). |
| */ |
| template<class R, class... Args> |
| class FunctionWrapper<R(Args...)> |
| { |
| /** |
| * Storage for the type-erased function. This holds the reference to |
| * lambda and to the invoke function. |
| */ |
| alignas(void *) char storage[2 * sizeof(void *)]; |
| |
| /** |
| * Base type for the type-erased function. This defines the virtual |
| * function that is used to invoke the captured lambda. |
| */ |
| struct ErasedFunctionWrapperBase |
| { |
| virtual R operator()(Args... args) = 0; |
| }; |
| |
| /** |
| * Returns a pointer to the storage, cast to the type-erased function |
| * type. |
| */ |
| ErasedFunctionWrapperBase &stored_function() |
| { |
| return *reinterpret_cast<ErasedFunctionWrapperBase *>(storage); |
| } |
| |
| /** |
| * Templated subclass that is specialised for each concrete callable |
| * type `T` that is passed. One instance of this will be created for |
| * each lambda type, with a single method in its vtable that invokes |
| * the lambda. |
| */ |
| template<typename T> |
| class ErasedFunctionWrapper : public ErasedFunctionWrapperBase |
| { |
| /// Pointer to the captured lambda. |
| T &&fn; |
| |
| public: |
| /** |
| * Invoke function. This is virtual and overrides the version in |
| * the parent class, allowing this to be called from code that does |
| * not know the cocrete type of the lambda. |
| */ |
| R operator()(Args... args) override |
| { |
| return fn(std::forward<Args>(args)...); |
| } |
| |
| /** |
| * Construct the type-erased function wrapper, capturing the |
| * lambda. |
| */ |
| ErasedFunctionWrapper(T &&fn) : fn{std::forward<T>(fn)} {} |
| }; |
| |
| public: |
| /** |
| * This is a non-owning reference, delete its copy and move |
| * constructors to avoid accidental copies. |
| */ |
| FunctionWrapper(FunctionWrapper &) = delete; |
| FunctionWrapper(FunctionWrapper &&) = delete; |
| FunctionWrapper &operator=(FunctionWrapper &&) = delete; |
| |
| /** |
| * Construct the type-erased function wrapper, capturing the lambda. |
| */ |
| template<typename T> |
| __always_inline FunctionWrapper(T &&fn) |
| { |
| // Make sure that we got the size for the storage right! |
| static_assert(sizeof(storage) >= sizeof(ErasedFunctionWrapper<T>)); |
| // Construct the type-erased function in place. |
| new (storage) ErasedFunctionWrapper<T>(std::forward<T>(fn)); |
| } |
| |
| /** |
| * Invoke the captured lambda. |
| */ |
| __always_inline R operator()(Args... args) |
| { |
| return stored_function()(std::forward<Args>(args)...); |
| } |
| }; |