Lagrange
scope_guard.h
1// Source: https://github.com/ricab/scope_guard
2// SPDX-License-Identifier: CC-PDDC
3//
4// Public domain implementation of the scoped guard concept
5//
6// This file has been modified by Adobe.
7//
8// All modifications are Copyright 2022 Adobe.
9
10#pragma once
11
12#include <type_traits>
13#include <utility>
14
15namespace lagrange {
16
18
19namespace sg_detail {
20
21// --- Some custom type traits ---
22
23// Type trait determining whether a type is callable with no arguments
24template <typename T, typename = void>
25struct is_noarg_callable_t : public std::false_type
26{
27 // in general, false
28};
29
30template <typename T>
31struct is_noarg_callable_t<T, decltype(std::declval<T&&>()())> : public std::true_type
32{
33 // only true when call expression valid
34};
35
36// Type trait determining whether a no-argument callable returns void
37template <typename T>
38struct returns_void_t : public std::is_same<void, decltype(std::declval<T&&>()())>
39{
40};
41
42// Type trait determining whether a no-arg callable is nothrow invocable if
43// required. This is where SG_REQUIRE_NOEXCEPT logic is encapsulated.
44template <typename T>
45struct is_nothrow_invocable_if_required_t : public std::true_type
46{
47};
48
49// logic AND of two or more type traits
50template <typename A, typename B, typename... C>
51struct and_t : public and_t<A, and_t<B, C...>>
52{
53 // for more than two arguments
54};
55
56template <typename A, typename B>
57struct and_t<A, B> : public std::conditional<A::value, B, A>::type
58{
59 // for two arguments
60};
61
62// Type trait determining whether a type is a proper scope_guard callback.
63template <typename T>
64struct is_proper_sg_callback_t : public and_t<
65 is_noarg_callable_t<T>,
66 returns_void_t<T>,
67 is_nothrow_invocable_if_required_t<T>,
68 std::is_nothrow_destructible<T>>
69{
70};
71
72// --- The actual scope_guard template ---
73
74template <
75 typename Callback,
76 typename = typename std::enable_if<is_proper_sg_callback_t<Callback>::value>::type>
77class scope_guard;
78
80
81// --- Now the friend maker ---
82
83//
84// we need this in the inner namespace due to MSVC bugs preventing sg_detail::scope_guard from
85// befriending a sg::make_scope_guard template instance in the parent namespace (see
86// https://is.gd/xFfFhE).
87//
88
91
107template <typename Callback>
108sg_detail::scope_guard<Callback> make_scope_guard(Callback&& callback) noexcept(
109 std::is_nothrow_constructible<Callback, Callback&&>::value);
110
112
113// --- The template specialization that actually defines the class ---
114
116
117template <typename Callback>
118class scope_guard<Callback> final
119{
120public:
121 typedef Callback callback_type;
122
123 scope_guard(scope_guard&& other) noexcept(
124 std::is_nothrow_constructible<Callback, Callback&&>::value);
125
126 ~scope_guard() noexcept; // highlight noexcept dtor
127
128 void dismiss() noexcept;
129
130public:
131 scope_guard() = delete;
132 scope_guard(const scope_guard&) = delete;
133 scope_guard& operator=(const scope_guard&) = delete;
134 scope_guard& operator=(scope_guard&&) = delete;
135
136private:
137 // meant for friends only
138 explicit scope_guard(Callback&& callback) noexcept(
139 std::is_nothrow_constructible<Callback, Callback&&>::value);
140
141 // only make_scope_guard can create scope_guards from scratch (i.e. non-move)
142 friend scope_guard<Callback> make_scope_guard<Callback>(Callback&&) noexcept(
143 std::is_nothrow_constructible<Callback, Callback&&>::value);
144
145private:
146 Callback m_callback;
147 bool m_active;
148};
149
150} // namespace sg_detail
151
152
153// --- Now the single public maker function ---
154
155using sg_detail::make_scope_guard; // see comment on declaration above
156
158
159template <typename Callback>
160sg_detail::scope_guard<Callback>::scope_guard(Callback&& callback) noexcept(
161 std::is_nothrow_constructible<Callback, Callback&&>::value)
162 // use () instead of {} because of DR 1467 (https://is.gd/WHmWuo), which still impacts older
163 // compilers (e.g. GCC 4.x and clang <=3.6, see https://godbolt.org/g/TE9tPJ and
164 // https://is.gd/Tsmh8G)
165 : m_callback(std::forward<Callback>(callback))
166 , m_active{true}
167{}
168
170
171template <typename Callback>
172sg_detail::scope_guard<Callback>::~scope_guard() noexcept
173{
174 if (m_active) m_callback();
175}
176
178
179template <typename Callback>
180sg_detail::scope_guard<Callback>::scope_guard(scope_guard&& other) noexcept(
181 std::is_nothrow_constructible<Callback, Callback&&>::value)
182 : m_callback(std::forward<Callback>(other.m_callback)) // idem
183 , m_active{std::move(other.m_active)}
184{
185 other.m_active = false;
186}
187
189
190template <typename Callback>
191inline void sg_detail::scope_guard<Callback>::dismiss() noexcept
192{
193 m_active = false;
194}
195
197
198template <typename Callback>
199inline auto sg_detail::make_scope_guard(Callback&& callback) noexcept(
200 std::is_nothrow_constructible<Callback, Callback&&>::value) -> sg_detail::scope_guard<Callback>
201{
202 return sg_detail::scope_guard<Callback>{std::forward<Callback>(callback)};
203}
204
206
207} // namespace lagrange
sg_detail::scope_guard< Callback > make_scope_guard(Callback &&callback) noexcept(std::is_nothrow_constructible< Callback, Callback && >::value)
Creates a scope guard around a callable object.
Main namespace for Lagrange.
Definition: AABBIGL.h:30