ResourceOwned.hpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. #pragma once
  2. #include <type_traits>
  3. #include <utility>
  4. template<typename __ResourceTraits, typename __LambdaReleasor = void>
  5. class ResourceOwned {
  6. private:
  7. using __HandleType = typename __ResourceTraits::HandleType;
  8. static_assert(std::is_pod_v<__HandleType>);
  9. __HandleType _Handle;
  10. __LambdaReleasor _Releasor;
  11. public:
  12. ResourceOwned(__LambdaReleasor&& Releasor) noexcept :
  13. _Handle(__ResourceTraits::InvalidValue),
  14. _Releasor(std::forward<__LambdaReleasor>(Releasor)) {}
  15. ResourceOwned(const __HandleType& Handle, __LambdaReleasor&& Releasor) noexcept :
  16. _Handle(Handle),
  17. _Releasor(std::forward<__LambdaReleasor>(Releasor)) {}
  18. //
  19. // Construct from custom releasor.
  20. // `_Handle` will be set to an invalid value.
  21. //
  22. ResourceOwned(__ResourceTraits, __LambdaReleasor&& Releasor) noexcept :
  23. _Handle(__ResourceTraits::InvalidValue),
  24. _Releasor(std::forward<__LambdaReleasor>(Releasor)) {}
  25. //
  26. // Construct from handle given and custom releasor.
  27. //
  28. ResourceOwned(__ResourceTraits, const __HandleType& Handle, __LambdaReleasor&& Releasor) noexcept :
  29. _Handle(Handle),
  30. _Releasor(std::forward<__LambdaReleasor>(Releasor)) {}
  31. //
  32. // ResourceOwned doesn't allow to copy.
  33. // Because it takes `_Handle` exclusively.
  34. //
  35. ResourceOwned(const ResourceOwned<__ResourceTraits, __LambdaReleasor>& Other) = delete;
  36. //
  37. // ResourceOwned allows to move.
  38. //
  39. ResourceOwned(ResourceOwned<__ResourceTraits, __LambdaReleasor>&& Other) noexcept :
  40. _Handle(Other._Handle),
  41. _Releasor(std::move(Other._Releasor))
  42. {
  43. Other._Handle = __ResourceTraits::InvalidValue;
  44. }
  45. //
  46. // ResourceOwned doesn't allow to copy.
  47. // Because it takes `_Handle` exclusively.
  48. //
  49. ResourceOwned<__ResourceTraits, __LambdaReleasor>& operator=(const ResourceOwned<__ResourceTraits, __LambdaReleasor>& Other) = delete;
  50. //
  51. // ResourceOwned allows to move.
  52. //
  53. ResourceOwned<__ResourceTraits, __LambdaReleasor>& operator=(ResourceOwned<__ResourceTraits, __LambdaReleasor>&& Other) noexcept {
  54. _Handle = Other._Handle;
  55. _Releasor = std::move(Other._Releasor);
  56. Other._Handle = __ResourceTraits::InvalidValue;
  57. return *this;
  58. }
  59. [[nodiscard]]
  60. operator const __HandleType&() const noexcept { // NOLINT: Allow implicit conversion.
  61. return _Handle;
  62. }
  63. template<typename __AsType, bool __IsPointer = std::is_pointer_v<__HandleType>, typename = std::enable_if_t<__IsPointer>>
  64. [[nodiscard]]
  65. __AsType As() const noexcept {
  66. return reinterpret_cast<__AsType>(_Handle);
  67. }
  68. template<bool __IsPointer = std::is_pointer_v<__HandleType>, typename = typename std::enable_if_t<__IsPointer>>
  69. [[nodiscard]]
  70. __HandleType operator->() const noexcept {
  71. return _Handle;
  72. }
  73. [[nodiscard]]
  74. bool IsValid() const noexcept {
  75. return __ResourceTraits::IsValid(_Handle);
  76. }
  77. [[nodiscard]]
  78. const __HandleType& Get() const noexcept {
  79. return _Handle;
  80. }
  81. template<typename __ReturnType = __HandleType*>
  82. [[nodiscard]]
  83. __ReturnType GetAddressOf() noexcept {
  84. return reinterpret_cast<__ReturnType>(&_Handle);
  85. }
  86. void TakeOver(const __HandleType& Handle) {
  87. if (__ResourceTraits::IsValid(_Handle) == true) {
  88. _Releasor(_Handle);
  89. }
  90. _Handle = Handle;
  91. }
  92. void Discard() noexcept {
  93. _Handle = __ResourceTraits::InvalidValue;
  94. }
  95. [[nodiscard]]
  96. __HandleType Transfer() noexcept {
  97. __HandleType t = _Handle;
  98. _Handle = __ResourceTraits::InvalidValue;
  99. return t;
  100. }
  101. void Release() {
  102. if (__ResourceTraits::IsValid(_Handle)) {
  103. _Releasor(_Handle);
  104. _Handle = __ResourceTraits::InvalidValue;
  105. }
  106. }
  107. ~ResourceOwned() {
  108. if (__ResourceTraits::IsValid(_Handle)) {
  109. _Releasor(_Handle);
  110. _Handle = __ResourceTraits::InvalidValue;
  111. }
  112. }
  113. };
  114. template<typename __ResourceTraits>
  115. class ResourceOwned<__ResourceTraits, void> {
  116. private:
  117. using __HandleType = typename __ResourceTraits::HandleType;
  118. static_assert(std::is_pod_v<__HandleType>);
  119. __HandleType _Handle;
  120. public:
  121. ResourceOwned() noexcept :
  122. _Handle(__ResourceTraits::InvalidValue) {}
  123. ResourceOwned(const __HandleType& Handle) noexcept :
  124. _Handle(Handle) {}
  125. //
  126. // Construct from custom releasor.
  127. // `_Handle` will be set to an invalid value.
  128. //
  129. explicit ResourceOwned(__ResourceTraits) noexcept :
  130. _Handle(__ResourceTraits::InvalidValue) {}
  131. //
  132. // Construct from handle given and custom releasor.
  133. //
  134. ResourceOwned(__ResourceTraits, const __HandleType& Handle) noexcept :
  135. _Handle(Handle) {}
  136. //
  137. // ResourceOwned doesn't allow to copy.
  138. // Because it takes `_Handle` exclusively.
  139. //
  140. ResourceOwned(const ResourceOwned<__ResourceTraits, void>& Other) = delete;
  141. //
  142. // ResourceOwned allows to move.
  143. //
  144. ResourceOwned(ResourceOwned<__ResourceTraits, void>&& Other) noexcept :
  145. _Handle(Other._Handle) {
  146. Other._Handle = __ResourceTraits::InvalidValue;
  147. }
  148. //
  149. // ResourceOwned doesn't allow to copy.
  150. // Because it takes `_Handle` exclusively.
  151. //
  152. ResourceOwned<__ResourceTraits, void>& operator=(const ResourceOwned<__ResourceTraits, void>& Other) = delete;
  153. //
  154. // ResourceOwned allows to move.
  155. //
  156. ResourceOwned<__ResourceTraits, void>& operator=(ResourceOwned<__ResourceTraits, void>&& Other) noexcept {
  157. _Handle = Other._Handle;
  158. Other._Handle = __ResourceTraits::InvalidValue;
  159. return *this;
  160. }
  161. [[nodiscard]]
  162. operator const __HandleType&() const noexcept { // NOLINT: Allow implicit conversion.
  163. return _Handle;
  164. }
  165. template<typename __AsType, bool __IsPointer = std::is_pointer_v<__HandleType>, typename = typename std::enable_if_t<__IsPointer>>
  166. [[nodiscard]]
  167. __AsType As() const noexcept {
  168. return reinterpret_cast<__AsType>(_Handle);
  169. }
  170. template<bool __IsPointer = std::is_pointer_v<__HandleType>, typename = typename std::enable_if_t<__IsPointer>>
  171. [[nodiscard]]
  172. __HandleType operator->() const noexcept {
  173. return _Handle;
  174. }
  175. [[nodiscard]]
  176. bool IsValid() const noexcept {
  177. return __ResourceTraits::IsValid(_Handle);
  178. }
  179. [[nodiscard]]
  180. const __HandleType& Get() const noexcept {
  181. return _Handle;
  182. }
  183. template<typename __ReturnType = __HandleType*>
  184. [[nodiscard]]
  185. __ReturnType GetAddressOf() noexcept {
  186. return reinterpret_cast<__ReturnType>(&_Handle);
  187. }
  188. void TakeOver(const __HandleType& Handle) {
  189. if (__ResourceTraits::IsValid(_Handle) == true) {
  190. __ResourceTraits::Releasor(_Handle);
  191. }
  192. _Handle = Handle;
  193. }
  194. void Discard() noexcept {
  195. _Handle = __ResourceTraits::InvalidValue;
  196. }
  197. [[nodiscard]]
  198. __HandleType Transfer() noexcept {
  199. __HandleType t = _Handle;
  200. _Handle = __ResourceTraits::InvalidValue;
  201. return t;
  202. }
  203. void Release() {
  204. if (__ResourceTraits::IsValid(_Handle)) {
  205. __ResourceTraits::Releasor(_Handle);
  206. _Handle = __ResourceTraits::InvalidValue;
  207. }
  208. }
  209. ~ResourceOwned() {
  210. if (__ResourceTraits::IsValid(_Handle)) {
  211. __ResourceTraits::Releasor(_Handle);
  212. _Handle = __ResourceTraits::InvalidValue;
  213. }
  214. }
  215. };
  216. template<typename __ResourceTraits>
  217. ResourceOwned(__ResourceTraits) ->
  218. ResourceOwned<__ResourceTraits, void>;
  219. template<typename __ResourceTraits, typename __ArgType>
  220. ResourceOwned(__ResourceTraits, __ArgType&&) ->
  221. ResourceOwned<
  222. __ResourceTraits,
  223. std::conditional_t<
  224. std::is_same_v<std::remove_cv_t<std::remove_reference_t<__ArgType>>, typename __ResourceTraits::HandleType> == false,
  225. std::remove_reference_t<__ArgType>,
  226. void
  227. >
  228. >;
  229. template<typename __ResourceTraits, typename __LambdaReleasor>
  230. ResourceOwned(__ResourceTraits, const typename __ResourceTraits::HandleType&, __LambdaReleasor&&) ->
  231. ResourceOwned<__ResourceTraits, std::remove_reference_t<__LambdaReleasor>>;
  232. template<typename __ClassType>
  233. struct CppObjectTraits {
  234. using HandleType = __ClassType*;
  235. static inline const HandleType InvalidValue = nullptr;
  236. [[nodiscard]]
  237. static bool IsValid(const HandleType& Handle) noexcept {
  238. return Handle != InvalidValue;
  239. }
  240. static void Releasor(const HandleType& Handle) {
  241. delete Handle;
  242. }
  243. };
  244. template<typename __ClassType>
  245. struct CppDynamicArrayTraits {
  246. using HandleType = __ClassType*;
  247. static inline const HandleType InvalidValue = nullptr;
  248. [[nodiscard]]
  249. static bool IsValid(const HandleType& Handle) noexcept {
  250. return Handle != InvalidValue;
  251. }
  252. static void Releasor(const HandleType& Handle) {
  253. delete[] Handle;
  254. }
  255. };