resource_wrapper.hpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. #pragma once
  2. #include <type_traits>
  3. #include <utility>
  4. namespace nkg {
  5. template<typename resource_traits_t, typename releaser_t = void>
  6. class resource_wrapper {
  7. public:
  8. using handle_t = typename resource_traits_t::handle_t;
  9. static_assert(std::is_trivial_v<handle_t> && std::is_standard_layout_v<handle_t>, "`resource_wrapper` requires a handle with POD type.");
  10. private:
  11. handle_t m_handle;
  12. releaser_t m_releaser;
  13. public:
  14. template<typename releaser_arg_t>
  15. resource_wrapper(releaser_arg_t&& releaser) noexcept :
  16. m_handle(resource_traits_t::invalid_value),
  17. m_releaser(std::forward<releaser_arg_t>(releaser)) {}
  18. template<typename releaser_arg_t>
  19. resource_wrapper(const handle_t& handle, releaser_arg_t&& releaser) noexcept :
  20. m_handle(handle),
  21. m_releaser(std::forward<releaser_arg_t>(releaser)) {}
  22. template<typename releaser_arg_t>
  23. resource_wrapper(resource_traits_t, releaser_arg_t&& releaser) noexcept :
  24. m_handle(resource_traits_t::invalid_value),
  25. m_releaser(std::forward<releaser_arg_t>(releaser)) {}
  26. template<typename releaser_arg_t>
  27. resource_wrapper(resource_traits_t, const handle_t& handle, releaser_arg_t&& releaser) noexcept :
  28. m_handle(handle),
  29. m_releaser(std::forward<releaser_t>(releaser)) {}
  30. //
  31. // `resource_wrapper` does not allow copy-construct
  32. //
  33. resource_wrapper(const resource_wrapper& other) = delete;
  34. //
  35. // `resource_wrapper` allows move-construct.
  36. //
  37. resource_wrapper(resource_wrapper&& other) noexcept :
  38. m_handle(other.m_handle),
  39. m_releaser(std::move(other.m_releaser))
  40. {
  41. other.m_handle = resource_traits_t::invalid_value;
  42. }
  43. //
  44. // `resource_wrapper` does not allow to copy.
  45. //
  46. resource_wrapper& operator=(const resource_wrapper& other) = delete;
  47. //
  48. // `resource_wrapper` allows to move.
  49. //
  50. resource_wrapper& operator=(resource_wrapper&& other) noexcept {
  51. if (this != std::addressof(other)) {
  52. m_handle = other.m_handle;
  53. m_releaser = std::move(other.m_releaser);
  54. other.m_handle = resource_traits_t::invalid_value;
  55. }
  56. return *this;
  57. }
  58. template<typename ptr_t = handle_t, std::enable_if_t<std::is_pointer_v<handle_t>, ptr_t> = nullptr>
  59. [[nodiscard]]
  60. ptr_t operator->() const noexcept {
  61. return m_handle;
  62. }
  63. template<typename as_t>
  64. [[nodiscard]]
  65. as_t as() const noexcept {
  66. return reinterpret_cast<as_t>(m_handle);
  67. }
  68. [[nodiscard]]
  69. bool is_valid() const noexcept {
  70. return resource_traits_t::is_valid(m_handle);
  71. }
  72. [[nodiscard]]
  73. const handle_t& get() const noexcept {
  74. return m_handle;
  75. }
  76. template<typename as_t = handle_t>
  77. [[nodiscard]]
  78. as_t* unsafe_addressof() noexcept {
  79. return reinterpret_cast<as_t*>(std::addressof(m_handle));
  80. }
  81. void set(const handle_t& handle) {
  82. if (is_valid()) {
  83. m_releaser(m_handle);
  84. }
  85. m_handle = handle;
  86. }
  87. void discard() noexcept {
  88. m_handle = resource_traits_t::invalid_value;
  89. }
  90. [[nodiscard]]
  91. handle_t transfer() noexcept {
  92. handle_t t = m_handle;
  93. m_handle = resource_traits_t::invalid_value;
  94. return t;
  95. }
  96. void release() {
  97. if (is_valid()) {
  98. m_releaser(m_handle);
  99. m_handle = resource_traits_t::invalid_value;
  100. }
  101. }
  102. ~resource_wrapper() {
  103. release();
  104. }
  105. };
  106. template<typename resource_traits_t>
  107. class resource_wrapper<resource_traits_t, void> {
  108. public:
  109. using handle_t = typename resource_traits_t::handle_t;
  110. static_assert(std::is_trivial_v<handle_t>&& std::is_standard_layout_v<handle_t>, "`resource_wrapper` requires a handle with POD type.");
  111. private:
  112. handle_t m_handle;
  113. public:
  114. resource_wrapper() noexcept :
  115. m_handle(resource_traits_t::invalid_value) {}
  116. resource_wrapper(const handle_t& handle) noexcept :
  117. m_handle(handle) {}
  118. resource_wrapper(resource_traits_t) noexcept :
  119. m_handle(resource_traits_t::invalid_value) {}
  120. resource_wrapper(resource_traits_t, const handle_t& handle) noexcept :
  121. m_handle(handle) {}
  122. resource_wrapper(const resource_wrapper& other) = delete;
  123. resource_wrapper(resource_wrapper&& other) noexcept :
  124. m_handle(other.m_handle)
  125. {
  126. other.m_handle = resource_traits_t::invalid_value;
  127. }
  128. resource_wrapper& operator=(const resource_wrapper& other) = delete;
  129. resource_wrapper& operator=(resource_wrapper&& other) noexcept {
  130. if (this != std::addressof(other)) {
  131. m_handle = other.m_handle;
  132. other.m_handle = resource_traits_t::invalid_value;
  133. }
  134. return *this;
  135. }
  136. template<typename ptr_t = handle_t, std::enable_if_t<std::is_pointer_v<handle_t>, ptr_t> = nullptr>
  137. [[nodiscard]]
  138. ptr_t operator->() const noexcept {
  139. return m_handle;
  140. }
  141. template<typename as_t>
  142. [[nodiscard]]
  143. as_t as() const noexcept {
  144. return reinterpret_cast<as_t>(m_handle);
  145. }
  146. [[nodiscard]]
  147. bool is_valid() const noexcept {
  148. return resource_traits_t::is_valid(m_handle);
  149. }
  150. [[nodiscard]]
  151. const handle_t& get() const noexcept {
  152. return m_handle;
  153. }
  154. template<typename as_t = handle_t>
  155. [[nodiscard]]
  156. as_t* unsafe_addressof() noexcept {
  157. return reinterpret_cast<as_t*>(std::addressof(m_handle));
  158. }
  159. void set(const handle_t& handle) {
  160. if (is_valid()) {
  161. resource_traits_t::release(m_handle);
  162. }
  163. m_handle = handle;
  164. }
  165. void discard() noexcept {
  166. m_handle = resource_traits_t::invalid_value;
  167. }
  168. [[nodiscard]]
  169. handle_t transfer() noexcept {
  170. handle_t t = m_handle;
  171. m_handle = resource_traits_t::invalid_value;
  172. return t;
  173. }
  174. void release() {
  175. if (is_valid()) {
  176. resource_traits_t::release(m_handle);
  177. m_handle = resource_traits_t::invalid_value;
  178. }
  179. }
  180. ~resource_wrapper() {
  181. release();
  182. }
  183. };
  184. template<typename resource_traits_t>
  185. resource_wrapper(resource_traits_t) ->
  186. resource_wrapper<resource_traits_t, void>;
  187. template<typename resource_traits_t, typename arg_t>
  188. resource_wrapper(resource_traits_t, arg_t&&) ->
  189. resource_wrapper<
  190. resource_traits_t,
  191. std::conditional_t<
  192. std::is_same_v<std::remove_cv_t<std::remove_reference_t<arg_t>>, typename resource_traits_t::handle_t> == false,
  193. std::remove_reference_t<arg_t>,
  194. void
  195. >
  196. >;
  197. template<typename resource_traits_t, typename releaser_t, typename handle_t = typename resource_traits_t::handle_t>
  198. resource_wrapper(resource_traits_t, const handle_t&, releaser_t&&) ->
  199. resource_wrapper<resource_traits_t, std::remove_reference_t<releaser_t>>;
  200. }