xenium
deletable_object.hpp
1 //
2 // Copyright (c) 2018-2020 Manuel Pöter.
3 // Licensed under the MIT License. See LICENSE file in the project root for full license information.
4 //
5 
6 #ifndef XENIUM_DETAIL_DELETABLE_OBJECT_HPP
7 #define XENIUM_DETAIL_DELETABLE_OBJECT_HPP
8 
9 #include <memory>
10 #include <type_traits>
11 
12 #ifdef _MSC_VER
13  #pragma warning(push)
14  #pragma warning(disable : 26495) // uninitialized member variable
15 #endif
16 
17 namespace xenium::reclamation::detail {
18 
19 struct deletable_object {
20  virtual void delete_self() = 0;
21  deletable_object* next = nullptr;
22 
23 protected:
24  virtual ~deletable_object() = default;
25 };
26 
27 inline void delete_objects(deletable_object*& list) {
28  auto* cur = list;
29  for (deletable_object* next = nullptr; cur != nullptr; cur = next) {
30  next = cur->next;
31  cur->delete_self();
32  }
33  list = nullptr;
34 }
35 
36 template <class Derived, class DeleterT, class Base>
37 struct deletable_object_with_non_empty_deleter : Base {
38  using Deleter = DeleterT;
39  void delete_self() override {
40  auto& my_deleter = reinterpret_cast<Deleter&>(_deleter_buffer);
41  Deleter deleter(std::move(my_deleter));
42  my_deleter.~Deleter(); // NOLINT (use-after-move)
43 
44  deleter(static_cast<Derived*>(this));
45  }
46 
47  void set_deleter(Deleter deleter) { new (&_deleter_buffer) Deleter(std::move(deleter)); }
48 
49 private:
50  using buffer = typename std::aligned_storage<sizeof(Deleter), alignof(Deleter)>::type;
51  buffer _deleter_buffer;
52 };
53 
54 template <class Derived, class DeleterT, class Base>
55 struct deletable_object_with_empty_deleter : Base {
56  using Deleter = DeleterT;
57  void delete_self() override {
58  static_assert(std::is_default_constructible<Deleter>::value, "empty deleters must be default constructible");
59  Deleter deleter{};
60  deleter(static_cast<Derived*>(this));
61  }
62 
63  void set_deleter(Deleter /*deleter*/) {}
64 };
65 
66 template <class Derived, class Deleter = std::default_delete<Derived>, class Base = deletable_object>
67 using deletable_object_impl = std::conditional_t<std::is_empty<Deleter>::value,
68  deletable_object_with_empty_deleter<Derived, Deleter, Base>,
69  deletable_object_with_non_empty_deleter<Derived, Deleter, Base>>;
70 } // namespace xenium::reclamation::detail
71 
72 #ifdef _MSC_VER
73  #pragma warning(pop)
74 #endif
75 
76 #endif