~singpolyma/biboumi

ref: ffb402f0adb9f808c7b8bc9616e71f7b3f8931ac biboumi/src/utils/scopeguard.hpp -rw-r--r-- 2.3 KiB
ffb402f0 — louiz’ Drop support for botan < 2.0 6 years ago
                                                                                
81f8f45b louiz’
e1a7114c Florent Le Coz
ce06c25e louiz’
e1a7114c Florent Le Coz
af420738 louiz’
e1a7114c Florent Le Coz
ce06c25e louiz’
7f08cf83 louiz’
ce06c25e louiz’
7f08cf83 louiz’
ce06c25e louiz’
e1a7114c Florent Le Coz
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#pragma once

#include <functional>
#include <memory>
#include <vector>

/**
 * A class to be used to make sure some functions are called when the scope
 * is left, because they will be called in the ScopeGuard's destructor.  It
 * can for example be used to delete some pointer whenever any exception is
 * called.  Example:

 * {
 *  ScopeGuard scope;
 *  int* number = new int(2);
 *  scope.add_callback([number]() { delete number; });
 *  // Do some other stuff with the number. But these stuff might throw an exception:
 *  throw std::runtime_error("Some error not caught here, but in our caller");
 *  return true;
 * }

 * In this example, our pointer will always be deleted, even when the
 * exception is thrown.  If we want the functions to be called only when the
 * scope is left because of an unexpected exception, we can use
 * ScopeGuard::disable();
 */

namespace utils
{

class ScopeGuard
{
public:
  /**
   * The constructor can take a callback. But additional callbacks can be
   * added later with add_callback()
   */
  explicit ScopeGuard(std::function<void()>&& func):
    enabled(true)
  {
    this->add_callback(std::move(func));
  }

  ScopeGuard(const ScopeGuard&) = delete;
  ScopeGuard& operator=(ScopeGuard&&) = delete;
  ScopeGuard(ScopeGuard&&) = delete;
  ScopeGuard& operator=(const ScopeGuard&) = delete;

  /**
   * default constructor, the scope guard is enabled but empty, use
   * add_callback()
   */
  explicit ScopeGuard():
    enabled(true)
  {
  }
  /**
   * Call all callbacks in the desctructor, unless it has been disabled.
   */
  ~ScopeGuard()
  {
    if (this->enabled)
      for (auto& func: this->callbacks)
        func();
  }
  /**
   * Add a callback to be called in our destructor, one scope guard can be
   * used for more than one task, if needed.
   */
  void add_callback(std::function<void()>&& func)
  {
    this->callbacks.emplace_back(std::move(func));
  }
  /**
   * Disable that scope guard, nothing will be done when the scope is
   * exited.
   */
  void disable()
  {
    this->enabled = false;
  }

private:
  bool enabled;
  std::vector<std::function<void()>> callbacks;

};

template<typename F>
auto make_scope_guard(F f)
{
  static struct Empty {} empty;
  auto deleter = [f = std::move(f)](Empty*) { f(); };
  return std::unique_ptr<Empty, decltype(deleter)>{&empty, std::move(deleter)};
}

}