Fix: syscall event rule: emission sites not compared in is_equal
[lttng-tools.git] / src / common / scope-exit.hpp
1 /*
2 * Copyright (C) 2022 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
8 #ifndef LTTNG_SCOPE_EXIT_H
9 #define LTTNG_SCOPE_EXIT_H
10
11 #include <utility>
12
13 namespace lttng {
14
15 namespace details {
16 /* Is operator() of InvocableType is marked as noexcept? */
17 template <typename InvocableType>
18 struct is_invocation_noexcept
19 : std::integral_constant<bool, noexcept((std::declval<InvocableType>())())> {
20 };
21 } /* namespace details. */
22
23 /*
24 * Generic utility to run a lambda (or any other invocable object) when leaving
25 * a scope.
26 *
27 * Notably, this makes it easy to specify an action (e.g. restore a context)
28 * that must occur at the end of a function or roll-back operations in an
29 * exception-safe way.
30 */
31 template <typename ScopeExitInvocableType>
32 class scope_exit {
33 public:
34 /*
35 * Since ScopeExitInvocableType will be invoked in the destructor, it
36 * must be `noexcept` lest we anger the undefined behaviour gods by throwing
37 * an exception while an exception is active.
38 */
39 static_assert(details::is_invocation_noexcept<ScopeExitInvocableType>::value,
40 "scope_exit requires a noexcept invocable type");
41
42 explicit scope_exit(ScopeExitInvocableType&& scope_exit_callable) :
43 _on_scope_exit{ std::forward<ScopeExitInvocableType>(scope_exit_callable) }
44 {
45 }
46
47 scope_exit(scope_exit&& rhs) noexcept :
48 _on_scope_exit{ std::move(rhs._on_scope_exit) }, _armed{ rhs._armed }
49 {
50 /* Don't invoke ScopeExitInvocableType for the moved-from copy. */
51 rhs.disarm();
52 }
53
54 /*
55 * The copy constructor is disabled to prevent the action from being
56 * executed twice should a copy be performed accidentaly.
57 *
58 * The move-constructor is present to enable make_scope_exit() but to
59 * also propagate the scope_exit to another scope, should it be needed.
60 */
61 scope_exit(const scope_exit&) = delete;
62 scope_exit& operator=(const scope_exit&) = delete;
63 scope_exit& operator=(scope_exit&&) = delete;
64 scope_exit() = delete;
65
66 void disarm() noexcept
67 {
68 _armed = false;
69 }
70
71 ~scope_exit()
72 {
73 if (_armed) {
74 _on_scope_exit();
75 }
76 }
77
78 private:
79 ScopeExitInvocableType _on_scope_exit;
80 bool _armed = true;
81 };
82
83 template <typename ScopeExitInvocableType>
84 scope_exit<ScopeExitInvocableType> make_scope_exit(ScopeExitInvocableType&& scope_exit_callable)
85 {
86 return scope_exit<ScopeExitInvocableType>(
87 std::forward<ScopeExitInvocableType>(scope_exit_callable));
88 }
89
90 } /* namespace lttng */
91
92 #endif /* LTTNG_SCOPE_EXIT_H */
This page took 0.030917 seconds and 4 git commands to generate.