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