Polyphase Game Engine
Loading...
Searching...
No Matches
SmartPointer.h
Go to the documentation of this file.
1#pragma once
2
3#include <vector>
4#include <type_traits>
5#include <stdint.h>
6#include "Assertion.h"
7#include "PolyphaseAPI.h"
8
9class Node;
10
13
14// Detect Node-derived types without requiring Node to be complete.
15template<typename U, typename = void>
16struct IsNodeType : std::false_type {};
17
18template<typename U>
19struct IsNodeType<U, std::void_t<decltype(std::declval<U>().IsDestroyed())>> : std::true_type {};
20
21template<typename T>
23{
24 typedef void(*DeleterFP)(T*);
25
26 int32_t mSharedCount = 0;
27 int32_t mWeakCount = 0;
29};
30
31template<typename T>
33{
34public:
35
37 {
38
39 }
40
42 {
43 Set(src.mPointer, src.mRefCount);
44 }
45
47 {
48 mPointer = src.mPointer;
49 mRefCount = src.mRefCount;
50
51 src.mPointer = nullptr;
52 src.mRefCount = nullptr;
53 }
54
55 SharedPtr(std::nullptr_t)
56 {
57 Clear();
58 }
59
61 {
62 Clear();
63 }
64
66 {
67 Set(src.mPointer, src.mRefCount);
68 return *this;
69 }
70
72 {
73 Clear();
74
75 mPointer = src.mPointer;
76 mRefCount = src.mRefCount;
77
78 src.mPointer = nullptr;
79 src.mRefCount = nullptr;
80
81 return *this;
82 }
83
84 SharedPtr<T>& operator=(std::nullptr_t)
85 {
86 Clear();
87 return *this;
88 }
89
90 bool operator==(const SharedPtr& other) const
91 {
92 return Get() == other.Get();
93 }
94
95 bool operator!=(const SharedPtr& other) const
96 {
97 return !operator==(other);
98 }
99
100 bool operator==(const T* other) const
101 {
102 return Get() == other;
103 }
104
105 bool operator!=(const T* other) const
106 {
107 return !operator==(other);
108 }
109
110 T* operator->() const
111 {
112 return mPointer;
113 }
114
115 T& operator*() const
116 {
117 return *mPointer;
118 }
119
120 operator bool() const
121 {
122 return IsValid();
123 }
124
125 void SetCommon(T* pointer, RefCount<T>* refCount)
126 {
127 if (mPointer != pointer)
128 {
129 // If we have a pointer, we must have a refcount
130 // If we have no pointer, then we shouldn't have a refcount
131 OCT_ASSERT((mPointer != nullptr) == (mRefCount != nullptr));
132
133 Clear();
134
135 mPointer = pointer;
136 mRefCount = refCount;
137
138 if (mPointer != nullptr && mRefCount == nullptr)
139 {
140 // Initialize ref count
141 mRefCount = new RefCount<T>();
142 }
143
144 if (mRefCount != nullptr)
145 {
146 mRefCount->mSharedCount++;
147 }
148 }
149 else
150 {
151 // Two shared pointers initialized independently to same pointer?
152 OCT_ASSERT(mRefCount == refCount);
153 }
154 }
155
156 void Set(T* pointer, RefCount<T>* refCount)
157 {
158 bool diffPointer = (mPointer != pointer);
159
160 SetCommon(pointer, refCount);
161
162 if constexpr (IsNodeType<T>::value)
163 {
164 if (diffPointer &&
165 mPointer != nullptr &&
166 mRefCount != nullptr &&
167 mRefCount->mSharedCount == 2)
168 {
169 Node* node = (Node*)mPointer;
171 }
172 }
173 }
174
176 {
177 if (mPointer != nullptr)
178 {
179 OCT_ASSERT(mRefCount);
180 OCT_ASSERT(mRefCount->mSharedCount > 0);
181 mRefCount->mSharedCount--;
182
183 if (mRefCount->mSharedCount <= 0)
184 {
185 // In the case where Node maintains a weak pointer to itself,
186 // it's possible that deleting the pointer will trigger a weak
187 // pointer cleanup which will destroy the mRefCount data.
188 // So temporarily up the weak count so that doesn't happen.
189 mRefCount->mWeakCount++;
190
191 if (mRefCount->mDeleter)
192 {
193 mRefCount->mDeleter(mPointer);
194 }
195
196 delete mPointer;
197
198 mRefCount->mWeakCount--;
199 }
200
201 if (mRefCount->mSharedCount <= 0 &&
202 mRefCount->mWeakCount <= 0)
203 {
204 delete mRefCount;
205 }
206
207 mPointer = nullptr;
208 mRefCount = nullptr;
209 }
210 else
211 {
212 // If we have no assigned pointer, we should have no ref count.
213 OCT_ASSERT(mRefCount == nullptr);
214 }
215 }
216
217 void Clear()
218 {
219 if constexpr (IsNodeType<T>::value)
220 {
221 Node* node = (Node*)mPointer;
222
223 if (node != nullptr &&
224 mRefCount != nullptr &&
225 mRefCount->mSharedCount == 2)
226 {
228 }
229 }
230
231 ClearCommon();
232 }
233
234 void SetDeleter(typename RefCount<T>::DeleterFP deleteFunc)
235 {
236 if (IsValid())
237 {
238 mRefCount->mDeleter = deleteFunc;
239 }
240 }
241
242 void Reset()
243 {
244 Clear();
245 }
246
247 T* Get() const
248 {
249 return mPointer;
250 }
251
252 T*& GetRef()
253 {
254 return mPointer;
255 }
256
258 {
259 return mRefCount;
260 }
261
262 int32_t GetUseCount() const
263 {
264 return mRefCount ? mRefCount->mSharedCount : 0;
265 }
266
267 int32_t GetSharedCount() const
268 {
269 return GetUseCount();
270 }
271
272 int32_t GetWeakCount() const
273 {
274 return mRefCount ? mRefCount->mWeakCount : 0;
275 }
276
277 const T* GetPointerRaw() const
278 {
279 return mPointer;
280 }
281
282 // For getting a subclass. T must inherit from Object.
283 template<typename S>
284 S* Get() const
285 {
286 OCT_ASSERT(!mPointer || mPointer->Is(S::ClassRuntimeId()));
287 return static_cast<S*>(Get());
288 }
289
290public:
291
292 bool IsValid() const
293 {
294 if constexpr (IsNodeType<T>::value)
295 {
296 return (mPointer != nullptr && mRefCount != nullptr && !mPointer->IsDestroyed());
297 }
298 else
299 {
300 return (mPointer != nullptr && mRefCount != nullptr);
301 }
302 }
303
304private:
305
306 T* mPointer = nullptr;
307 RefCount<T>* mRefCount = nullptr;
308};
309
310template<typename T>
312{
313public:
315 {
316
317 }
318
319 WeakPtr(const WeakPtr<T>& src)
320 {
321 if (src.IsValid())
322 {
323 Set(src.mPointer, src.mRefCount);
324 }
325 }
326
328 {
329 Set(src.Get(), src.GetRefCount());
330 }
331
332 WeakPtr(std::nullptr_t)
333 {
334 Clear();
335 }
336
338 {
339 mPointer = src.mPointer;
340 mRefCount = src.mRefCount;
341
342 src.mPointer = nullptr;
343 src.mRefCount = nullptr;
344 }
345
347 {
348 Clear();
349 }
350
352 {
353 if (src.IsValid())
354 {
355 Set(src.mPointer, src.mRefCount);
356 }
357 else
358 {
359 Clear();
360 }
361
362 return *this;
363 }
364
366 {
367 Set(src.Get(), src.GetRefCount());
368 return *this;
369 }
370
371 WeakPtr<T>& operator=(std::nullptr_t)
372 {
373 Clear();
374 return *this;
375 }
376
378 {
379 Clear();
380
381 mPointer = src.mPointer;
382 mRefCount = src.mRefCount;
383
384 src.mPointer = nullptr;
385 src.mRefCount = nullptr;
386
387 return *this;
388 }
389
390 bool operator==(const SharedPtr<T>& other) const
391 {
392 return Get() == other.Get();
393 }
394
395 bool operator!=(const SharedPtr<T>& other) const
396 {
397 return !operator==(other);
398 }
399
400 bool operator==(const WeakPtr<T>& other) const
401 {
402 return Get() == other.Get();
403 }
404
405 bool operator!=(const WeakPtr<T>& other) const
406 {
407 return !operator==(other);
408 }
409
410 bool operator==(const T* other) const
411 {
412 return Get() == other;
413 }
414
415 bool operator!=(const T* other) const
416 {
417 return !operator==(other);
418 }
419
420 T* operator->() const
421 {
422 return mPointer;
423 }
424
425 T& operator*() const
426 {
427 return *mPointer;
428 }
429
430 operator bool() const
431 {
432 return IsValid();
433 }
434
435 void Set(T* pointer, RefCount<T>* refCount)
436 {
437 // We must always receive a valid refcount if given a valid pointer.
438 OCT_ASSERT((pointer != nullptr) == (refCount != nullptr));
439
440 if (!IsValid())
441 {
442 Clear();
443 }
444
445 if (mPointer != pointer)
446 {
447 // If we have a pointer, we must have a refcount
448 // If we have no pointer, then we shouldn't have a refcount
449 OCT_ASSERT((mPointer != nullptr) == (mRefCount != nullptr));
450
451 Clear();
452
453 mPointer = pointer;
454 mRefCount = refCount;
455
456 if (mRefCount != nullptr)
457 {
458 mRefCount->mWeakCount++;
459 }
460 }
461 else
462 {
463 // Two shared pointers initialized independently to same pointer?
464 OCT_ASSERT(mRefCount == refCount);
465 }
466 }
467
468 void Clear()
469 {
470 if (mPointer != nullptr)
471 {
472 OCT_ASSERT(mRefCount);
473 OCT_ASSERT(mRefCount->mWeakCount > 0);
474 mRefCount->mWeakCount--;
475
476 if (mRefCount->mSharedCount <= 0 &&
477 mRefCount->mWeakCount <= 0)
478 {
479 delete mRefCount;
480 }
481
482 mPointer = nullptr;
483 mRefCount = nullptr;
484 }
485 else
486 {
487 // If we have no assigned pointer, we should have no ref count.
488 OCT_ASSERT(mRefCount == nullptr);
489 }
490 }
491
493 {
494 SharedPtr<T> ret;
495
496 if (IsValid())
497 {
498 ret.Set(mPointer, mRefCount);
499 }
500
501 return ret;
502 }
503
504 bool IsValid() const
505 {
506 if constexpr (IsNodeType<T>::value)
507 {
508 return (mPointer != nullptr && mRefCount != nullptr && mRefCount->mSharedCount > 0 && !mPointer->IsDestroyed());
509 }
510 else
511 {
512 return (mPointer != nullptr && mRefCount != nullptr && mRefCount->mSharedCount > 0);
513 }
514 }
515
516 void Reset()
517 {
518 Clear();
519 }
520
521 T* Get() const
522 {
523 return IsValid() ? mPointer : nullptr;
524 }
525
526 T*& GetRef()
527 {
528 return IsValid() ? mPointer : nullptr;
529 }
530
532 {
533 return mRefCount;
534 }
535
536 int32_t GetUseCount() const
537 {
538 return mRefCount ? mRefCount->mSharedCount : 0;
539 }
540
541 int32_t GetSharedCount() const
542 {
543 return GetUseCount();
544 }
545
546 int32_t GetWeakCount() const
547 {
548 return mRefCount ? mRefCount->mWeakCount : 0;
549 }
550
551 const T* GetPointerRaw() const
552 {
553 return mPointer;
554 }
555
556 // For getting a subclass. T must inherit from Object.
557 template<typename S>
558 S* Get() const
559 {
560 if (!IsValid())
561 {
562 return nullptr;
563 }
564
565 OCT_ASSERT(!mPointer || mPointer->Is(S::ClassRuntimeId()));
566 return static_cast<S*>(Get());
567 }
568
569private:
570
571 T* mPointer = nullptr;
572 RefCount<T>* mRefCount = nullptr;
573};
574
575// TODO: Perfect forwarding
576template<typename T>
578{
579 SharedPtr<T> ret;
580 T* newPtr = new T();
581 ret.Set(newPtr, nullptr);
582 return ret;
583}
584
585template<typename T, typename U>
587{
588 T* pointer = static_cast<T*>(src.Get());
589 SharedPtr<T> dst;
590 dst.Set(pointer, (RefCount<T>*)src.GetRefCount());
591 return dst;
592}
593
594template<typename T, typename U>
596{
597 return PtrStaticCast<T>(src.Lock());
598}
599
600template<typename T, typename U>
602{
603 U* srcPointer = src.Get();
604 T* dstPointer = nullptr;
605
606 if (srcPointer)
607 {
608 dstPointer = srcPointer->template As<T>();
609 }
610
611 if (dstPointer)
612 {
613 SharedPtr<T> dst;
614 dst.Set(dstPointer, (RefCount<T>*)src.GetRefCount());
615 return dst;
616 }
617
618 return SharedPtr<T>();
619}
620
621template<typename T, typename U>
623{
624 return PtrDynamicCast<T>(src.Lock());
625}
626
629
630namespace std
631{
632 template<typename T>
633 struct hash<SharedPtr<T> >
634 {
635 size_t operator()(const SharedPtr<T>& k) const
636 {
637 return std::hash<const T*>{}(k.GetPointerRaw());
638 }
639 };
640
641 template<typename T>
642 struct hash<WeakPtr<T> >
643 {
644 size_t operator()(const WeakPtr<T>& k) const
645 {
646 return std::hash<const T*>{}(k.GetPointerRaw());
647 }
648 };
649}
#define OCT_ASSERT(expr)
Definition Assertion.h:12
Export macros for Polyphase Engine symbols.
#define POLYPHASE_API
Definition PolyphaseAPI.h:31
POLYPHASE_API void MakeNodeUserdataStrong(Node *node)
Definition SmartPointer.cpp:7
SharedPtr< T > MakeShared()
Definition SmartPointer.h:577
SharedPtr< Node > NodePtr
Definition SmartPointer.h:627
SharedPtr< T > PtrDynamicCast(const SharedPtr< U > &src)
Definition SmartPointer.h:601
POLYPHASE_API void MakeNodeUserdataWeak(Node *node)
Definition SmartPointer.cpp:52
SharedPtr< T > PtrStaticCast(const SharedPtr< U > &src)
Definition SmartPointer.h:586
WeakPtr< Node > NodePtrWeak
Definition SmartPointer.h:628
Definition Node.h:67
Definition SmartPointer.h:33
SharedPtr< T > & operator=(std::nullptr_t)
Definition SmartPointer.h:84
int32_t GetSharedCount() const
Definition SmartPointer.h:267
int32_t GetWeakCount() const
Definition SmartPointer.h:272
void ClearCommon()
Definition SmartPointer.h:175
void SetDeleter(typename RefCount< T >::DeleterFP deleteFunc)
Definition SmartPointer.h:234
SharedPtr(const SharedPtr< T > &src)
Definition SmartPointer.h:41
SharedPtr< T > & operator=(const SharedPtr< T > &src)
Definition SmartPointer.h:65
bool IsValid() const
Definition SmartPointer.h:292
SharedPtr< T > & operator=(SharedPtr< T > &&src)
Definition SmartPointer.h:71
SharedPtr(SharedPtr< T > &&src)
Definition SmartPointer.h:46
SharedPtr(std::nullptr_t)
Definition SmartPointer.h:55
int32_t GetUseCount() const
Definition SmartPointer.h:262
SharedPtr()
Definition SmartPointer.h:36
T *& GetRef()
Definition SmartPointer.h:252
void Set(T *pointer, RefCount< T > *refCount)
Definition SmartPointer.h:156
bool operator==(const SharedPtr &other) const
Definition SmartPointer.h:90
T * Get() const
Definition SmartPointer.h:247
T & operator*() const
Definition SmartPointer.h:115
void Clear()
Definition SmartPointer.h:217
RefCount< T > * GetRefCount() const
Definition SmartPointer.h:257
bool operator==(const T *other) const
Definition SmartPointer.h:100
const T * GetPointerRaw() const
Definition SmartPointer.h:277
bool operator!=(const T *other) const
Definition SmartPointer.h:105
void SetCommon(T *pointer, RefCount< T > *refCount)
Definition SmartPointer.h:125
~SharedPtr()
Definition SmartPointer.h:60
bool operator!=(const SharedPtr &other) const
Definition SmartPointer.h:95
T * operator->() const
Definition SmartPointer.h:110
S * Get() const
Definition SmartPointer.h:284
void Reset()
Definition SmartPointer.h:242
Definition SmartPointer.h:312
T * operator->() const
Definition SmartPointer.h:420
bool operator==(const SharedPtr< T > &other) const
Definition SmartPointer.h:390
void Reset()
Definition SmartPointer.h:516
RefCount< T > * GetRefCount() const
Definition SmartPointer.h:531
SharedPtr< T > Lock() const
Definition SmartPointer.h:492
T & operator*() const
Definition SmartPointer.h:425
bool operator!=(const WeakPtr< T > &other) const
Definition SmartPointer.h:405
~WeakPtr()
Definition SmartPointer.h:346
const T * GetPointerRaw() const
Definition SmartPointer.h:551
T *& GetRef()
Definition SmartPointer.h:526
WeakPtr(WeakPtr< T > &&src)
Definition SmartPointer.h:337
WeakPtr(const WeakPtr< T > &src)
Definition SmartPointer.h:319
int32_t GetWeakCount() const
Definition SmartPointer.h:546
WeakPtr< T > & operator=(WeakPtr< T > &&src)
Definition SmartPointer.h:377
WeakPtr()
Definition SmartPointer.h:314
WeakPtr(std::nullptr_t)
Definition SmartPointer.h:332
S * Get() const
Definition SmartPointer.h:558
T * Get() const
Definition SmartPointer.h:521
int32_t GetSharedCount() const
Definition SmartPointer.h:541
WeakPtr< T > & operator=(const WeakPtr< T > &src)
Definition SmartPointer.h:351
bool operator!=(const T *other) const
Definition SmartPointer.h:415
bool operator==(const WeakPtr< T > &other) const
Definition SmartPointer.h:400
WeakPtr< T > & operator=(std::nullptr_t)
Definition SmartPointer.h:371
WeakPtr(const SharedPtr< T > &src)
Definition SmartPointer.h:327
bool operator==(const T *other) const
Definition SmartPointer.h:410
bool operator!=(const SharedPtr< T > &other) const
Definition SmartPointer.h:395
int32_t GetUseCount() const
Definition SmartPointer.h:536
WeakPtr< T > & operator=(const SharedPtr< T > &src)
Definition SmartPointer.h:365
bool IsValid() const
Definition SmartPointer.h:504
void Clear()
Definition SmartPointer.h:468
void Set(T *pointer, RefCount< T > *refCount)
Definition SmartPointer.h:435
Definition SmartPointer.h:631
Definition SmartPointer.h:16
Definition SmartPointer.h:23
void(* DeleterFP)(T *)
Definition SmartPointer.h:24
int32_t mWeakCount
Definition SmartPointer.h:27
DeleterFP mDeleter
Definition SmartPointer.h:28
int32_t mSharedCount
Definition SmartPointer.h:26