scope.h 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. #pragma once
  2. #include <util/system/compiler.h>
  3. #include <util/system/defaults.h>
  4. #include <utility>
  5. namespace NPrivate {
  6. template <typename F>
  7. class TScopeGuard {
  8. public:
  9. TScopeGuard(const F& function)
  10. : Function_{function}
  11. {
  12. }
  13. TScopeGuard(F&& function)
  14. : Function_{std::move(function)}
  15. {
  16. }
  17. TScopeGuard(TScopeGuard&&) = default;
  18. TScopeGuard(const TScopeGuard&) = default;
  19. ~TScopeGuard() {
  20. Function_();
  21. }
  22. private:
  23. F Function_;
  24. };
  25. struct TMakeGuardHelper {
  26. template <class F>
  27. TScopeGuard<F> operator|(F&& function) const {
  28. return std::forward<F>(function);
  29. }
  30. };
  31. }
  32. // \brief `Y_SCOPE_EXIT(captures) { body };`
  33. //
  34. // General implementaion of RAII idiom (resource acquisition is initialization). Executes
  35. // function upon return from the current scope.
  36. //
  37. // @note expects `body` to provide no-throw guarantee, otherwise whenever an exception
  38. // is thrown and leaves the outermost block of `body`, the function `std::terminate` is called.
  39. // @see http://drdobbs.com/184403758 for detailed motivation.
  40. #define Y_SCOPE_EXIT(...) const auto Y_GENERATE_UNIQUE_ID(scopeGuard) Y_DECLARE_UNUSED = ::NPrivate::TMakeGuardHelper{} | [__VA_ARGS__]() mutable -> void
  41. // \brief `Y_DEFER { body };`
  42. //
  43. // Same as `Y_SCOPE_EXIT` but doesn't require user to provide capture-list explicitly (it
  44. // implicitly uses `[&]` capture). Have same requirements for `body`.
  45. //
  46. // Inspired by `defer` statement in languages like Swift and Go.
  47. //
  48. // \code
  49. // auto item = s.pop();
  50. // bool ok = false;
  51. // Y_DEFER { if (!ok) { s.push(std::move(item)); } };
  52. // ... try handle `item` ...
  53. // ok = true;
  54. // \endcode
  55. #define Y_DEFER Y_SCOPE_EXIT(&)