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