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