1 //
2 // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 #pragma once
8 
9 #include "td/utils/common.h"
10 
11 #include <cstdlib>
12 #include <memory>
13 #include <type_traits>
14 #include <utility>
15 
16 namespace td {
17 
18 class Guard {
19  public:
20   Guard() = default;
21   Guard(const Guard &other) = delete;
22   Guard &operator=(const Guard &other) = delete;
23   Guard(Guard &&other) = default;
24   Guard &operator=(Guard &&other) = default;
25   virtual ~Guard() = default;
dismiss()26   virtual void dismiss() {
27     std::abort();
28   }
29 };
30 
31 template <class FunctionT>
32 class LambdaGuard final : public Guard {
33  public:
LambdaGuard(const FunctionT & func)34   explicit LambdaGuard(const FunctionT &func) : func_(func) {
35   }
LambdaGuard(FunctionT && func)36   explicit LambdaGuard(FunctionT &&func) : func_(std::move(func)) {
37   }
38   LambdaGuard(const LambdaGuard &other) = delete;
39   LambdaGuard &operator=(const LambdaGuard &other) = delete;
LambdaGuard(LambdaGuard && other)40   LambdaGuard(LambdaGuard &&other) : func_(std::move(other.func_)), dismissed_(other.dismissed_) {
41     other.dismissed_ = true;
42   }
43   LambdaGuard &operator=(LambdaGuard &&other) = delete;
44 
dismiss()45   void dismiss() final {
46     dismissed_ = true;
47   }
48 
~LambdaGuard()49   ~LambdaGuard() final {
50     if (!dismissed_) {
51       func_();
52     }
53   }
54 
55  private:
56   FunctionT func_;
57   bool dismissed_ = false;
58 };
59 
60 template <class F>
create_lambda_guard(F && f)61 unique_ptr<Guard> create_lambda_guard(F &&f) {
62   return make_unique<LambdaGuard<F>>(std::forward<F>(f));
63 }
64 template <class F>
create_shared_lambda_guard(F && f)65 std::shared_ptr<Guard> create_shared_lambda_guard(F &&f) {
66   return std::make_shared<LambdaGuard<F>>(std::forward<F>(f));
67 }
68 
69 enum class ScopeExit {};
70 template <class FunctionT>
71 auto operator+(ScopeExit, FunctionT &&func) {
72   return LambdaGuard<std::decay_t<FunctionT>>(std::forward<FunctionT>(func));
73 }
74 
75 }  // namespace td
76 
77 #define SCOPE_EXIT auto TD_CONCAT(SCOPE_EXIT_VAR_, __LINE__) = ::td::ScopeExit() + [&]
78