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.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
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
19 * Copyright (C) 2014 Cloudius Systems, Ltd.
22 #ifndef CEPH_COMMON_DELETER_H
23 #define CEPH_COMMON_DELETER_H
29 /// \addtogroup memory-module
32 /// Provides a mechanism for managing the lifetime of a buffer.
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:
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
44 /// A deleter performs its action from its destructor.
49 struct raw_object_tag
{};
52 // if bit 0 set, point to object to be freed directly.
53 impl
* _impl
= nullptr;
55 /// Constructs an empty deleter that does nothing in its destructor.
57 deleter(const deleter
&) = delete;
59 deleter(deleter
&& x
) noexcept
: _impl(x
._impl
) { x
._impl
= nullptr; }
61 explicit deleter(impl
* i
) : _impl(i
) {}
62 deleter(raw_object_tag tag
, void* object
)
63 : _impl(from_raw_object(object
)) {}
65 /// Destroys the deleter and carries out the encapsulated action.
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.
73 /// \return a deleter with the same encapsulated action as this one.
75 /// Checks whether the deleter has an associated action.
76 explicit operator bool() const { return bool(_impl
); }
80 new (this) deleter(i
);
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
);
87 static bool is_raw_object(impl
* i
) {
88 auto x
= reinterpret_cast<uintptr_t>(i
);
91 bool is_raw_object() const {
92 return is_raw_object(_impl
);
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));
98 void* to_raw_object() const {
99 return to_raw_object(_impl
);
101 impl
* from_raw_object(void* object
) {
102 auto x
= reinterpret_cast<uintptr_t>(object
);
103 return reinterpret_cast<impl
*>(x
| 1);
108 struct deleter::impl
{
109 std::atomic_uint refs
;
111 impl(deleter next
) : refs(1), next(std::move(next
)) {}
116 inline deleter::~deleter() {
117 if (is_raw_object()) {
118 std::free(to_raw_object());
121 if (_impl
&& --_impl
->refs
== 0) {
126 inline deleter
& deleter::operator=(deleter
&& x
) {
129 new (this) deleter(std::move(x
));
135 template <typename Deleter
>
136 struct lambda_deleter_impl final
: deleter::impl
{
138 lambda_deleter_impl(deleter next
, Deleter
&& del
)
139 : impl(std::move(next
)), del(std::move(del
)) {}
140 ~lambda_deleter_impl() override
{ del(); }
143 template <typename Object
>
144 struct object_deleter_impl final
: deleter::impl
{
146 object_deleter_impl(deleter next
, Object
&& obj
)
147 : impl(std::move(next
)), obj(std::move(obj
)) {}
150 template <typename Object
>
152 object_deleter_impl
<Object
>* make_object_deleter_impl(deleter next
, Object obj
) {
153 return new object_deleter_impl
<Object
>(std::move(next
), std::move(obj
));
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.
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
164 template <typename Object
>
165 deleter
make_deleter(deleter next
, Object o
) {
166 return deleter(new lambda_deleter_impl
<Object
>(std::move(next
), std::move(o
)));
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.
172 /// \param o object whose destructor becomes the new deleter's encapsulated action
174 template <typename Object
>
175 deleter
make_deleter(Object o
) {
176 return make_deleter(deleter(), std::move(o
));
180 struct free_deleter_impl final
: deleter::impl
{
182 free_deleter_impl(void* obj
) : impl(deleter()), obj(obj
) {}
183 ~free_deleter_impl() override
{ std::free(obj
); }
187 inline deleter
deleter::share() {
191 if (is_raw_object()) {
192 _impl
= new free_deleter_impl(to_raw_object());
195 return deleter(_impl
);
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
201 inline void deleter::append(deleter d
) {
205 impl
* next_impl
= _impl
;
206 deleter
* next_d
= this;
208 if (next_impl
== d
._impl
)
210 if (is_raw_object(next_impl
)) {
211 next_d
->_impl
= next_impl
= new free_deleter_impl(to_raw_object(next_impl
));
213 if (next_impl
->refs
!= 1) {
214 next_d
->_impl
= next_impl
= make_object_deleter_impl(std::move(next_impl
->next
), deleter(next_impl
));
216 next_d
= &next_impl
->next
;
217 next_impl
= next_d
->_impl
;
219 next_d
->_impl
= d
._impl
;
223 /// Makes a deleter that calls \c std::free() when it is destroyed.
225 /// \param obj object to free.
227 inline deleter
make_free_deleter(void* obj
) {
231 return deleter(deleter::raw_object_tag(), obj
);
234 /// Makes a deleter that calls \c std::free() when it is destroyed, as well
235 /// as invoking the encapsulated action of another deleter.
237 /// \param d deleter to invoke.
238 /// \param obj object to free.
240 inline deleter
make_free_deleter(deleter next
, void* obj
) {
241 return make_deleter(std::move(next
), [obj
] () mutable { std::free(obj
); });
244 /// \see make_deleter(Object)
246 template <typename T
>
247 inline deleter
make_object_deleter(T
&& obj
) {
248 return deleter
{make_object_deleter_impl(deleter(), std::move(obj
))};
251 /// \see make_deleter(deleter, Object)
253 template <typename T
>
254 inline deleter
make_object_deleter(deleter d
, T
&& obj
) {
255 return deleter
{make_object_deleter_impl(std::move(d
), std::move(obj
))};
260 #endif /* CEPH_COMMON_DELETER_H */