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
7namespace 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