NAP
safeptr.h
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4 
5 #pragma once
6 
7 // Std includes
8 #include <set>
9 #include <functional>
10 #include <atomic>
11 
12 // Nap includes
13 #include <utility/dllexport.h>
14 #include <readerwriterqueue.h>
15 
16 namespace nap
17 {
18 
19  namespace audio
20  {
21  // Forward declarations
22  class DeletionQueue;
23 
24  template<typename T>
25  class SafeOwner;
26 
27  template<typename T>
28  class SafePtr;
29 
33  class NAPAPI SafeOwnerBase
34  {
35  friend class DeletionQueue;
36 
37  protected:
38  class Data
39  {
40  public:
41  virtual ~Data() = default;
42  };
43 
44  public:
45  virtual ~SafeOwnerBase() = default;
46 
47  protected:
52  void assign(SafeOwnerBase& source);
53 
54  private:
55  // These methods are internally used by assign() and will be overwritted by SafeOwner<T> to support polymorphism.
56  virtual void* getData() = 0;
57 
58  virtual void setData(void* data) = 0;
59 
60  virtual DeletionQueue* getDeletionQueue() = 0;
61 
62  virtual void setDeletionQueue(DeletionQueue* queue) = 0;
63 
64  virtual void enqueueForDeletion() = 0;
65  };
66 
67 
74  class NAPAPI DeletionQueue final
75  {
76  friend class SafeOwnerBase;
77 
78  public:
79  DeletionQueue() = default;
80 
84  ~DeletionQueue();
85 
90  void enqueue(std::unique_ptr<SafeOwnerBase::Data> ownerData)
91  {
92  mQueue.enqueue(std::move(ownerData));
93  }
94 
99  void clear();
100 
101  private:
102  moodycamel::ReaderWriterQueue<std::unique_ptr<SafeOwnerBase::Data>> mQueue; // Lockfree queue that holds SafeOwner::Data objects to be deleted because the enclosing SafeOwner went out of scope.
103  };
104 
105 
113  template<typename T>
114  class SafeOwner final : public SafeOwnerBase
115  {
116  friend class DeletionQueue;
117 
118  friend class SafePtr<T>;
119 
120  private:
124  class Data : public SafeOwnerBase::Data
125  {
126  public:
127  Data(T* ptr)
128  {
129  mObject = std::unique_ptr<T>(ptr);
130  mSharedSafePtr = std::make_shared<Data*>(this);
131  }
132 
133  ~Data() override
134  {
135  *mSharedSafePtr = nullptr;
136  }
137 
138  public:
139  std::unique_ptr<T> mObject = nullptr;
140  std::shared_ptr<Data*> mSharedSafePtr = nullptr;
141  std::atomic<bool> mEnqueuedForDeletion = { false };
142  };
143 
144  public:
145  SafeOwner() = default;
146 
150  SafeOwner(DeletionQueue& deletionQueue, T* ptr)
151  {
152  mDeletionQueue = &deletionQueue;
153  mData = std::make_unique<Data>(ptr);
154  }
155 
160  {
161  enqueueForDeletion();
162  }
163 
164  // Copy constructor with nullptr
165  SafeOwner(const std::nullptr_t) { }
166 
167  // Assignment operator with nullptr
168  SafeOwner& operator=(const std::nullptr_t)
169  {
170  enqueueForDeletion();
171  return *this;
172  }
173 
174  // Copy and move are not allowed because the SafeOwner (just like unique_ptr) holds ownership
175  SafeOwner(const SafeOwner& other) = delete;
176  SafeOwner& operator=(const SafeOwner& other) = delete;
177 
178  // Move ctor is fine, as unique_ptr's can be moved
179  SafeOwner(SafeOwner<T>&& other) { assign(other); }
180 
181  // Move assignment operator
183  {
184  assign(other);
185  return *this;
186  }
187 
188  // Move constructor with different type
189  template<typename OTHER>
190  SafeOwner(SafeOwner<OTHER>&& other) { assign(other); }
191 
192  // Move assignment operator with different type
193  template<typename OTHER>
195  {
196  assign(other);
197  return *this;
198  }
199 
200  const T& operator*() const
201  {
202  assert(mData != nullptr);
203  return *static_cast<T*>(mData->mObject.get());
204  }
205 
207  {
208  assert(mData != nullptr);
209  return *static_cast<T*>(mData->mObject.get());
210  }
211 
212  T* operator->() const
213  {
214  assert(mData != nullptr);
215  return static_cast<T*>(mData->mObject.get());
216  }
217 
219  {
220  assert(mData != nullptr);
221  return static_cast<T*>(mData->mObject.get());
222  }
223 
224  template<typename OTHER>
225  bool operator==(const OTHER* ptr) const
226  {
227 
228  return ptr ? mData->mObject.get() == ptr : mData == nullptr;
229  }
230 
231  template<typename OTHER>
232  bool operator!=(const OTHER* ptr) const
233  {
234  return ptr ? mData->mObject.get() != ptr : mData != nullptr;
235  }
236 
237  bool operator==(const std::nullptr_t) const
238  {
239  return mData == nullptr;
240  }
241 
242  bool operator!=(const std::nullptr_t) const
243  {
244  return mData != nullptr;
245  }
246 
251  {
252  auto safePtr = SafePtr<T>(*this);
253  return std::move(safePtr);
254  }
255 
259  SafePtr<T> get() const
260  {
261  auto safePtr = SafePtr<T>(*this);
262  return std::move(safePtr);
263  }
264 
268  T* getRaw() { return mData->mObject.get(); }
269 
273  T* getRaw() const { return mData->mObject.get(); }
274 
275  protected:
276  // Inherited from SafeOwnerBase for polymorphism support
277  void* getData() override { return mData.release(); }
278 
279  void setData(void* data) override { mData = std::unique_ptr<Data>(static_cast<Data*>(data)); }
280 
281  DeletionQueue* getDeletionQueue() override { return mDeletionQueue; }
282 
283  void setDeletionQueue(DeletionQueue* queue) override { mDeletionQueue = queue; }
284 
285  private:
289  void enqueueForDeletion() override
290  {
291  if (mData != nullptr) {
292  assert(mDeletionQueue != nullptr);
293  mData->mEnqueuedForDeletion = true;
294  mDeletionQueue->enqueue(std::move(mData));
295  mDeletionQueue = nullptr;
296  mData = nullptr;
297  }
298  }
299 
300  std::unique_ptr<Data> mData = nullptr;
301  DeletionQueue* mDeletionQueue = nullptr;
302  };
303 
304 
308  class NAPAPI SafePtrBase
309  {
310  public:
311  virtual ~SafePtrBase() = default;
312 
313  protected:
314  void assign(const SafePtrBase& other)
315  {
316  setOwnerData(other.getOwnerData());
317  }
318 
319  private:
320  // These methods are internally used by assign() in order to support polymorphism.
321  virtual void* getOwnerData() const = 0;
322 
323  virtual void setOwnerData(void* ownerData) = 0;
324  };
325 
326 
330  template<typename T>
331  class SafePtr final : public SafePtrBase
332  {
333  friend class SafeOwner<T>;
334 
335  friend class DeletionQueue;
336 
337  public:
338  SafePtr() = default;
339 
344  {
345  mOwnerData = owner.mData->mSharedSafePtr;
346  }
347 
352  {
353  }
354 
355  // Copy ctor
356  SafePtr(const SafePtr<T>& other)
357  {
358  assign(other);
359  }
360 
361  // Assignment operator
362  SafePtr& operator=(const SafePtr<T>& other)
363  {
364  assign(other);
365  return *this;
366  }
367 
368  // Copy ctor with different type
369  template<typename OTHER>
370  SafePtr(const SafePtr<OTHER>& other)
371  {
372  assign(other);
373  }
374 
375  // Assignment operator with different type
376  template<typename OTHER>
378  {
379  assign(other);
380  return *this;
381  }
382 
383  // Copy ctor with nullptr
384  SafePtr(const std::nullptr_t)
385  {}
386 
387  // Assignment operator with nullptr
388  SafePtr& operator=(const std::nullptr_t)
389  {
390  mOwnerData = nullptr;
391  return *this;
392  }
393 
394  // Move ctor
396  {
397  assign(other);
398  }
399 
400  // Move assignment operator
402  {
403  assign(other);
404  return *this;
405  }
406 
407  // Move ctor with different type
408  template<typename OTHER>
410  {
411  assign(other);
412  }
413 
414  // Move assignment operator with different type
415  template<typename OTHER>
417  {
418  assign(other);
419  return *this;
420  }
421 
422  const T& operator*() const
423  {
424  assert(isValid());
425  return *static_cast<T*>((*mOwnerData)->mObject.get());
426  }
427 
429  {
430  assert(isValid());
431  return *static_cast<T*>((*mOwnerData)->mObject.get());
432  }
433 
434  T* operator->() const
435  {
436  assert(isValid());
437  return static_cast<T*>((*mOwnerData)->mObject.get());
438  }
439 
441  {
442  assert(isValid());
443  return static_cast<T*>((*mOwnerData)->mObject.get());
444  }
445 
446  template<typename OTHER>
447  bool operator==(const OTHER* ptr) const
448  {
449  return ptr ? isValid() && (*mOwnerData)->mObject.get() == ptr : !isValid();
450  }
451 
452  template<typename OTHER>
453  bool operator!=(const OTHER* ptr) const
454  {
455  return ptr ? isValid() && (*mOwnerData)->mObject.get() != ptr : !isValid();
456  }
457 
458  bool operator==(const std::nullptr_t) const
459  {
460  return !isValid() || (*mOwnerData)->mEnqueuedForDeletion == true;
461  }
462 
463  bool operator!=(const std::nullptr_t) const
464  {
465  return isValid() && (*mOwnerData)->mEnqueuedForDeletion == false;
466  }
467 
468  T* get() const
469  {
470  assert(isValid());
471  return static_cast<T*>((*mOwnerData)->mObject.get());
472  }
473 
474  T* get()
475  {
476  assert(isValid());
477  return static_cast<T*>((*mOwnerData)->mObject.get());
478  }
479 
480  private:
481  void* getOwnerData() const override
482  { return *mOwnerData; }
483 
484  void setOwnerData(void* ownerData) override
485  {
486  if (ownerData == nullptr)
487  mOwnerData = nullptr;
488  else
489  // Update the target data
490  mOwnerData = static_cast<typename SafeOwner<T>::Data*>(ownerData)->mSharedSafePtr;
491  }
492 
493  bool isValid() const
494  {
495  return (mOwnerData != nullptr) && (*mOwnerData != nullptr);
496  }
497 
498  std::shared_ptr<typename SafeOwner<T>::Data*> mOwnerData = nullptr;
499  };
500 
501 
502  }
503 
504 }
505 
nap::audio::SafeOwner::getRaw
T * getRaw() const
Definition: safeptr.h:273
nap::audio::SafeOwner::setData
void setData(void *data) override
Definition: safeptr.h:279
nap::audio::SafePtr::operator=
SafePtr< T > & operator=(SafePtr< OTHER > &&other)
Definition: safeptr.h:416
nap::audio::SafeOwner::get
SafePtr< T > get()
Definition: safeptr.h:250
nap::audio::SafePtrBase
Definition: safeptr.h:308
nap::audio::SafeOwner::operator=
SafeOwner & operator=(const std::nullptr_t)
Definition: safeptr.h:168
nap::audio::DeletionQueue
Definition: safeptr.h:74
nap::audio::SafePtr::SafePtr
SafePtr(SafePtr< OTHER > &&other)
Definition: safeptr.h:409
nap::audio::SafePtr::SafePtr
SafePtr(SafePtr< T > &&other)
Definition: safeptr.h:395
nap::audio::SafePtr::operator!=
bool operator!=(const std::nullptr_t) const
Definition: safeptr.h:463
nap::audio::SafePtr::operator=
SafePtr & operator=(const SafePtr< T > &other)
Definition: safeptr.h:362
nap::audio::SafePtr::operator==
bool operator==(const std::nullptr_t) const
Definition: safeptr.h:458
nap::audio::SafePtr::SafePtr
SafePtr(const SafePtr< T > &other)
Definition: safeptr.h:356
nap::audio::SafeOwner::SafeOwner
SafeOwner()=default
nap::audio::SafeOwnerBase::Data
Definition: safeptr.h:38
nap::audio::SafeOwner::~SafeOwner
~SafeOwner()
Definition: safeptr.h:159
nap::audio::SafePtr::SafePtr
SafePtr(const std::nullptr_t)
Definition: safeptr.h:384
nap::audio::SafePtr::operator=
SafePtr & operator=(const SafePtr< OTHER > &other)
Definition: safeptr.h:377
nap::audio::SafePtrBase::assign
void assign(const SafePtrBase &other)
Definition: safeptr.h:314
nap::audio::SafePtr::get
T * get() const
Definition: safeptr.h:468
nap::audio::DeletionQueue::enqueue
void enqueue(std::unique_ptr< SafeOwnerBase::Data > ownerData)
Definition: safeptr.h:90
nap::audio::SafePtr::operator*
T & operator*()
Definition: safeptr.h:428
nap::audio::SafeOwner::getRaw
T * getRaw()
Definition: safeptr.h:268
nap::audio::SafePtr::operator==
bool operator==(const OTHER *ptr) const
Definition: safeptr.h:447
nap::audio::SafeOwner::operator*
const T & operator*() const
Definition: safeptr.h:200
nap::audio::SafePtr::operator=
SafePtr & operator=(const std::nullptr_t)
Definition: safeptr.h:388
nap::audio::SafeOwner::operator=
SafeOwner< T > & operator=(SafeOwner< T > &&other)
Definition: safeptr.h:182
nap::audio::SafeOwner::SafeOwner
SafeOwner(const std::nullptr_t)
Definition: safeptr.h:165
nap::audio::SafeOwner::operator==
bool operator==(const OTHER *ptr) const
Definition: safeptr.h:225
nap::audio::SafeOwnerBase
Definition: safeptr.h:33
nap::audio::SafeOwner
Definition: safeptr.h:25
nap::audio::SafeOwner::setDeletionQueue
void setDeletionQueue(DeletionQueue *queue) override
Definition: safeptr.h:283
nap::audio::SafeOwner::SafeOwner
SafeOwner(SafeOwner< T > &&other)
Definition: safeptr.h:179
nap::audio::SafeOwner::operator!=
bool operator!=(const std::nullptr_t) const
Definition: safeptr.h:242
nap::audio::SafePtr::operator->
T * operator->() const
Definition: safeptr.h:434
nap::audio::SafeOwner::SafeOwner
SafeOwner(SafeOwner< OTHER > &&other)
Definition: safeptr.h:190
nap::audio::SafePtr::SafePtr
SafePtr(SafeOwner< T > &owner)
Definition: safeptr.h:343
nap::audio::SafeOwner::operator==
bool operator==(const std::nullptr_t) const
Definition: safeptr.h:237
nap::audio::SafeOwner::operator->
T * operator->()
Definition: safeptr.h:218
nap::audio::SafePtr::SafePtr
SafePtr()=default
nap::audio::SafeOwner::SafePtr< T >
friend class SafePtr< T >
Definition: safeptr.h:118
nap::audio::SafeOwner::SafeOwner
SafeOwner(DeletionQueue &deletionQueue, T *ptr)
Definition: safeptr.h:150
nap::audio::SafeOwner::operator*
T & operator*()
Definition: safeptr.h:206
nap
Definition: templateapp.h:17
nap::audio::SafePtr::operator!=
bool operator!=(const OTHER *ptr) const
Definition: safeptr.h:453
nap::audio::SafePtr::operator->
T * operator->()
Definition: safeptr.h:440
nap::audio::SafePtr::get
T * get()
Definition: safeptr.h:474
nap::audio::SafePtr::operator*
const T & operator*() const
Definition: safeptr.h:422
nap::audio::SafeOwner::operator!=
bool operator!=(const OTHER *ptr) const
Definition: safeptr.h:232
nap::audio::SafeOwner::DeletionQueue
friend class DeletionQueue
Definition: safeptr.h:116
nap::audio::SafeOwner::getDeletionQueue
DeletionQueue * getDeletionQueue() override
Definition: safeptr.h:281
nap::audio::SafeOwner::operator=
SafeOwner< T > & operator=(SafeOwner< OTHER > &&other)
Definition: safeptr.h:194
nap::audio::SafeOwner::get
SafePtr< T > get() const
Definition: safeptr.h:259
nap::audio::SafeOwner::operator->
T * operator->() const
Definition: safeptr.h:212
nap::audio::SafePtr::SafePtr
SafePtr(const SafePtr< OTHER > &other)
Definition: safeptr.h:370
nap::audio::SafePtr::operator=
SafePtr< T > & operator=(SafePtr< T > &&other)
Definition: safeptr.h:401
nap::audio::SafePtr
Definition: safeptr.h:28
nap::audio::SafePtr::~SafePtr
~SafePtr()
Definition: safeptr.h:351
nap::audio::SafeOwner::getData
void * getData() override
Definition: safeptr.h:277