#pragma once #include #include namespace nkg { template class resource_wrapper { public: using handle_t = typename resource_traits_t::handle_t; static_assert(std::is_trivial_v && std::is_standard_layout_v, "`resource_wrapper` requires a handle with POD type."); private: handle_t m_handle; releaser_t m_releaser; public: template resource_wrapper(releaser_arg_t&& releaser) noexcept : m_handle(resource_traits_t::invalid_value), m_releaser(std::forward(releaser)) {} template resource_wrapper(const handle_t& handle, releaser_arg_t&& releaser) noexcept : m_handle(handle), m_releaser(std::forward(releaser)) {} template resource_wrapper(resource_traits_t, releaser_arg_t&& releaser) noexcept : m_handle(resource_traits_t::invalid_value), m_releaser(std::forward(releaser)) {} template resource_wrapper(resource_traits_t, const handle_t& handle, releaser_arg_t&& releaser) noexcept : m_handle(handle), m_releaser(std::forward(releaser)) {} // // `resource_wrapper` does not allow copy-construct // resource_wrapper(const resource_wrapper& other) = delete; // // `resource_wrapper` allows move-construct. // resource_wrapper(resource_wrapper&& other) noexcept : m_handle(other.m_handle), m_releaser(std::move(other.m_releaser)) { other.m_handle = resource_traits_t::invalid_value; } // // `resource_wrapper` does not allow to copy. // resource_wrapper& operator=(const resource_wrapper& other) = delete; // // `resource_wrapper` allows to move. // resource_wrapper& operator=(resource_wrapper&& other) noexcept { if (this != std::addressof(other)) { m_handle = other.m_handle; m_releaser = std::move(other.m_releaser); other.m_handle = resource_traits_t::invalid_value; } return *this; } template, ptr_t> = nullptr> [[nodiscard]] ptr_t operator->() const noexcept { return m_handle; } template [[nodiscard]] as_t as() const noexcept { return reinterpret_cast(m_handle); } [[nodiscard]] bool is_valid() const noexcept { return resource_traits_t::is_valid(m_handle); } [[nodiscard]] const handle_t& get() const noexcept { return m_handle; } template [[nodiscard]] as_t* unsafe_addressof() noexcept { return reinterpret_cast(std::addressof(m_handle)); } void set(const handle_t& handle) { if (is_valid()) { m_releaser(m_handle); } m_handle = handle; } void discard() noexcept { m_handle = resource_traits_t::invalid_value; } [[nodiscard]] handle_t transfer() noexcept { handle_t t = m_handle; m_handle = resource_traits_t::invalid_value; return t; } void release() { if (is_valid()) { m_releaser(m_handle); m_handle = resource_traits_t::invalid_value; } } ~resource_wrapper() { release(); } }; template class resource_wrapper { public: using handle_t = typename resource_traits_t::handle_t; static_assert(std::is_trivial_v&& std::is_standard_layout_v, "`resource_wrapper` requires a handle with POD type."); private: handle_t m_handle; public: resource_wrapper() noexcept : m_handle(resource_traits_t::invalid_value) {} resource_wrapper(const handle_t& handle) noexcept : m_handle(handle) {} resource_wrapper(resource_traits_t) noexcept : m_handle(resource_traits_t::invalid_value) {} resource_wrapper(resource_traits_t, const handle_t& handle) noexcept : m_handle(handle) {} resource_wrapper(const resource_wrapper& other) = delete; resource_wrapper(resource_wrapper&& other) noexcept : m_handle(other.m_handle) { other.m_handle = resource_traits_t::invalid_value; } resource_wrapper& operator=(const resource_wrapper& other) = delete; resource_wrapper& operator=(resource_wrapper&& other) noexcept { if (this != std::addressof(other)) { m_handle = other.m_handle; other.m_handle = resource_traits_t::invalid_value; } return *this; } template, ptr_t> = nullptr> [[nodiscard]] ptr_t operator->() const noexcept { return m_handle; } template [[nodiscard]] as_t as() const noexcept { return reinterpret_cast(m_handle); } [[nodiscard]] bool is_valid() const noexcept { return resource_traits_t::is_valid(m_handle); } [[nodiscard]] const handle_t& get() const noexcept { return m_handle; } template [[nodiscard]] as_t* unsafe_addressof() noexcept { return reinterpret_cast(std::addressof(m_handle)); } void set(const handle_t& handle) { if (is_valid()) { resource_traits_t::release(m_handle); } m_handle = handle; } void discard() noexcept { m_handle = resource_traits_t::invalid_value; } [[nodiscard]] handle_t transfer() noexcept { handle_t t = m_handle; m_handle = resource_traits_t::invalid_value; return t; } void release() { if (is_valid()) { resource_traits_t::release(m_handle); m_handle = resource_traits_t::invalid_value; } } ~resource_wrapper() { release(); } }; template resource_wrapper(resource_traits_t) -> resource_wrapper; template resource_wrapper(resource_traits_t, arg_t&&) -> resource_wrapper< resource_traits_t, std::conditional_t< std::is_same_v>, typename resource_traits_t::handle_t> == false, std::remove_reference_t, void > >; template resource_wrapper(resource_traits_t, const handle_t&, releaser_t&&) -> resource_wrapper>; }