clang-tidy: add Chrome-inspired checks
[lttng-tools.git] / src / common / scope-exit.hpp
CommitLineData
b6bbb1d6
JG
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
13namespace lttng {
14
15namespace details {
16/* Is operator() of InvocableType is marked as noexcept? */
17template <typename InvocableType>
18struct 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 */
31template <typename ScopeExitInvocableType>
32class scope_exit {
33public:
34 /*
35 * Since ScopeExitInvocableType will be invoked in the destructor, it
36 * must be `noexcept` lest we anger the undefined behaviour gods.
37 */
38 static_assert(details::is_invocation_noexcept<ScopeExitInvocableType>::value,
cd9adb8b 39 "scope_exit requires a noexcept invocable type");
b6bbb1d6
JG
40
41 explicit scope_exit(ScopeExitInvocableType&& scope_exit_callable) :
cd9adb8b 42 _on_scope_exit{ std::forward<ScopeExitInvocableType>(scope_exit_callable) }
b6bbb1d6
JG
43 {
44 }
45
cd9adb8b
JG
46 scope_exit(scope_exit&& rhs) noexcept :
47 _on_scope_exit{ std::move(rhs._on_scope_exit) }, _armed{ rhs._armed }
b6bbb1d6
JG
48 {
49 /* Don't invoke ScopeExitInvocableType for the moved-from copy. */
50 rhs.disarm();
51 }
52
53 /*
54 * The copy constructor is disabled to prevent the action from being
55 * executed twice should a copy be performed accidentaly.
56 *
57 * The move-constructor is present to enable make_scope_exit() but to
58 * also propagate the scope_exit to another scope, should it be needed.
59 */
60 scope_exit(const scope_exit&) = delete;
61 scope_exit() = delete;
62
63 void disarm() noexcept
64 {
65 _armed = false;
66 }
67
68 ~scope_exit()
69 {
70 if (_armed) {
71 _on_scope_exit();
72 }
73 }
74
75private:
76 ScopeExitInvocableType _on_scope_exit;
77 bool _armed = true;
78};
79
80template <typename ScopeExitInvocableType>
81scope_exit<ScopeExitInvocableType> make_scope_exit(ScopeExitInvocableType&& scope_exit_callable)
82{
83 return scope_exit<ScopeExitInvocableType>(
cd9adb8b 84 std::forward<ScopeExitInvocableType>(scope_exit_callable));
b6bbb1d6
JG
85}
86
87} /* namespace lttng */
88
89#endif /* LTTNG_SCOPE_EXIT_H */
This page took 0.025461 seconds and 4 git commands to generate.