Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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
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.
43 class 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
106 struct 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
114 inline 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
124 inline 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
133 template <typename Deleter>
134 struct 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
141 template <typename Object>
142 struct 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
148 template <typename Object>
149 inline
150 object_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
162 template <typename Object>
163 deleter 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
172 template <typename Object>
173 deleter make_deleter(Object o) {
174   return make_deleter(deleter(), std::move(o));
175 }
176
177 /// \cond internal
178 struct 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
185 inline 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.
199 inline 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
225 inline 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
238 inline 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
244 template <typename T>
245 inline 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
251 template <typename T>
252 inline 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 */