From d8d392b39ab6e93caf7a1c657f9245df3f7a125d Mon Sep 17 00:00:00 2001
From: ReinUsesLisp <reinuseslisp@airmail.cc>
Date: Fri, 27 Mar 2020 02:55:07 -0300
Subject: [PATCH] renderer_vulkan/wrapper: Add owning handle templated class

---
 src/video_core/renderer_vulkan/wrapper.h | 144 +++++++++++++++++++++++
 1 file changed, 144 insertions(+)

diff --git a/src/video_core/renderer_vulkan/wrapper.h b/src/video_core/renderer_vulkan/wrapper.h
index e5d9b34f21..5c6729dbcf 100644
--- a/src/video_core/renderer_vulkan/wrapper.h
+++ b/src/video_core/renderer_vulkan/wrapper.h
@@ -278,4 +278,148 @@ void Destroy(VkInstance, VkSurfaceKHR, const InstanceDispatch&) noexcept;
 VkResult Free(VkDevice, VkDescriptorPool, Span<VkDescriptorSet>, const DeviceDispatch&) noexcept;
 VkResult Free(VkDevice, VkCommandPool, Span<VkCommandBuffer>, const DeviceDispatch&) noexcept;
 
+template <typename Type, typename OwnerType, typename Dispatch>
+class Handle;
+
+/// Handle with an owning type.
+/// Analogue to std::unique_ptr.
+template <typename Type, typename OwnerType, typename Dispatch>
+class Handle {
+public:
+    /// Construct a handle and hold it's ownership.
+    explicit Handle(Type handle_, OwnerType owner_, const Dispatch& dld_) noexcept
+        : handle{handle_}, owner{owner_}, dld{&dld_} {}
+
+    /// Construct an empty handle.
+    Handle() = default;
+
+    /// Copying Vulkan objects is not supported and will never be.
+    Handle(const Handle&) = delete;
+    Handle& operator=(const Handle&) = delete;
+
+    /// Construct a handle transfering the ownership from another handle.
+    Handle(Handle&& rhs) noexcept
+        : handle{std::exchange(rhs.handle, nullptr)}, owner{rhs.owner}, dld{rhs.dld} {}
+
+    /// Assign the current handle transfering the ownership from another handle.
+    /// Destroys any previously held object.
+    Handle& operator=(Handle&& rhs) noexcept {
+        Release();
+        handle = std::exchange(rhs.handle, nullptr);
+        owner = rhs.owner;
+        dld = rhs.dld;
+        return *this;
+    }
+
+    /// Destroys the current handle if it existed.
+    ~Handle() noexcept {
+        Release();
+    }
+
+    /// Destroys any held object.
+    void reset() noexcept {
+        Release();
+        handle = nullptr;
+    }
+
+    /// Returns the address of the held object.
+    /// Intended for Vulkan structures that expect a pointer to an array.
+    const Type* address() const noexcept {
+        return &handle;
+    }
+
+    /// Returns the held Vulkan handle.
+    Type operator*() const noexcept {
+        return handle;
+    }
+
+    /// Returns true when there's a held object.
+    operator bool() const noexcept {
+        return handle != nullptr;
+    }
+
+protected:
+    Type handle = nullptr;
+    OwnerType owner = nullptr;
+    const Dispatch* dld = nullptr;
+
+private:
+    /// Destroys the held object if it exists.
+    void Release() noexcept {
+        if (handle) {
+            Destroy(owner, handle, *dld);
+        }
+    }
+};
+
+/// Dummy type used to specify a handle has no owner.
+struct NoOwner {};
+
+/// Handle without an owning type.
+/// Analogue to std::unique_ptr
+template <typename Type, typename Dispatch>
+class Handle<Type, NoOwner, Dispatch> {
+public:
+    /// Construct a handle and hold it's ownership.
+    explicit Handle(Type handle_, const Dispatch& dld_) noexcept : handle{handle_}, dld{&dld_} {}
+
+    /// Construct an empty handle.
+    Handle() noexcept = default;
+
+    /// Copying Vulkan objects is not supported and will never be.
+    Handle(const Handle&) = delete;
+    Handle& operator=(const Handle&) = delete;
+
+    /// Construct a handle transfering ownership from another handle.
+    Handle(Handle&& rhs) noexcept : handle{std::exchange(rhs.handle, nullptr)}, dld{rhs.dld} {}
+
+    /// Assign the current handle transfering the ownership from another handle.
+    /// Destroys any previously held object.
+    Handle& operator=(Handle&& rhs) noexcept {
+        Release();
+        handle = std::exchange(rhs.handle, nullptr);
+        dld = rhs.dld;
+        return *this;
+    }
+
+    /// Destroys the current handle if it existed.
+    ~Handle() noexcept {
+        Release();
+    }
+
+    /// Destroys any held object.
+    void reset() noexcept {
+        Release();
+        handle = nullptr;
+    }
+
+    /// Returns the address of the held object.
+    /// Intended for Vulkan structures that expect a pointer to an array.
+    const Type* address() const noexcept {
+        return &handle;
+    }
+
+    /// Returns the held Vulkan handle.
+    Type operator*() const noexcept {
+        return handle;
+    }
+
+    /// Returns true when there's a held object.
+    operator bool() const noexcept {
+        return handle != nullptr;
+    }
+
+protected:
+    Type handle = nullptr;
+    const Dispatch* dld = nullptr;
+
+private:
+    /// Destroys the held object if it exists.
+    void Release() noexcept {
+        if (handle) {
+            Destroy(handle, *dld);
+        }
+    }
+};
+
 } // namespace Vulkan::vk