diff options
author | Shauren <shauren.trinity@gmail.com> | 2024-10-01 21:03:44 +0200 |
---|---|---|
committer | Ovahlord <dreadkiller@gmx.de> | 2024-10-03 00:38:15 +0200 |
commit | d2d3457b2fd0635e3a32a701bd0b2d17b0374b4a (patch) | |
tree | 74d8698c82179ef42bf7fe0b29006d3234a31652 /src/common/Utilities/Memory.h | |
parent | e05461a0ed83ef500321383668f05bb4ba6dc6a7 (diff) |
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)
Diffstat (limited to 'src/common/Utilities/Memory.h')
-rw-r--r-- | src/common/Utilities/Memory.h | 143 |
1 files changed, 134 insertions, 9 deletions
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 <concepts> #include <memory> +#if TRINITY_COMPILER == TRINITY_COMPILER_GNU +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wignored-attributes" +#endif + namespace Trinity { namespace Impl { template<typename T, typename Del> -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<typename T, auto Del> +struct stateless_unique_ptr_deleter +{ + using pointer = T; + void operator()(pointer ptr) const + { + if constexpr (std::is_member_function_pointer_v<decltype(Del)>) + (void)(ptr->*Del)(); + else + (void)Del(ptr); + } +}; } -template<typename T, typename Del> -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<Resource*>(&FreeV1)); + * + * std::unique_ptr<Resource, ResourceDeleter> 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 <typename Ptr, typename Del> requires std::invocable<Del, Ptr> && std::is_pointer_v<Ptr> +Impl::stateful_unique_ptr_deleter<Ptr, Del> unique_ptr_deleter(Del deleter) +{ + return Impl::stateful_unique_ptr_deleter<Ptr, Del>(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<FILE*, &::fclose>()); + * + * class Resource + * { + * std::unique_ptr<FILE, FileDeleter> File; + * }; + * @endcode + */ +template <typename Ptr, auto Del> requires std::invocable<decltype(Del), Ptr> && std::is_pointer_v<Ptr> +Impl::stateless_unique_ptr_deleter<Ptr, Del> unique_ptr_deleter() +{ + return Impl::stateless_unique_ptr_deleter<Ptr, Del>(); +} + +/** + * 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<Ptr>) + * @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 Ptr, typename T = std::remove_pointer_t<Ptr>, typename Del> requires std::invocable<Del, Ptr> && std::is_pointer_v<Ptr> +std::unique_ptr<T, Impl::stateful_unique_ptr_deleter<Ptr, Del>> make_unique_ptr_with_deleter(Ptr ptr, Del deleter) { - using Deleter_t = Impl::unique_ptr_deleter<T, Del>; + return std::unique_ptr<T, Impl::stateful_unique_ptr_deleter<Ptr, Del>>(ptr, std::move(deleter)); +} - return std::unique_ptr<T, Deleter_t>(ptr, Deleter_t(std::forward<Del>(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<Ptr>) + * @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<auto Del, typename Ptr, typename T = std::remove_pointer_t<Ptr>> requires std::invocable<decltype(Del), Ptr> && std::is_pointer_v<Ptr> +std::unique_ptr<T, Impl::stateless_unique_ptr_deleter<Ptr, Del>> make_unique_ptr_with_deleter(Ptr ptr) +{ + return std::unique_ptr<T, Impl::stateless_unique_ptr_deleter<Ptr, Del>>(ptr); } } +#if TRINITY_COMPILER == TRINITY_COMPILER_GNU +#pragma GCC diagnostic pop +#endif + #endif // TRINITY_MEMORY_H |