From a291bf0d2a750d7c64c1151d335f5ce3a8af67de Mon Sep 17 00:00:00 2001 From: "an.tsouchlos" Date: Fri, 25 Apr 2025 22:04:42 +0000 Subject: [PATCH] Add inplace-function.cpp --- cpp/inplace-function.md | 144 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 cpp/inplace-function.md diff --git a/cpp/inplace-function.md b/cpp/inplace-function.md new file mode 100644 index 0000000..208bf0f --- /dev/null +++ b/cpp/inplace-function.md @@ -0,0 +1,144 @@ +```c++ +#pragma once + + +#include +#include +#include +#include + + +namespace util { + + +/// +/// @brief Class storing a type-erased function object/pointer. +/// @details This class does not employ dynamic memory allocation; instead, it +/// stores the function object/pointer in a fixed-size buffer, the size of which +/// can be specified as a template parameter. +/// @warning This class does not take ownership of any resources it is +/// constructed from. It is the responsibility of the user to ensure that the +/// function object/pointer outlives the InplaceFunction object. +/// +/// @tparam func_sig_t Signature of the function. +/// @tparam t_storage_size Size of the storage buffer, in bytes. +/// +template +class InplaceFunction; + +template +class InplaceFunction { + + using storage_t = char[storage_size]; + using wrapper_func_t = return_t (*)(storage_t, args_t...); + +public: + InplaceFunction() = default; + + /// + /// @brief Constructor for function objects. + /// + template + InplaceFunction(F f) { + bind(f); + } + + /// + /// @brief Construct from free function pointer. + /// + template + static InplaceFunction construct() { + InplaceFunction func; + func.template bind(); + return func; + } + + /// + /// @brief Construct form member function pointer. + /// + template + static InplaceFunction construct(class_t& c) { + InplaceFunction func; + func.template bind(c); + return func; + } + + /// + /// @brief Construct from function object. + /// + template + static InplaceFunction construct(F f) { + InplaceFunction func; + func.bind(f); + return func; + } + + /// + /// @warning If no callable has been bound, calling this function will + /// result in undefined behavior. + /// + return_t operator()(args_t... args) { + return mWrapper(mStorage, args...); + } + + operator bool() const { + return !(mWrapper == nullptr); + } + + /// + /// @brief Bind a free function. + /// + /// @tparam F Pointer to free function + /// + template + requires std::is_invocable_r_v + void bind() { + mWrapper = [](storage_t, args_t... args) { + return F(std::forward(args)...); + // return std::invoke(F, std::forward(args)...); + }; + } + + /// + /// @brief Bind a member function. + /// + /// @tparam class_t Class the member belongs to. + /// @param c Reference to object the member function should be called on. + /// @tparam F Member function pointer. + /// + template + requires std::is_invocable_r_v && + (sizeof(class_t*) <= storage_size) + void bind(class_t& c) { + new (mStorage)(class_t*){&c}; + + mWrapper = [](storage_t storage, args_t... args) { + return F(*reinterpret_cast(storage), + std::forward(args)...); + }; + } + + /// + /// @brief Bind a function object. + /// + template + requires std::is_invocable_r_v && + (sizeof(F) <= storage_size) && + std::is_trivially_destructible_v + void bind(F f) { + new (mStorage) F{std::move(f)}; + mWrapper = [](storage_t storage, args_t... args) { + return (*reinterpret_cast(storage))( + std::forward(args)...); + }; + } + +private: + storage_t mStorage; + wrapper_func_t mWrapper = nullptr; +}; + + +} // namespace util +``` \ No newline at end of file