1 /*************************************************************************** 2 * Copyright (C) 2005-2019 by the FIFE team * 3 * http://www.fifengine.net * 4 * This file is part of FIFE. * 5 * * 6 * FIFE is free software; you can redistribute it and/or * 7 * modify it under the terms of the GNU Lesser General Public * 8 * License as published by the Free Software Foundation; either * 9 * version 2.1 of the License, or (at your option) any later version. * 10 * * 11 * This library is distributed in the hope that it will be useful, * 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 14 * Lesser General Public License for more details. * 15 * * 16 * You should have received a copy of the GNU Lesser General Public * 17 * License along with this library; if not, write to the * 18 * Free Software Foundation, Inc., * 19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * 20 ***************************************************************************/ 21 #ifndef FIFE_SHARED_PTR_H_ 22 #define FIFE_SHARED_PTR_H_ 23 24 // Standard C++ library includes 25 #include <cassert> 26 #include <functional> 27 28 // 3rd party library includes 29 30 // FIFE includes 31 // These includes are split up in two parts, separated by one empty line 32 // First block: files included from the FIFE root src directory 33 // Second block: files included from the same folder 34 #include "fife_stdint.h" 35 36 namespace FIFE { 37 /** shared pointer implementation to provide automatic 38 * reference counting and deletion when last reference 39 * falls out of scope. 40 */ 41 template <typename T> 42 class SharedPtr { 43 public: 44 45 /** Constructor 46 * default constructor 47 * creates a null shared pointer 48 */ SharedPtr()49 SharedPtr() 50 : m_ptr(0), m_refCount(0) { 51 52 } 53 54 /** Constructor 55 * takes over ownership of the provided pointer 56 * and will delete it automatically when last 57 * reference falls out of scope. 58 */ 59 template <typename U> SharedPtr(U * ptr)60 explicit SharedPtr(U *ptr) 61 : m_ptr(ptr), m_refCount(ptr ? new uint32_t(1) : 0) { 62 63 } 64 65 /** Copy Constructor 66 * provides ability to properly copy a shared resource 67 */ SharedPtr(const SharedPtr & rhs)68 SharedPtr(const SharedPtr& rhs) 69 : m_ptr(rhs.m_ptr), m_refCount(rhs.m_refCount) { 70 // increase reference count 71 incRefCount(); 72 } 73 74 /** Constructor 75 * shares ownership with the value passed into rhs 76 * the pointer type passed in must be convertible 77 * to this shared pointer type 78 */ 79 template <typename U> SharedPtr(const SharedPtr<U> & rhs)80 SharedPtr(const SharedPtr<U>& rhs) { 81 m_ptr = rhs.get(); 82 m_refCount = rhs.useCountPtr(); 83 incRefCount(); 84 } 85 86 /** Destructor 87 * handles deletion of underlying pointer 88 * if the reference count reaches 0 89 */ ~SharedPtr()90 ~SharedPtr() { 91 // decrement reference count 92 decRefCount(); 93 94 // check to see if we need to delete 95 if (m_refCount && *m_refCount == 0) { 96 // delete and set pointers to null 97 delete m_ptr; 98 delete m_refCount; 99 m_ptr = 0; 100 m_refCount = 0; 101 } 102 } 103 104 /** provides functionality for the equality operator 105 */ 106 SharedPtr& operator=(const SharedPtr& rhs) { 107 // handle self assignment 108 if (rhs.get() == m_ptr) { 109 return *this; 110 } 111 112 // store in temporary (which causes a ref count increase) 113 // and swap with this object 114 SharedPtr<T> temp(rhs); 115 swap(temp); 116 return *this; 117 } 118 119 /** provides functionality for the equality operator 120 * the passed in pointer type must be convertible to 121 * this pointer type 122 */ 123 template <typename U> 124 SharedPtr& operator=(const SharedPtr<U>& rhs) { 125 // handle self assignment 126 if (rhs.get() == m_ptr) { 127 return *this; 128 } 129 130 // store in temporary (which causes a ref count increase) 131 // and swap with this object 132 SharedPtr<T> temp(rhs); 133 swap(temp); 134 return *this; 135 } 136 137 /** allows dereferencing of shared pointer to act 138 * identical to dereferencing the underlying pointer 139 */ 140 inline T& operator*() const { 141 assert(m_ptr); 142 return *m_ptr; 143 } 144 145 /** allows dereferencing of shared pointer to act 146 * identical to dereferencing the underlying pointer 147 */ 148 inline T* operator->() const { 149 assert(m_ptr); 150 return m_ptr; 151 } 152 153 /** allows direct access to underlying pointer 154 */ get()155 inline T* get() const { 156 return m_ptr; 157 } 158 159 /** reset this pointer to a null shared pointer 160 * this can be used to lower the reference count 161 * of the shared resource or set the underlying pointer 162 * to different pointer. 163 */ 164 inline void reset(T* ptr = 0) { 165 assert(ptr == 0 || ptr != m_ptr); 166 SharedPtr<T>(ptr).swap(*this); 167 } 168 169 /** returns the current reference count 170 * this should only be called on a non-null 171 * shared pointer 172 */ useCount()173 inline uint32_t useCount() const { 174 assert(m_refCount); 175 176 if (!m_refCount) { 177 return 0; 178 } 179 180 return *m_refCount; 181 } 182 183 /** returns the current reference count 184 * provides direct access to the user count pointer 185 * this should really only be used internally 186 */ useCountPtr()187 inline uint32_t* useCountPtr() const { 188 return m_refCount; 189 } 190 191 /** provides the ability to see if 192 * a shared resource is currently only 193 * held by a single shared pointer 194 * this should only be called on a non-null 195 * shared pointer 196 */ unique()197 inline bool unique() const { 198 assert(m_refCount); 199 return (*m_refCount == 1); 200 } 201 202 /** provides the ability to convert a 203 * shared pointer to a bool, this is 204 * a convenience for checking validity 205 * of a shared pointer in a conditional 206 */ 207 operator bool() const { 208 return (m_ptr != 0); 209 } 210 211 /** negation operator overload 212 */ 213 bool operator!() const { 214 return (m_ptr == 0); 215 } 216 217 private: 218 219 /** provides swapping function between 220 * two shared pointers, used internally 221 */ swap(SharedPtr<T> & rhs)222 inline void swap(SharedPtr<T>& rhs) { 223 std::swap(m_ptr, rhs.m_ptr); 224 std::swap(m_refCount, rhs.m_refCount); 225 } 226 227 /** increases the reference count for 228 * this shared resource, used internally 229 */ incRefCount()230 inline void incRefCount() { 231 if (m_refCount) { 232 ++(*m_refCount); 233 } 234 } 235 236 /** decreases the reference count for 237 * this shared resource, used internally 238 */ decRefCount()239 inline void decRefCount() { 240 if (m_refCount) { 241 --(*m_refCount); 242 } 243 } 244 245 private: 246 T* m_ptr; 247 uint32_t* m_refCount; 248 }; 249 250 /** provides equality operator for shared pointers 251 */ 252 template <typename T, typename U> 253 inline bool operator==(const SharedPtr<T>& lhs, const SharedPtr<U>& rhs) { 254 return (lhs.get() == rhs.get()); 255 } 256 257 /** provides inequality operator for shared pointers 258 */ 259 template <typename T, typename U> 260 inline bool operator!=(const SharedPtr<T>& lhs, const SharedPtr<U>& rhs) { 261 return (lhs.get() != rhs.get()); 262 } 263 264 /** provides less than operator for shared pointers 265 */ 266 template<class T, class U> 267 inline bool operator<(SharedPtr<T> const& lhs, SharedPtr<U> const& rhs) { 268 return std::less<const void*>()(lhs.get(), rhs.get()); 269 } 270 271 /** convenience function for making a shared pointer 272 * can be used anytime a shared pointer should be created 273 */ 274 template <typename T> make_shared(T * ptr)275 SharedPtr<T> make_shared(T* ptr) { 276 return SharedPtr<T>(ptr); 277 } 278 } //FIFE 279 280 #endif //FIFE_SHARED_PTR_H_ 281