aboutsummaryrefslogtreecommitdiff
path: root/src/common/Utilities/Memory.h
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2024-10-01 21:03:44 +0200
committerOvahlord <dreadkiller@gmx.de>2024-10-03 00:38:15 +0200
commitd2d3457b2fd0635e3a32a701bd0b2d17b0374b4a (patch)
tree74d8698c82179ef42bf7fe0b29006d3234a31652 /src/common/Utilities/Memory.h
parente05461a0ed83ef500321383668f05bb4ba6dc6a7 (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.h143
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