scope_exit.hpp 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. /// \file
  2. // Range v3 library
  3. //
  4. // Copyright Eric Niebler 2017-present
  5. //
  6. // Use, modification and distribution is subject to the
  7. // Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. //
  11. // Project home: https://github.com/ericniebler/range-v3
  12. //
  13. #ifndef RANGES_V3_UTILITY_SCOPE_EXIT_HPP
  14. #define RANGES_V3_UTILITY_SCOPE_EXIT_HPP
  15. #include <functional>
  16. #include <type_traits>
  17. #include <utility>
  18. #include <meta/meta.hpp>
  19. #include <range/v3/detail/prologue.hpp>
  20. namespace ranges
  21. {
  22. template<typename Fun>
  23. struct scope_exit
  24. {
  25. private:
  26. using nothrow_move_t = std::is_nothrow_move_constructible<Fun>;
  27. using nothrow_copy_t = std::is_nothrow_copy_constructible<Fun>;
  28. Fun fun_;
  29. bool dismissed_{false};
  30. using ref_t = decltype(std::ref(std::declval<Fun const &>()));
  31. using guard = scope_exit<ref_t>;
  32. scope_exit(Fun const & fun, guard && g)
  33. : fun_(fun)
  34. {
  35. g.dismiss();
  36. }
  37. scope_exit(Fun const & fun, std::false_type)
  38. : scope_exit(fun, guard{std::ref(fun)})
  39. {}
  40. scope_exit(Fun const & fun, std::true_type) noexcept
  41. : fun_(fun)
  42. {}
  43. scope_exit(Fun && fun, std::true_type) noexcept
  44. : fun_(std::move(fun))
  45. {}
  46. public:
  47. explicit scope_exit(Fun const & fun) noexcept(
  48. noexcept(scope_exit(fun, nothrow_copy_t{})))
  49. : scope_exit(fun, nothrow_copy_t{})
  50. {}
  51. explicit scope_exit(Fun && fun) noexcept(noexcept(scope_exit(std::move(fun),
  52. nothrow_move_t{})))
  53. : scope_exit(std::move(fun), nothrow_move_t{})
  54. {}
  55. scope_exit(scope_exit const &) = delete;
  56. scope_exit(scope_exit && that) noexcept(
  57. std::is_nothrow_move_constructible<Fun>::value)
  58. : scope_exit(std::move((that.dismiss(), that)).fun_)
  59. {}
  60. ~scope_exit()
  61. {
  62. if(!dismissed_)
  63. fun_();
  64. }
  65. void dismiss() noexcept
  66. {
  67. dismissed_ = true;
  68. }
  69. };
  70. template<typename Fun, typename ScopeExit = scope_exit<meta::_t<std::decay<Fun>>>>
  71. ScopeExit make_scope_exit(Fun && fun) noexcept(
  72. noexcept(ScopeExit(ScopeExit((Fun &&) fun))))
  73. {
  74. return ScopeExit((Fun &&) fun);
  75. }
  76. } // namespace ranges
  77. #include <range/v3/detail/epilogue.hpp>
  78. #endif