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