]> git.proxmox.com Git - ceph.git/blob - ceph/src/seastar/include/seastar/core/deleter.hh
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / seastar / include / seastar / core / deleter.hh
1 /*
2 * This file is open source software, licensed to you under the terms
3 * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
4 * distributed with this work for additional information regarding copyright
5 * ownership. You may not use this file except in compliance with the License.
6 *
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
16 * under the License.
17 */
18 /*
19 * Copyright (C) 2014 Cloudius Systems, Ltd.
20 */
21
22 #pragma once
23
24 #include <memory>
25 #include <cstdlib>
26 #include <assert.h>
27 #include <type_traits>
28
29 namespace seastar {
30
31 /// \addtogroup memory-module
32 /// @{
33
34 /// Provides a mechanism for managing the lifetime of a buffer.
35 ///
36 /// A \c deleter is an object that is used to inform the consumer
37 /// of some buffer (not referenced by the deleter itself) how to
38 /// delete the buffer. This can be by calling an arbitrary function
39 /// or destroying an object carried by the deleter. Examples of
40 /// a deleter's encapsulated actions are:
41 ///
42 /// - calling \c std::free(p) on some captured pointer, p
43 /// - calling \c delete \c p on some captured pointer, p
44 /// - decrementing a reference count somewhere
45 ///
46 /// A deleter performs its action from its destructor.
47 class deleter final {
48 public:
49 /// \cond internal
50 struct impl;
51 struct raw_object_tag {};
52 /// \endcond
53 private:
54 // if bit 0 set, point to object to be freed directly.
55 impl* _impl = nullptr;
56 public:
57 /// Constructs an empty deleter that does nothing in its destructor.
58 deleter() noexcept = default;
59 deleter(const deleter&) = delete;
60 /// Moves a deleter.
61 deleter(deleter&& x) noexcept : _impl(x._impl) { x._impl = nullptr; }
62 /// \cond internal
63 explicit deleter(impl* i) noexcept : _impl(i) {}
64 deleter(raw_object_tag tag, void* object) noexcept
65 : _impl(from_raw_object(object)) {}
66 /// \endcond
67 /// Destroys the deleter and carries out the encapsulated action.
68 ~deleter();
69 deleter& operator=(deleter&& x) noexcept;
70 deleter& operator=(deleter&) = delete;
71 /// Performs a sharing operation. The encapsulated action will only
72 /// be carried out after both the original deleter and the returned
73 /// deleter are both destroyed.
74 ///
75 /// \return a deleter with the same encapsulated action as this one.
76 deleter share();
77 /// Checks whether the deleter has an associated action.
78 explicit operator bool() const noexcept { return bool(_impl); }
79 /// \cond internal
80 void reset(impl* i) {
81 this->~deleter();
82 new (this) deleter(i);
83 }
84 /// \endcond
85 /// Appends another deleter to this deleter. When this deleter is
86 /// destroyed, both encapsulated actions will be carried out.
87 void append(deleter d);
88 private:
89 static bool is_raw_object(impl* i) noexcept {
90 auto x = reinterpret_cast<uintptr_t>(i);
91 return x & 1;
92 }
93 bool is_raw_object() const noexcept {
94 return is_raw_object(_impl);
95 }
96 static void* to_raw_object(impl* i) noexcept {
97 auto x = reinterpret_cast<uintptr_t>(i);
98 return reinterpret_cast<void*>(x & ~uintptr_t(1));
99 }
100 void* to_raw_object() const noexcept {
101 return to_raw_object(_impl);
102 }
103 impl* from_raw_object(void* object) noexcept {
104 auto x = reinterpret_cast<uintptr_t>(object);
105 return reinterpret_cast<impl*>(x | 1);
106 }
107 };
108
109 /// \cond internal
110 struct deleter::impl {
111 unsigned refs = 1;
112 deleter next;
113 impl(deleter next) : next(std::move(next)) {}
114 virtual ~impl() {}
115 };
116 /// \endcond
117
118 inline
119 deleter::~deleter() {
120 if (is_raw_object()) {
121 std::free(to_raw_object());
122 return;
123 }
124 if (_impl && --_impl->refs == 0) {
125 delete _impl;
126 }
127 }
128
129 inline
130 deleter& deleter::operator=(deleter&& x) noexcept {
131 if (this != &x) {
132 this->~deleter();
133 new (this) deleter(std::move(x));
134 }
135 return *this;
136 }
137
138 /// \cond internal
139 template <typename Deleter>
140 struct lambda_deleter_impl final : deleter::impl {
141 Deleter del;
142 lambda_deleter_impl(deleter next, Deleter&& del)
143 : impl(std::move(next)), del(std::move(del)) {}
144 virtual ~lambda_deleter_impl() override { del(); }
145 };
146
147 template <typename Object>
148 struct object_deleter_impl final : deleter::impl {
149 Object obj;
150 object_deleter_impl(deleter next, Object&& obj)
151 : impl(std::move(next)), obj(std::move(obj)) {}
152 };
153
154 template <typename Object>
155 inline
156 object_deleter_impl<Object>* make_object_deleter_impl(deleter next, Object obj) {
157 return new object_deleter_impl<Object>(std::move(next), std::move(obj));
158 }
159 /// \endcond
160
161 /// Makes a \ref deleter that encapsulates the action of
162 /// destroying an object, as well as running another deleter. The input
163 /// object is moved to the deleter, and destroyed when the deleter is destroyed.
164 ///
165 /// \param next deleter that will become part of the new deleter's encapsulated action
166 /// \param o object whose destructor becomes part of the new deleter's encapsulated action
167 /// \related deleter
168 template <typename Object>
169 deleter
170 make_deleter(deleter next, Object o) {
171 return deleter(new lambda_deleter_impl<Object>(std::move(next), std::move(o)));
172 }
173
174 /// Makes a \ref deleter that encapsulates the action of destroying an object. The input
175 /// object is moved to the deleter, and destroyed when the deleter is destroyed.
176 ///
177 /// \param o object whose destructor becomes the new deleter's encapsulated action
178 /// \related deleter
179 template <typename Object>
180 deleter
181 make_deleter(Object o) {
182 return make_deleter(deleter(), std::move(o));
183 }
184
185 /// \cond internal
186 struct free_deleter_impl final : deleter::impl {
187 void* obj;
188 free_deleter_impl(void* obj) : impl(deleter()), obj(obj) {}
189 virtual ~free_deleter_impl() override { std::free(obj); }
190 };
191 /// \endcond
192
193 inline
194 deleter
195 deleter::share() {
196 if (!_impl) {
197 return deleter();
198 }
199 if (is_raw_object()) {
200 _impl = new free_deleter_impl(to_raw_object());
201 }
202 ++_impl->refs;
203 return deleter(_impl);
204 }
205
206 // Appends 'd' to the chain of deleters. Avoids allocation if possible. For
207 // performance reasons the current chain should be shorter and 'd' should be
208 // longer.
209 inline
210 void deleter::append(deleter d) {
211 if (!d._impl) {
212 return;
213 }
214 impl* next_impl = _impl;
215 deleter* next_d = this;
216 while (next_impl) {
217 if (next_impl == d._impl) {
218 return; // Already appended
219 }
220 if (is_raw_object(next_impl)) {
221 next_d->_impl = next_impl = new free_deleter_impl(to_raw_object(next_impl));
222 }
223
224 if (next_impl->refs != 1) {
225 next_d->_impl = next_impl = make_object_deleter_impl(deleter(next_impl), std::move(d));
226 return;
227 }
228
229 next_d = &next_impl->next;
230 next_impl = next_d->_impl;
231 }
232 next_d->_impl = d._impl;
233 d._impl = nullptr;
234 }
235
236 /// Makes a deleter that calls \c std::free() when it is destroyed.
237 ///
238 /// \param obj object to free.
239 /// \related deleter
240 inline
241 deleter
242 make_free_deleter(void* obj) {
243 if (!obj) {
244 return deleter();
245 }
246 return deleter(deleter::raw_object_tag(), obj);
247 }
248
249 /// Makes a deleter that calls \c std::free() when it is destroyed, as well
250 /// as invoking the encapsulated action of another deleter.
251 ///
252 /// \param next deleter to invoke.
253 /// \param obj object to free.
254 /// \related deleter
255 inline
256 deleter
257 make_free_deleter(deleter next, void* obj) {
258 return make_deleter(std::move(next), [obj] () mutable { std::free(obj); });
259 }
260
261 /// \see make_deleter(Object)
262 /// \related deleter
263 template <typename T>
264 inline
265 deleter
266 make_object_deleter(T&& obj) {
267 return deleter{make_object_deleter_impl(deleter(), std::move(obj))};
268 }
269
270 /// \see make_deleter(deleter, Object)
271 /// \related deleter
272 template <typename T>
273 inline
274 deleter
275 make_object_deleter(deleter d, T&& obj) {
276 return deleter{make_object_deleter_impl(std::move(d), std::move(obj))};
277 }
278
279 /// @}
280
281 }