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 { namespace reclamation { namespace detail {
18 
19  struct deletable_object
20  {
21  virtual void delete_self() = 0;
22  deletable_object* next = nullptr;
23  protected:
24  virtual ~deletable_object() = default;
25  };
26 
27  inline void delete_objects(deletable_object*& list)
28  {
29  auto cur = list;
30  for (deletable_object* next = nullptr; cur != nullptr; cur = next)
31  {
32  next = cur->next;
33  cur->delete_self();
34  }
35  list = nullptr;
36  }
37 
38  template <class Derived, class DeleterT, class Base>
39  struct deletable_object_with_non_empty_deleter : Base
40  {
41  using Deleter = DeleterT;
42  virtual void delete_self() override
43  {
44  Deleter& my_deleter = reinterpret_cast<Deleter&>(deleter_buffer);
45  Deleter deleter(std::move(my_deleter));
46  my_deleter.~Deleter();
47 
48  deleter(static_cast<Derived*>(this));
49  }
50 
51  void set_deleter(Deleter deleter)
52  {
53  new (&deleter_buffer) Deleter(std::move(deleter));
54  }
55 
56  private:
57  using buffer = typename std::aligned_storage<sizeof(Deleter), alignof(Deleter)>::type;
58  buffer deleter_buffer;
59  };
60 
61  template <class Derived, class DeleterT, class Base>
62  struct deletable_object_with_empty_deleter : Base
63  {
64  using Deleter = DeleterT;
65  virtual void delete_self() override
66  {
67  static_assert(std::is_default_constructible<Deleter>::value, "empty deleters must be default constructible");
68  Deleter deleter{};
69  deleter(static_cast<Derived*>(this));
70  }
71 
72  void set_deleter(Deleter /*deleter*/) {}
73  };
74 
75  template <class Derived, class Deleter = std::default_delete<Derived>, class Base = deletable_object>
76  using deletable_object_impl = std::conditional_t<std::is_empty<Deleter>::value,
77  deletable_object_with_empty_deleter<Derived, Deleter, Base>,
78  deletable_object_with_non_empty_deleter<Derived, Deleter, Base>
79  >;
80 }}}
81 
82 #ifdef _MSC_VER
83 #pragma warning(pop)
84 #endif
85 
86 #endif