1 | //************************************ bs::framework - Copyright 2018-2019 Marko Pintera **************************************//
|
2 | //*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
|
3 | #pragma once
|
4 |
|
5 | #include "Prerequisites/BsPrerequisitesUtil.h"
|
6 |
|
7 | namespace bs
|
8 | {
|
9 | /** @addtogroup General
|
10 | * @{
|
11 | */
|
12 |
|
13 | /** Unsafe smart pointer that does not support use across multiple threads, but comes with less overhead. */
|
14 | template <class T>
|
15 | class USPtr
|
16 | {
|
17 | public:
|
18 | USPtr() = default;
|
19 | USPtr(nullptr_t) { }
|
20 |
|
21 | explicit USPtr(T* ptr)
|
22 | : mPtr(ptr)
|
23 | {
|
24 | add();
|
25 | }
|
26 |
|
27 | USPtr(const USPtr& ptr)
|
28 | : mPtr(ptr.mPtr), mCounter(ptr.mCounter)
|
29 | {
|
30 | add();
|
31 | }
|
32 |
|
33 | template <typename U>
|
34 | USPtr(const USPtr<U>& ptr)
|
35 | : mPtr(static_cast<T*>(ptr.mPtr)), mCounter(ptr.mCounter)
|
36 | {
|
37 | add();
|
38 | }
|
39 |
|
40 | ~USPtr()
|
41 | {
|
42 | release();
|
43 | }
|
44 |
|
45 | USPtr& operator= (const USPtr& ptr)
|
46 | {
|
47 | release();
|
48 |
|
49 | mPtr = ptr.mPtr;
|
50 | mCounter = ptr.mCounter;
|
51 |
|
52 | add();
|
53 |
|
54 | return *this;
|
55 | }
|
56 |
|
57 | void reset()
|
58 | {
|
59 | release();
|
60 | }
|
61 |
|
62 | void reset(T* ptr)
|
63 | {
|
64 | assert(ptr == nullptr || (ptr != mPtr));
|
65 |
|
66 | release();
|
67 |
|
68 | mPtr = ptr;
|
69 | mCounter = nullptr;
|
70 |
|
71 | add();
|
72 | }
|
73 |
|
74 | void swap(USPtr& rhs)
|
75 | {
|
76 | std::swap(mPtr, rhs.mPtr);
|
77 | std::swap(mCounter, rhs.mCounter);
|
78 | }
|
79 |
|
80 | T& operator*() const
|
81 | {
|
82 | assert(mPtr != nullptr);
|
83 | return *mPtr;
|
84 | }
|
85 |
|
86 | T* operator->() const
|
87 | {
|
88 | assert(mPtr != nullptr);
|
89 | return mPtr;
|
90 | }
|
91 |
|
92 | operator bool() const { return mCounter != nullptr && *mCounter > 0; }
|
93 | bool unique() const { return mCounter != nullptr && *mCounter == 1; }
|
94 | uint32_t useCount() const { return mCounter == nullptr ? 0 : *mCounter; }
|
95 | T* get() const { return mPtr; }
|
96 |
|
97 | private:
|
98 | template<class U>
|
99 | friend class USPtr;
|
100 |
|
101 | void add()
|
102 | {
|
103 | if (mPtr != nullptr)
|
104 | {
|
105 | if (mCounter == nullptr)
|
106 | mCounter = bs_new<uint32_t>(1);
|
107 | else
|
108 | ++(*mCounter);
|
109 | }
|
110 | }
|
111 |
|
112 | void release()
|
113 | {
|
114 | if (mCounter != nullptr)
|
115 | {
|
116 | --(*mCounter);
|
117 | if (*mCounter == 0)
|
118 | {
|
119 | bs_delete(mPtr);
|
120 | bs_delete(mCounter);
|
121 | }
|
122 |
|
123 | mCounter = nullptr;
|
124 | }
|
125 |
|
126 | mPtr = nullptr;
|
127 | }
|
128 |
|
129 | T* mPtr = nullptr;
|
130 | uint32_t* mCounter = nullptr;
|
131 | };
|
132 |
|
133 | template<class T, class U>
|
134 | bool operator==(const USPtr<T>& lhs, const USPtr<U>& rhs)
|
135 | {
|
136 | return lhs.get() == rhs.get();
|
137 | }
|
138 |
|
139 | template<class T, class U>
|
140 | bool operator!=(const USPtr<T>& lhs, const USPtr<U>& rhs)
|
141 | {
|
142 | return lhs.get() != rhs.get();
|
143 | }
|
144 |
|
145 | template<class T, class U>
|
146 | bool operator<=(const USPtr<T>& lhs, const USPtr<U>& rhs)
|
147 | {
|
148 | return lhs.get() <= rhs.get();
|
149 | }
|
150 |
|
151 | template<class T, class U>
|
152 | bool operator<(const USPtr<T>& lhs, const USPtr<U>& rhs)
|
153 | {
|
154 | return lhs.get() < rhs.get();
|
155 | }
|
156 |
|
157 | template<class T, class U>
|
158 | bool operator>=(const USPtr<T>& lhs, const USPtr<U>& rhs)
|
159 | {
|
160 | return lhs.get() >= rhs.get();
|
161 | }
|
162 |
|
163 | template<class T, class U>
|
164 | bool operator>(const USPtr<T>& lhs, const USPtr<U>& rhs)
|
165 | {
|
166 | return lhs.get() > rhs.get();
|
167 | }
|
168 |
|
169 | template<class T>
|
170 | bool operator==(nullptr_t, const USPtr<T>& rhs)
|
171 | {
|
172 | return nullptr == rhs.get();
|
173 | }
|
174 |
|
175 | template<class T>
|
176 | bool operator==(const USPtr<T>& lhs, nullptr_t)
|
177 | {
|
178 | return lhs.get() == nullptr;
|
179 | }
|
180 |
|
181 | template<class T>
|
182 | bool operator!=(nullptr_t, const USPtr<T>& rhs)
|
183 | {
|
184 | return nullptr != rhs.get();
|
185 | }
|
186 |
|
187 | template<class T>
|
188 | bool operator!=(const USPtr<T>& lhs, nullptr_t)
|
189 | {
|
190 | return lhs.get() != nullptr;
|
191 | }
|
192 |
|
193 | /** Cast an unsafe shared pointer from one type to another. */
|
194 | template<class T, class U>
|
195 | USPtr<T> static_pointer_cast(const USPtr<U>& ptr)
|
196 | {
|
197 | return USPtr<T>(ptr);
|
198 | }
|
199 |
|
200 | /** Create a new unsafe shared pointer using a custom allocator category. */
|
201 | template<typename Type, typename... Args>
|
202 | USPtr<Type> bs_ushared_ptr_new(Args &&... args)
|
203 | {
|
204 | // Note: Ideally we merge the pointer and internal USPtr counter allocation in a single allocation
|
205 |
|
206 | return USPtr<Type>(bs_new<Type>(std::forward<Args>(args)...));
|
207 | }
|
208 |
|
209 | /** Create a new unsafe shared pointer from a previously constructed object. */
|
210 | template<typename Type>
|
211 | USPtr<Type> bs_ushared_ptr(Type* data)
|
212 | {
|
213 | return USPtr<Type>(data);
|
214 | }
|
215 |
|
216 | /** @} */
|
217 | }
|
218 | |