aboutsummaryrefslogtreecommitdiff
path: root/ProjectBrussel/Common/RcPtr.hpp
blob: 130b2b2439a7d2ed841e6070a558dfd72f2c72d9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#pragma once

#include "Macros.hpp"
#include "TypeTraits.hpp"

#include <cstddef>
#include <cstdint>
#include <optional>
#include <type_traits>

class RefCounted {
public:
	// DO NOT MODIFY this field, unless explicitly documented the use
	uint32_t refCount = 0;
	uint32_t weakCount = 0; // TODO implement
};

template <class T, class TDeleter = DefaultDeleter<T>>
class RcPtr : TDeleter {
private:
	static_assert(std::is_base_of_v<RefCounted, T>);
	T* mPtr;

public:
	RcPtr()
		: mPtr{ nullptr } {
	}

	explicit RcPtr(T* ptr)
		: mPtr{ ptr } {
		if (ptr) {
			++ptr->RefCounted::refCount;
		}
	}

	~RcPtr() {
		CleanUp();
	}

	void Attach(T* ptr) {
		CleanUp();
		mPtr = ptr;
		if (ptr) {
			++ptr->RefCounted::refCount;
		}
	}

	void Detatch() {
		CleanUp();
		mPtr = nullptr;
	}

	RcPtr(const RcPtr& that)
		: mPtr{ that.mPtr } {
		if (mPtr) {
			++mPtr->RefCounted::refCount;
		}
	}

	RcPtr& operator=(const RcPtr& that) {
		CleanUp();
		mPtr = that.mPtr;
		if (mPtr) {
			++mPtr->RefCounted::refCount;
		}
		return *this;
	}

	RcPtr(RcPtr&& that)
		: mPtr{ that.mPtr } {
		that.mPtr = nullptr;
	}

	RcPtr& operator=(RcPtr&& that) {
		CleanUp();
		mPtr = that.mPtr;
		that.mPtr = nullptr;
		return *this;
	}

	template <class TBase>
	requires std::is_base_of_v<TBase, T>
	operator RcPtr<TBase>() const {
		return RcPtr<TBase>(mPtr);
	}

	bool operator==(std::nullptr_t ptr) const {
		return mPtr == nullptr;
	}

	bool operator==(const T* ptr) const {
		return mPtr == ptr;
	}

	bool operator==(T* ptr) const {
		return mPtr == ptr;
	}

	template <class TThat>
	bool operator==(const RcPtr<TThat>& ptr) const {
		return mPtr == ptr.Get();
	}

	T* Get() const {
		return mPtr;
	}

	T& operator*() const { return *mPtr; }
	T* operator->() const { return mPtr; }

private:
	void CleanUp() {
		if (mPtr) {
			--mPtr->RefCounted::refCount;
			if (mPtr->RefCounted::refCount == 0) {
				TDeleter::operator()(mPtr);
			}
		}
	}
};