Seastar
High performance C++ framework for concurrent servers
deleter.hh
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 #pragma once
23 
24 #include <memory>
25 #include <cstdlib>
26 #include <assert.h>
27 #include <type_traits>
28 
29 namespace seastar {
30 
33 
47 class deleter final {
48 public:
50  struct impl;
51  struct raw_object_tag {};
53 private:
54  // if bit 0 set, point to object to be freed directly.
55  impl* _impl = nullptr;
56 public:
58  deleter() noexcept = default;
59  deleter(const deleter&) = delete;
61  deleter(deleter&& x) noexcept : _impl(x._impl) { x._impl = nullptr; }
63  explicit deleter(impl* i) noexcept : _impl(i) {}
64  deleter(raw_object_tag tag, void* object) noexcept
65  : _impl(from_raw_object(object)) {}
68  ~deleter();
69  deleter& operator=(deleter&& x) noexcept;
70  deleter& operator=(deleter&) = delete;
76  deleter share();
78  explicit operator bool() const noexcept { return bool(_impl); }
80  void reset(impl* i) {
81  this->~deleter();
82  new (this) deleter(i);
83  }
87  void append(deleter d);
88 private:
89  static bool is_raw_object(impl* i) noexcept {
90  auto x = reinterpret_cast<uintptr_t>(i);
91  return x & 1;
92  }
93  bool is_raw_object() const noexcept {
94  return is_raw_object(_impl);
95  }
96  static void* to_raw_object(impl* i) noexcept {
97  auto x = reinterpret_cast<uintptr_t>(i);
98  return reinterpret_cast<void*>(x & ~uintptr_t(1));
99  }
100  void* to_raw_object() const noexcept {
101  return to_raw_object(_impl);
102  }
103  impl* from_raw_object(void* object) noexcept {
104  auto x = reinterpret_cast<uintptr_t>(object);
105  return reinterpret_cast<impl*>(x | 1);
106  }
107 };
108 
110 struct deleter::impl {
111  unsigned refs = 1;
112  deleter next;
113  impl(deleter next) : next(std::move(next)) {}
114  virtual ~impl() {}
115 };
117 
118 inline
120  if (is_raw_object()) {
121  std::free(to_raw_object());
122  return;
123  }
124  if (_impl && --_impl->refs == 0) {
125  delete _impl;
126  }
127 }
128 
129 inline
130 deleter& deleter::operator=(deleter&& x) noexcept {
131  if (this != &x) {
132  this->~deleter();
133  new (this) deleter(std::move(x));
134  }
135  return *this;
136 }
137 
139 template <typename Deleter>
140 struct lambda_deleter_impl final : deleter::impl {
141  Deleter del;
142  lambda_deleter_impl(deleter next, Deleter&& del)
143  : impl(std::move(next)), del(std::move(del)) {}
144  virtual ~lambda_deleter_impl() override { del(); }
145 };
146 
147 template <typename Object>
148 struct object_deleter_impl final : deleter::impl {
149  Object obj;
150  object_deleter_impl(deleter next, Object&& obj)
151  : impl(std::move(next)), obj(std::move(obj)) {}
152 };
153 
154 template <typename Object>
155 inline
156 object_deleter_impl<Object>* make_object_deleter_impl(deleter next, Object obj) {
157  return new object_deleter_impl<Object>(std::move(next), std::move(obj));
158 }
160 
168 template <typename Object>
169 deleter
170 make_deleter(deleter next, Object o) {
171  return deleter(new lambda_deleter_impl<Object>(std::move(next), std::move(o)));
172 }
173 
179 template <typename Object>
180 deleter
181 make_deleter(Object o) {
182  return make_deleter(deleter(), std::move(o));
183 }
184 
186 struct free_deleter_impl final : deleter::impl {
187  void* obj;
188  free_deleter_impl(void* obj) : impl(deleter()), obj(obj) {}
189  virtual ~free_deleter_impl() override { std::free(obj); }
190 };
192 
193 inline
194 deleter
196  if (!_impl) {
197  return deleter();
198  }
199  if (is_raw_object()) {
200  _impl = new free_deleter_impl(to_raw_object());
201  }
202  ++_impl->refs;
203  return deleter(_impl);
204 }
205 
206 // Appends 'd' to the chain of deleters. Avoids allocation if possible. For
207 // performance reasons the current chain should be shorter and 'd' should be
208 // longer.
209 inline
211  if (!d._impl) {
212  return;
213  }
214  impl* next_impl = _impl;
215  deleter* next_d = this;
216  while (next_impl) {
217  if (next_impl == d._impl) {
218  return; // Already appended
219  }
220  if (is_raw_object(next_impl)) {
221  next_d->_impl = next_impl = new free_deleter_impl(to_raw_object(next_impl));
222  }
223 
224  if (next_impl->refs != 1) {
225  next_d->_impl = next_impl = make_object_deleter_impl(deleter(next_impl), std::move(d));
226  return;
227  }
228 
229  next_d = &next_impl->next;
230  next_impl = next_d->_impl;
231  }
232  next_d->_impl = d._impl;
233  d._impl = nullptr;
234 }
235 
240 inline
241 deleter
242 make_free_deleter(void* obj) {
243  if (!obj) {
244  return deleter();
245  }
246  return deleter(deleter::raw_object_tag(), obj);
247 }
248 
255 inline
256 deleter
257 make_free_deleter(deleter next, void* obj) {
258  return make_deleter(std::move(next), [obj] () mutable { std::free(obj); });
259 }
260 
263 template <typename T>
264 inline
265 deleter
267  return deleter{make_object_deleter_impl(deleter(), std::move(obj))};
268 }
269 
272 template <typename T>
273 inline
274 deleter
276  return deleter{make_object_deleter_impl(std::move(d), std::move(obj))};
277 }
278 
280 
281 }
seastar::deleter::make_object_deleter
deleter make_object_deleter(T &&obj)
Definition: deleter.hh:266
seastar
Seastar API namespace.
Definition: abort_on_ebadf.hh:24
seastar::deleter::make_object_deleter
deleter make_object_deleter(deleter d, T &&obj)
Definition: deleter.hh:275
seastar::deleter::make_free_deleter
deleter make_free_deleter(deleter next, void *obj)
Definition: deleter.hh:257
seastar::deleter::make_deleter
deleter make_deleter(deleter next, Object o)
Definition: deleter.hh:170
seastar::deleter::deleter
deleter(deleter &&x) noexcept
Moves a deleter.
Definition: deleter.hh:61
seastar::deleter::share
deleter share()
Definition: deleter.hh:195
seastar::deleter::make_free_deleter
deleter make_free_deleter(void *obj)
Definition: deleter.hh:242
seastar::deleter::make_deleter
deleter make_deleter(Object o)
Definition: deleter.hh:181
impl
holds the implementation parts of the metrics layer, do not use directly.
seastar::deleter
Definition: deleter.hh:47
seastar::deleter::~deleter
~deleter()
Destroys the deleter and carries out the encapsulated action.
Definition: deleter.hh:119
seastar::deleter::append
void append(deleter d)
Definition: deleter.hh:210
seastar::deleter::deleter
deleter() noexcept=default
Constructs an empty deleter that does nothing in its destructor.