CommonLibSSE NG
BSTSmartPointer.h
Go to the documentation of this file.
1 #pragma once
2 
3 namespace RE
4 {
5  template <class T>
7  {
8  static void Acquire(T* a_ptr)
9  {
10  a_ptr->IncRef();
11  }
12 
13  static void Release(T* a_ptr)
14  {
15  if (a_ptr->DecRef() == 0) {
16  delete a_ptr;
17  }
18  }
19  };
20 
21  template <class T>
23  {
24  constexpr static void Acquire([[maybe_unused]] T* a_ptr)
25  {
26  }
27 
28  static void Release(T* a_ptr)
29  {
30  delete a_ptr;
31  }
32  };
33 
34  template <class T, template <class> class RefManager = BSTSmartPointerIntrusiveRefCount>
36  {
37  public:
38  using element_type = T;
39  using reference_manager = RefManager<T>;
40 
41  // 1
42  inline constexpr BSTSmartPointer() noexcept :
43  _ptr(nullptr)
44  {}
45 
46  // 2
47  inline constexpr BSTSmartPointer(std::nullptr_t) noexcept :
48  _ptr(nullptr)
49  {}
50 
51  // 3
52  template <
53  class Y,
54  std::enable_if_t<
55  std::is_convertible_v<
56  Y*,
57  element_type*>,
58  int> = 0>
59  inline explicit BSTSmartPointer(Y* a_rhs) :
60  _ptr(a_rhs)
61  {
62  TryAttach();
63  }
64 
65  // 9a
66  inline BSTSmartPointer(const BSTSmartPointer& a_rhs) :
67  _ptr(a_rhs._ptr)
68  {
69  TryAttach();
70  }
71 
72  // 9b
73  template <
74  class Y,
75  std::enable_if_t<
76  std::is_convertible_v<
77  Y*,
78  element_type*>,
79  int> = 0>
80  inline BSTSmartPointer(const BSTSmartPointer<Y>& a_rhs) :
81  _ptr(a_rhs._ptr)
82  {
83  TryAttach();
84  }
85 
86  // 10a
87  inline BSTSmartPointer(BSTSmartPointer&& a_rhs) noexcept :
88  _ptr(std::move(a_rhs._ptr))
89  {
90  a_rhs._ptr = nullptr;
91  }
92 
93  // 10b
94  template <
95  class Y,
96  std::enable_if_t<
97  std::is_convertible_v<
98  Y*,
99  element_type*>,
100  int> = 0>
101  inline BSTSmartPointer(BSTSmartPointer<Y>&& a_rhs) noexcept :
102  _ptr(std::move(a_rhs._ptr))
103  {
104  a_rhs._ptr = nullptr;
105  }
106 
108  {
109  TryDetach();
110  }
111 
112  // 1a
114  {
115  if (this != std::addressof(a_rhs)) {
116  TryDetach();
117  _ptr = a_rhs._ptr;
118  TryAttach();
119  }
120  return *this;
121  }
122 
123  // 1b
124  template <
125  class Y,
126  std::enable_if_t<
127  std::is_convertible_v<
128  Y*,
129  element_type*>,
130  int> = 0>
132  {
133  TryDetach();
134  _ptr = a_rhs._ptr;
135  TryAttach();
136  return *this;
137  }
138 
139  // 2a
141  {
142  if (this != std::addressof(a_rhs)) {
143  TryDetach();
144  _ptr = std::move(a_rhs._ptr);
145  a_rhs._ptr = nullptr;
146  }
147  return *this;
148  }
149 
150  // 2b
151  template <
152  class Y,
153  std::enable_if_t<
154  std::is_convertible_v<
155  Y*,
156  element_type*>,
157  int> = 0>
159  {
160  TryDetach();
161  _ptr = std::move(a_rhs._ptr);
162  a_rhs._ptr = nullptr;
163  return *this;
164  }
165 
166  inline void reset()
167  {
168  TryDetach();
169  }
170 
171  template <
172  class Y,
173  std::enable_if_t<
174  std::is_convertible_v<
175  Y*,
176  element_type*>,
177  int> = 0>
178  inline void reset(Y* a_ptr)
179  {
180  if (_ptr != a_ptr) {
181  TryDetach();
182  _ptr = a_ptr;
183  TryAttach();
184  }
185  }
186 
187  [[nodiscard]] constexpr element_type* get() const noexcept
188  {
189  return _ptr;
190  }
191 
192  [[nodiscard]] explicit constexpr operator bool() const noexcept
193  {
194  return static_cast<bool>(_ptr);
195  }
196 
197  [[nodiscard]] constexpr element_type& operator*() const noexcept
198  {
199  assert(static_cast<bool>(*this));
200  return *_ptr;
201  }
202 
203  [[nodiscard]] constexpr element_type* operator->() const noexcept
204  {
205  assert(static_cast<bool>(*this));
206  return _ptr;
207  }
208 
209  protected:
210  template <class, template <class> class>
211  friend class BSTSmartPointer;
212 
213  inline void TryAttach()
214  {
215  if (_ptr) {
216  reference_manager::Acquire(_ptr);
217  }
218  }
219 
220  inline void TryDetach()
221  {
222  if (_ptr) {
223  reference_manager::Release(_ptr);
224  _ptr = nullptr;
225  }
226  }
227 
228  // members
230  };
231  static_assert(sizeof(BSTSmartPointer<void*>) == 0x8);
232 
233  template <class T, class... Args>
234  [[nodiscard]] inline BSTSmartPointer<T> make_smart(Args&&... a_args)
235  {
236  return BSTSmartPointer<T>{ new T(std::forward<Args>(a_args)...) };
237  }
238 
239  template <class T1, class T2>
240  [[nodiscard]] constexpr bool operator==(const BSTSmartPointer<T1>& a_lhs, const BSTSmartPointer<T2>& a_rhs)
241  {
242  return a_lhs.get() == a_rhs.get();
243  }
244 
245  template <class T1, class T2>
246  [[nodiscard]] constexpr bool operator!=(const BSTSmartPointer<T1>& a_lhs, const BSTSmartPointer<T2>& a_rhs)
247  {
248  return !(a_lhs == a_rhs);
249  }
250 
251  template <class T>
252  [[nodiscard]] constexpr bool operator==(const BSTSmartPointer<T>& a_lhs, std::nullptr_t) noexcept
253  {
254  return !a_lhs;
255  }
256 
257  template <class T>
258  [[nodiscard]] constexpr bool operator==(std::nullptr_t, const BSTSmartPointer<T>& a_rhs) noexcept
259  {
260  return !a_rhs;
261  }
262 
263  template <class T>
264  [[nodiscard]] constexpr bool operator!=(const BSTSmartPointer<T>& a_lhs, std::nullptr_t) noexcept
265  {
266  return static_cast<bool>(a_lhs);
267  }
268 
269  template <class T>
270  [[nodiscard]] constexpr bool operator!=(std::nullptr_t, const BSTSmartPointer<T>& a_rhs) noexcept
271  {
272  return static_cast<bool>(a_rhs);
273  }
274 
275  template <class T>
277 
278  template <class T>
280  static_assert(sizeof(BSTAutoPointer<void*>) == 0x8);
281 }
282 
283 #define BSSmartPointer(className) \
284  class className; \
285  using className##Ptr = RE::BSTSmartPointer<className>;
Definition: BSTSmartPointer.h:36
BSTSmartPointer(const BSTSmartPointer< Y > &a_rhs)
Definition: BSTSmartPointer.h:80
BSTSmartPointer(BSTSmartPointer &&a_rhs) noexcept
Definition: BSTSmartPointer.h:87
constexpr element_type & operator*() const noexcept
Definition: BSTSmartPointer.h:197
BSTSmartPointer & operator=(const BSTSmartPointer &a_rhs)
Definition: BSTSmartPointer.h:113
void reset()
Definition: BSTSmartPointer.h:166
void TryAttach()
Definition: BSTSmartPointer.h:213
void TryDetach()
Definition: BSTSmartPointer.h:220
constexpr BSTSmartPointer(std::nullptr_t) noexcept
Definition: BSTSmartPointer.h:47
element_type * _ptr
Definition: BSTSmartPointer.h:229
constexpr BSTSmartPointer() noexcept
Definition: BSTSmartPointer.h:42
BSTSmartPointer & operator=(BSTSmartPointer< Y > &&a_rhs)
Definition: BSTSmartPointer.h:158
constexpr element_type * operator->() const noexcept
Definition: BSTSmartPointer.h:203
BSTSmartPointer(const BSTSmartPointer &a_rhs)
Definition: BSTSmartPointer.h:66
~BSTSmartPointer()
Definition: BSTSmartPointer.h:107
RefManager< T > reference_manager
Definition: BSTSmartPointer.h:39
BSTSmartPointer(BSTSmartPointer< Y > &&a_rhs) noexcept
Definition: BSTSmartPointer.h:101
T element_type
Definition: BSTSmartPointer.h:38
BSTSmartPointer(Y *a_rhs)
Definition: BSTSmartPointer.h:59
BSTSmartPointer & operator=(const BSTSmartPointer< Y > &a_rhs)
Definition: BSTSmartPointer.h:131
BSTSmartPointer & operator=(BSTSmartPointer &&a_rhs)
Definition: BSTSmartPointer.h:140
constexpr element_type * get() const noexcept
Definition: BSTSmartPointer.h:187
void reset(Y *a_ptr)
Definition: BSTSmartPointer.h:178
Definition: AbsorbEffect.h:6
constexpr bool operator==(const BSTSmartPointer< T1 > &a_lhs, const BSTSmartPointer< T2 > &a_rhs)
Definition: BSTSmartPointer.h:240
BSTSmartPointer(T *) -> BSTSmartPointer< T, BSTSmartPointerIntrusiveRefCount >
BSTSmartPointer< T > make_smart(Args &&... a_args)
Definition: BSTSmartPointer.h:234
constexpr bool operator!=(const BSTSmartPointer< T1 > &a_lhs, const BSTSmartPointer< T2 > &a_rhs)
Definition: BSTSmartPointer.h:246
Definition: BSTSmartPointer.h:23
static void Release(T *a_ptr)
Definition: BSTSmartPointer.h:28
constexpr static void Acquire([[maybe_unused]] T *a_ptr)
Definition: BSTSmartPointer.h:24
Definition: BSTSmartPointer.h:7
static void Release(T *a_ptr)
Definition: BSTSmartPointer.h:13
static void Acquire(T *a_ptr)
Definition: BSTSmartPointer.h:8