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.

94 lines
2.4KB

  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. namespace ranges
  20. {
  21. template<typename Fun>
  22. struct scope_exit
  23. {
  24. private:
  25. using nothrow_move_t = std::is_nothrow_move_constructible<Fun>;
  26. using nothrow_copy_t = std::is_nothrow_copy_constructible<Fun>;
  27. Fun fun_;
  28. bool dismissed_{false};
  29. using ref_t = decltype(std::ref(std::declval<Fun const &>()));
  30. using guard = scope_exit<ref_t>;
  31. scope_exit(Fun const & fun, guard && g)
  32. : fun_(fun)
  33. {
  34. g.dismiss();
  35. }
  36. scope_exit(Fun const & fun, std::false_type)
  37. : scope_exit(fun, guard{std::ref(fun)})
  38. {}
  39. scope_exit(Fun const & fun, std::true_type) noexcept
  40. : fun_(fun)
  41. {}
  42. scope_exit(Fun && fun, std::true_type) noexcept
  43. : fun_(std::move(fun))
  44. {}
  45. public:
  46. explicit scope_exit(Fun const & fun) noexcept(
  47. noexcept(scope_exit(fun, nothrow_copy_t{})))
  48. : scope_exit(fun, nothrow_copy_t{})
  49. {}
  50. explicit scope_exit(Fun && fun) noexcept(noexcept(scope_exit(std::move(fun),
  51. nothrow_move_t{})))
  52. : scope_exit(std::move(fun), nothrow_move_t{})
  53. {}
  54. scope_exit(scope_exit const &) = delete;
  55. scope_exit(scope_exit && that) noexcept(
  56. std::is_nothrow_move_constructible<Fun>::value)
  57. : scope_exit(std::move((that.dismiss(), that)).fun_)
  58. {}
  59. ~scope_exit()
  60. {
  61. if(!dismissed_)
  62. fun_();
  63. }
  64. void dismiss() noexcept
  65. {
  66. dismissed_ = true;
  67. }
  68. };
  69. template<typename Fun, typename ScopeExit = scope_exit<meta::_t<std::decay<Fun>>>>
  70. ScopeExit make_scope_exit(Fun && fun) noexcept(
  71. noexcept(ScopeExit(ScopeExit((Fun &&) fun))))
  72. {
  73. return ScopeExit((Fun &&) fun);
  74. }
  75. } // namespace ranges
  76. #endif