| #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)...); | |
| } | |
| }; |