aboutsummaryrefslogtreecommitdiff
path: root/source/10-common/ScopeGuard.hpp
blob: 4e1a348e9d412a993d43b088c5d857b41a328c29 (plain)
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
#pragma once

#include "Macros.hpp"

#include <utility>

template <typename TCleanupFunc>
class ScopeGuard {
private:
	TCleanupFunc mFunc;
	bool mDismissed = false;

public:
	/// Specifically left this implicit so that constructs like
	/// \code
	/// ScopeGuard sg = [&]() { res.Cleanup(); };
	/// \endcode
	/// would work. It is highly discourage and unlikely that one would want to use ScopeGuard as a function
	/// parameter, so the normal argument that implicit conversion are harmful doesn't really apply here.
	// Deliberately not explicit to allow usages like: ScopeGuard var = lambda;
	ScopeGuard(TCleanupFunc&& function) noexcept
		: mFunc{ std::move(function) } {
	}

	~ScopeGuard() noexcept {
		if (!mDismissed) {
			mFunc();
		}
	}

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

	ScopeGuard(ScopeGuard&& that) noexcept
		: mFunc{ std::move(that.mFunc) } {
		that.Cancel();
	}

	ScopeGuard& operator=(ScopeGuard&& that) noexcept {
		if (!mDismissed) {
			mFunc();
		}
		this->mFunc = std::move(that.mFunc);
		this->cancelled = std::exchange(that.cancelled, true);
	}

	void Dismiss() noexcept {
		mDismissed = true;
	}
};

template <typename T>
auto GuardDeletion(T* ptr) {
	return ScopeGuard([ptr]() {
		delete ptr;
	});
}

#define SCOPE_GUARD(name) ScopeGuard name = [&]()
#define DEFER ScopeGuard UNIQUE_NAME(scopeGuard) = [&]()