You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

168 lines
4.6KB

  1. /*
  2. * Scope Guard
  3. * Copyright (C) 2017 offa
  4. *
  5. * This file is part of Scope Guard.
  6. *
  7. * Scope Guard is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * Scope Guard is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with Scope Guard. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #pragma once
  21. #include <utility>
  22. #include <type_traits>
  23. namespace sr
  24. {
  25. enum class invoke_it
  26. {
  27. once,
  28. again
  29. };
  30. template<class Ressource, class Deleter>
  31. class unique_resource_t
  32. {
  33. public:
  34. explicit unique_resource_t(Ressource&& res, Deleter&& deleter, bool shouldrun = true) noexcept : m_resource(std::move(res)),
  35. m_deleter(std::move(deleter)),
  36. m_execute_on_destruction(shouldrun)
  37. {
  38. }
  39. unique_resource_t(const unique_resource_t&) = delete;
  40. unique_resource_t(unique_resource_t&& other) noexcept : m_resource(std::move(other.m_resource)),
  41. m_deleter(std::move(other.m_deleter)),
  42. m_execute_on_destruction(other.m_execute_on_destruction)
  43. {
  44. other.release();
  45. }
  46. ~unique_resource_t()
  47. {
  48. invoke(invoke_it::once);
  49. }
  50. void invoke(const invoke_it strategy = invoke_it::once) noexcept
  51. {
  52. if( m_execute_on_destruction == true )
  53. {
  54. call_deleter_safe();
  55. }
  56. m_execute_on_destruction = ( strategy == invoke_it::again );
  57. }
  58. Ressource release() noexcept
  59. {
  60. m_execute_on_destruction = false;
  61. return m_resource;
  62. }
  63. void reset(Ressource&& res) noexcept
  64. {
  65. invoke(invoke_it::again);
  66. m_resource = std::move(res);
  67. }
  68. const Ressource& get() const noexcept
  69. {
  70. return m_resource;
  71. }
  72. operator const Ressource&() const noexcept
  73. {
  74. return m_resource;
  75. }
  76. template<class R = Ressource,
  77. std::enable_if_t<std::is_pointer<R>::value &&
  78. ( std::is_class<std::remove_pointer_t<R>>::value
  79. || std::is_union<std::remove_pointer_t<R>>::value ), int> = 0>
  80. R operator->() const noexcept
  81. {
  82. return m_resource;
  83. }
  84. template<class R = Ressource,
  85. std::enable_if_t<std::is_pointer<R>::value, int> = 0>
  86. std::add_lvalue_reference_t<std::remove_pointer_t<Ressource>> operator*() const noexcept
  87. {
  88. return *get();
  89. }
  90. const Deleter& get_deleter() const noexcept
  91. {
  92. return m_deleter;
  93. }
  94. Deleter& get_deleter() noexcept
  95. {
  96. return m_deleter;
  97. }
  98. unique_resource_t& operator=(unique_resource_t&& other) noexcept
  99. {
  100. invoke(invoke_it::once);
  101. m_resource = std::move(other.m_resource);
  102. m_deleter = std::move(other.m_deleter);
  103. m_execute_on_destruction = other.m_execute_on_destruction;
  104. other.release();
  105. return *this;
  106. }
  107. unique_resource_t& operator=(const unique_resource_t&) = delete;
  108. private:
  109. void call_deleter_safe() noexcept
  110. {
  111. try
  112. {
  113. get_deleter()(m_resource);
  114. }
  115. catch( ... ) { /* Empty */ }
  116. }
  117. Ressource m_resource;
  118. Deleter m_deleter;
  119. bool m_execute_on_destruction;
  120. };
  121. template<class Ressource, class Deleter>
  122. unique_resource_t<Ressource, Deleter> unique_resource(Ressource&& res, Deleter d) noexcept
  123. {
  124. return unique_resource_t<Ressource, Deleter>{std::move(res), std::move(d), true};
  125. }
  126. template<class Ressource, class Deleter>
  127. unique_resource_t<Ressource, Deleter> unique_resource_checked(Ressource res, Ressource invalid, Deleter d) noexcept
  128. {
  129. return unique_resource_t<Ressource, Deleter>{std::move(res), std::move(d), (res != invalid)};
  130. }
  131. }