Skip to content

Commit 636074b

Browse files
committed
Add a helper for generic scope guards.
1 parent 9472470 commit 636074b

File tree

3 files changed

+113
-1
lines changed

3 files changed

+113
-1
lines changed

amtl/am-raii.h

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// vim: set sts=8 ts=2 sw=2 tw=99 et:
1+
// vim: set sts=4 ts=8 sw=4 tw=99 et:
22
//
33
// Copyright (C) 2013-2014, David Anderson and AlliedModders LLC
44
// All rights reserved.
@@ -30,6 +30,8 @@
3030
#ifndef _include_amtl_am_raii_h_
3131
#define _include_amtl_am_raii_h_
3232

33+
#include <utility>
34+
3335
namespace ke {
3436

3537
template <typename T>
@@ -71,6 +73,48 @@ class StackLinked
7173
T* prev_;
7274
};
7375

76+
template <typename T>
77+
class ScopeGuard
78+
{
79+
public:
80+
ScopeGuard(T&& callback) noexcept
81+
: callback_(std::forward<T>(callback)),
82+
cancelled_(false)
83+
{}
84+
ScopeGuard(ScopeGuard&& other) noexcept
85+
: callback_(std::move(other.callback_)),
86+
cancelled_(other.cancelled_)
87+
{
88+
other.cancel();
89+
}
90+
91+
~ScopeGuard() {
92+
if (!cancelled_)
93+
callback_();
94+
}
95+
96+
void cancel() {
97+
cancelled_ = true;
98+
}
99+
100+
private:
101+
ScopeGuard() = delete;
102+
ScopeGuard(const ScopeGuard&) = delete;
103+
104+
void operator=(const ScopeGuard&) = delete;
105+
void operator=(ScopeGuard&&) = delete;
106+
107+
private:
108+
T callback_;
109+
bool cancelled_;
110+
};
111+
112+
template <typename T>
113+
ScopeGuard<T> MakeScopeGuard(T&& callback)
114+
{
115+
return ScopeGuard<T>(std::forward<T>(callback));
116+
}
117+
74118
template <typename T>
75119
T
76120
ReturnAndVoid(T& t)

tests/AMBuild.tests

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ binary.sources += [
5353
'test-inlinelist.cpp',
5454
'test-priority-queue.cpp',
5555
'test-refcounting.cpp',
56+
'test-raii.cpp',
5657
'test-string.cpp',
5758
'test-system.cpp',
5859
'test-threadlocal-threaded.cpp',

tests/test-raii.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// vim: set sts=4 ts=8 sw=4 tw=99 et:
2+
//
3+
// Copyright (C) 2021 AlliedModders LLC
4+
// All rights reserved.
5+
//
6+
// Redistribution and use in source and binary forms, with or without
7+
// modification, are permitted provided that the following conditions are met:
8+
//
9+
// * Redistributions of source code must retain the above copyright notice, this
10+
// list of conditions and the following disclaimer.
11+
// * Redistributions in binary form must reproduce the above copyright notice,
12+
// this list of conditions and the following disclaimer in the documentation
13+
// and/or other materials provided with the distribution.
14+
// * Neither the name of AlliedModders LLC nor the names of its contributors
15+
// may be used to endorse or promote products derived from this software
16+
// without specific prior written permission.
17+
//
18+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28+
// POSSIBILITY OF SUCH DAMAGE.
29+
30+
#include <amtl/am-raii.h>
31+
#include <gtest/gtest.h>
32+
#include "runner.h"
33+
34+
using namespace ke;
35+
36+
TEST(ScopeGuard, Invoke)
37+
{
38+
int invokes = 0;
39+
40+
{
41+
auto guard1 = MakeScopeGuard([&]() -> void {
42+
invokes++;
43+
});
44+
45+
{
46+
auto guard2 = MakeScopeGuard([&]() -> void {
47+
invokes++;
48+
});
49+
}
50+
ASSERT_EQ(invokes, 1);
51+
}
52+
ASSERT_EQ(invokes, 2);
53+
}
54+
55+
TEST(ScopeGuard, Cancel)
56+
{
57+
int invokes = 0;
58+
59+
{
60+
auto guard1 = MakeScopeGuard([&]() -> void {
61+
invokes++;
62+
});
63+
64+
guard1.cancel();
65+
}
66+
ASSERT_EQ(invokes, 0);
67+
}

0 commit comments

Comments
 (0)