]> git.proxmox.com Git - ceph.git/blob - ceph/src/common/deleter.h
d2272cace4b8d9ae63530841581f736c3984e404
[ceph.git] / ceph / src / common / deleter.h
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 #ifndef CEPH_COMMON_DELETER_H
23 #define CEPH_COMMON_DELETER_H
24
25 #include <atomic>
26 #include <cstdlib>
27 #include <new>
28 #include <utility>
29
30 /// \addtogroup memory-module
31 /// @{
32
33 /// Provides a mechanism for managing the lifetime of a buffer.
34 ///
35 /// A \c deleter is an object that is used to inform the consumer
36 /// of some buffer (not referenced by the deleter itself) how to
37 /// delete the buffer. This can be by calling an arbitrary function
38 /// or destroying an object carried by the deleter. Examples of
39 /// a deleter's encapsulated actions are:
40 ///
41 /// - calling \c std::free(p) on some captured pointer, p
42 /// - calling \c delete \c p on some captured pointer, p
43 /// - decrementing a reference count somewhere
44 ///
45 /// A deleter performs its action from its destructor.
46 class deleter final {
47 public:
48 /// \cond internal
49 struct impl;
50 struct raw_object_tag {};
51 /// \endcond
52 private:
53 // if bit 0 set, point to object to be freed directly.
54 impl* _impl = nullptr;
55 public:
56 /// Constructs an empty deleter that does nothing in its destructor.
57 deleter() = default;
58 deleter(const deleter&) = delete;
59 /// Moves a deleter.
60 deleter(deleter&& x) noexcept : _impl(x._impl) { x._impl = nullptr; }
61 /// \cond internal
62 explicit deleter(impl* i) : _impl(i) {}
63 deleter(raw_object_tag tag, void* object)
64 : _impl(from_raw_object(object)) {}
65 /// \endcond
66 /// Destroys the deleter and carries out the encapsulated action.
67 ~deleter();
68 deleter& operator=(deleter&& x);
69 deleter& operator=(deleter&) = delete;
70 /// Performs a sharing operation. The encapsulated action will only
71 /// be carried out after both the original deleter and the returned
72 /// deleter are both destroyed.
73 ///
74 /// \return a deleter with the same encapsulated action as this one.
75 deleter share();
76 /// Checks whether the deleter has an associated action.
77 explicit operator bool() const { return bool(_impl); }
78 /// \cond internal
79 void reset(impl* i) {
80 this->~deleter();
81 new (this) deleter(i);
82 }
83 /// \endcond
84 /// Appends another deleter to this deleter. When this deleter is
85 /// destroyed, both encapsulated actions will be carried out.
86 void append(deleter d);
87 private:
88 static bool is_raw_object(impl* i) {
89 auto x = reinterpret_cast<uintptr_t>(i);
90 return x & 1;
91 }
92 bool is_raw_object() const {
93 return is_raw_object(_impl);
94 }
95 static void* to_raw_object(impl* i) {
96 auto x = reinterpret_cast<uintptr_t>(i);
97 return reinterpret_cast<void*>(x & ~uintptr_t(1));
98 }
99 void* to_raw_object() const {
100 return to_raw_object(_impl);
101 }
102 impl* from_raw_object(void* object) {
103 auto x = reinterpret_cast<uintptr_t>(object);
104 return reinterpret_cast<impl*>(x | 1);
105 }
106 };
107
108 /// \cond internal
109 struct deleter::impl {
110 std::atomic_uint refs;
111 deleter next;
112 impl(deleter next) : refs(1), next(std::move(next)) {}
113 virtual ~impl() {}
114 };
115 /// \endcond
116
117 inline deleter::~deleter() {
118 if (is_raw_object()) {
119 std::free(to_raw_object());
120 return;
121 }
122 if (_impl && --_impl->refs == 0) {
123 delete _impl;
124 }
125 }
126
127 inline deleter& deleter::operator=(deleter&& x) {
128 if (this != &x) {
129 this->~deleter();
130 new (this) deleter(std::move(x));
131 }
132 return *this;
133 }
134
135 /// \cond internal
136 template <typename Deleter>
137 struct lambda_deleter_impl final : deleter::impl {
138 Deleter del;
139 lambda_deleter_impl(deleter next, Deleter&& del)
140 : impl(std::move(next)), del(std::move(del)) {}
141 ~lambda_deleter_impl() override { del(); }
142 };
143
144 template <typename Object>
145 struct object_deleter_impl final : deleter::impl {
146 Object obj;
147 object_deleter_impl(deleter next, Object&& obj)
148 : impl(std::move(next)), obj(std::move(obj)) {}
149 };
150
151 template <typename Object>
152 inline
153 object_deleter_impl<Object>* make_object_deleter_impl(deleter next, Object obj) {
154 return new object_deleter_impl<Object>(std::move(next), std::move(obj));
155 }
156 /// \endcond
157
158 /// Makes a \ref deleter that encapsulates the action of
159 /// destroying an object, as well as running another deleter. The input
160 /// object is moved to the deleter, and destroyed when the deleter is destroyed.
161 ///
162 /// \param d deleter that will become part of the new deleter's encapsulated action
163 /// \param o object whose destructor becomes part of the new deleter's encapsulated action
164 /// \related deleter
165 template <typename Object>
166 deleter make_deleter(deleter next, Object o) {
167 return deleter(new lambda_deleter_impl<Object>(std::move(next), std::move(o)));
168 }
169
170 /// Makes a \ref deleter that encapsulates the action of destroying an object. The input
171 /// object is moved to the deleter, and destroyed when the deleter is destroyed.
172 ///
173 /// \param o object whose destructor becomes the new deleter's encapsulated action
174 /// \related deleter
175 template <typename Object>
176 deleter make_deleter(Object o) {
177 return make_deleter(deleter(), std::move(o));
178 }
179
180 /// \cond internal
181 struct free_deleter_impl final : deleter::impl {
182 void* obj;
183 free_deleter_impl(void* obj) : impl(deleter()), obj(obj) {}
184 ~free_deleter_impl() override { std::free(obj); }
185 };
186 /// \endcond
187
188 inline deleter deleter::share() {
189 if (!_impl) {
190 return deleter();
191 }
192 if (is_raw_object()) {
193 _impl = new free_deleter_impl(to_raw_object());
194 }
195 ++_impl->refs;
196 return deleter(_impl);
197 }
198
199 // Appends 'd' to the chain of deleters. Avoids allocation if possible. For
200 // performance reasons the current chain should be shorter and 'd' should be
201 // longer.
202 inline void deleter::append(deleter d) {
203 if (!d._impl) {
204 return;
205 }
206 impl* next_impl = _impl;
207 deleter* next_d = this;
208 while (next_impl) {
209 if (next_impl == d._impl)
210 return ;
211 if (is_raw_object(next_impl)) {
212 next_d->_impl = next_impl = new free_deleter_impl(to_raw_object(next_impl));
213 }
214 if (next_impl->refs != 1) {
215 next_d->_impl = next_impl = make_object_deleter_impl(std::move(next_impl->next), deleter(next_impl));
216 }
217 next_d = &next_impl->next;
218 next_impl = next_d->_impl;
219 }
220 next_d->_impl = d._impl;
221 d._impl = nullptr;
222 }
223
224 /// Makes a deleter that calls \c std::free() when it is destroyed.
225 ///
226 /// \param obj object to free.
227 /// \related deleter
228 inline deleter make_free_deleter(void* obj) {
229 if (!obj) {
230 return deleter();
231 }
232 return deleter(deleter::raw_object_tag(), obj);
233 }
234
235 /// Makes a deleter that calls \c std::free() when it is destroyed, as well
236 /// as invoking the encapsulated action of another deleter.
237 ///
238 /// \param d deleter to invoke.
239 /// \param obj object to free.
240 /// \related deleter
241 inline deleter make_free_deleter(deleter next, void* obj) {
242 return make_deleter(std::move(next), [obj] () mutable { std::free(obj); });
243 }
244
245 /// \see make_deleter(Object)
246 /// \related deleter
247 template <typename T>
248 inline deleter make_object_deleter(T&& obj) {
249 return deleter{make_object_deleter_impl(deleter(), std::move(obj))};
250 }
251
252 /// \see make_deleter(deleter, Object)
253 /// \related deleter
254 template <typename T>
255 inline deleter make_object_deleter(deleter d, T&& obj) {
256 return deleter{make_object_deleter_impl(std::move(d), std::move(obj))};
257 }
258
259 /// @}
260
261 #endif /* CEPH_COMMON_DELETER_H */