From d2d3457b2fd0635e3a32a701bd0b2d17b0374b4a Mon Sep 17 00:00:00 2001 From: Shauren Date: Tue, 1 Oct 2024 21:03:44 +0200 Subject: Core/Utilities: Extend make_unique_ptr_with_deleter functionality to allow it to create deleters with compile time constant functions (reduces its size to just sizeof(void*)) (cherry picked from commit b13b5142f1009a71ff06786ac8c8db92891f566a) --- src/common/Utilities/Memory.h | 143 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 134 insertions(+), 9 deletions(-) (limited to 'src/common/Utilities/Memory.h') diff --git a/src/common/Utilities/Memory.h b/src/common/Utilities/Memory.h index 98622166b22..629099bf3e3 100644 --- a/src/common/Utilities/Memory.h +++ b/src/common/Utilities/Memory.h @@ -18,32 +18,157 @@ #ifndef TRINITY_MEMORY_H #define TRINITY_MEMORY_H +#include "CompilerDefs.h" +#include #include +#if TRINITY_COMPILER == TRINITY_COMPILER_GNU +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wignored-attributes" +#endif + namespace Trinity { namespace Impl { template -struct unique_ptr_deleter +struct stateful_unique_ptr_deleter { - using pointer = T*; - unique_ptr_deleter(Del deleter) : _deleter(std::move(deleter)) { } - - void operator()(pointer ptr) const { _deleter(ptr); } + using pointer = T; + explicit(false) stateful_unique_ptr_deleter(Del deleter) : _deleter(std::move(deleter)) { } + void operator()(pointer ptr) const { (void)_deleter(ptr); } private: Del _deleter; }; + +template +struct stateless_unique_ptr_deleter +{ + using pointer = T; + void operator()(pointer ptr) const + { + if constexpr (std::is_member_function_pointer_v) + (void)(ptr->*Del)(); + else + (void)Del(ptr); + } +}; } -template -auto make_unique_ptr_with_deleter(T* ptr, Del&& deleter) +/** + * Convenience function to construct type aliases for std::unique_ptr stateful deleters (such as lambda with captures) + * @tparam Ptr Type of the pointer + * @tparam Del Type of object freeing function (deduced from argument) + * @param deleter Object deleter + * + * Example use + * @code + * void FreeV1(Resource*); + * void FreeV2(Resource*); + * + * using ResourceDeleter = decltype(Trinity::unique_ptr_deleter(&FreeV1)); + * + * std::unique_ptr resource = Trinity::make_unique_ptr_with_deleter(GetResourceV1(), &FreeV1); + * // do stuff ... + * // ... later get new resource + * resource = Trinity::make_unique_ptr_with_deleter(GetResourceV2(), &FreeV2); + * @endcode + */ +template requires std::invocable && std::is_pointer_v +Impl::stateful_unique_ptr_deleter unique_ptr_deleter(Del deleter) +{ + return Impl::stateful_unique_ptr_deleter(std::move(deleter)); +} + +/** + * Convenience function to construct type aliases for std::unique_ptr stateful deleters (such as lambda with captures) + * + * Main use is for forming struct/class members without the call to make_unique_ptr_with_deleter + * @tparam Ptr Type of the pointer + * @tparam Del The freeing function. This can be either a free function pointer that accepts T* as argument, pointer to a member function of T that accepts no arguments or a lambda with no captures + * + * Example use + * @code + * using FileDeleter = decltype(Trinity::unique_ptr_deleter()); + * + * class Resource + * { + * std::unique_ptr File; + * }; + * @endcode + */ +template requires std::invocable && std::is_pointer_v +Impl::stateless_unique_ptr_deleter unique_ptr_deleter() +{ + return Impl::stateless_unique_ptr_deleter(); +} + +/** + * Utility function to construct a std::unique_ptr object with custom stateful deleter (such as lambda with captures) + * @tparam Ptr Type of the pointer + * @tparam T Type of the pointed-to object (defaults to std::remove_pointer_t) + * @tparam Del Type of object freeing function (deduced from second argument) + * @param ptr Raw pointer to owned object + * @param deleter Object deleter + * + * Example use + * @code + * class Resource + * { + * }; + * class ResourceService + * { + * Resource* Create(); + * void Destroy(Resource*); + * }; + * + * ResourceService* service = GetResourceService(); + * + * // Lambda that captures all required variables for destruction + * auto resource = Trinity::make_unique_ptr_with_deleter(service->Create(), [service](Resource* res){ service->Destroy(res); }); + * @endcode + */ +template, typename Del> requires std::invocable && std::is_pointer_v +std::unique_ptr> make_unique_ptr_with_deleter(Ptr ptr, Del deleter) { - using Deleter_t = Impl::unique_ptr_deleter; + return std::unique_ptr>(ptr, std::move(deleter)); +} - return std::unique_ptr(ptr, Deleter_t(std::forward(deleter))); +/** + * Utility function to construct a std::unique_ptr object with custom stateless deleter (function pointer, captureless lambda) + * @tparam Del The freeing function. This can be either a free function pointer that accepts T* as argument, pointer to a member function of T that accepts no arguments or a lambda with no captures + * @tparam Ptr Type of the pointer + * @tparam T Type of the pointed-to object (defaults to std::remove_pointer_t) + * @param ptr Raw pointer to owned object + * + * Example uses + * @code + * void DestroyResource(Resource*); + * class Resource + * { + * void Destroy(); + * }; + * + * // Free function + * auto free = Trinity::make_unique_ptr_with_deleter<&DestroyResource>(new Resource()); + * + * // Member function + * auto member = Trinity::make_unique_ptr_with_deleter<&Resource::Destroy>(new Resource()); + * + * // Lambda + * auto lambda = Trinity::make_unique_ptr_with_deleter<[](Resource* res){ res->Destroy(); }>(new Resource()); + * @endcode + */ +template> requires std::invocable && std::is_pointer_v +std::unique_ptr> make_unique_ptr_with_deleter(Ptr ptr) +{ + return std::unique_ptr>(ptr); } } +#if TRINITY_COMPILER == TRINITY_COMPILER_GNU +#pragma GCC diagnostic pop +#endif + #endif // TRINITY_MEMORY_H -- cgit v1.2.3