1 #ifndef PEE_POINTER_H
2 #define PEE_POINTER_H
3 
4 #include <SFML/System.hpp>
5 #include <vector>
6 #include <assert.h>
7 
8 #include "logging.h"
9 
10 /**
11     P<T> is a reference counting pointer class. This class keeps track to the amount of P<T> pointers pointing to a Pobject.
12     If no more P<T> pointers point to a Pobject, the object is deleted. The object also has a destroyed flag, if the destroyed
13     flag is set, the pointers pointing towards it act as NULL pointers from that point on.
14     NOTE: This does not free circular references.
15 
16     The Pobject is not copyable and should not be created on the stack, only on the heap (so with "new")
17 
18     The Pvector class is a specialized version of the std::vector template. This vector holds an array of P<> pointers
19     The "foreach" macro can be used to walk trough all the Pobjects in a list without needing to dive into details
20     and automaticly removes any pointer from the list that points to an Pobject which has been destroyed.
21  */
22 #ifdef DEBUG
23 class PObject;
24 extern int DEBUG_PobjCount;
25 extern PObject* DEBUG_PobjListStart;
26 #endif
27 
28 class PObject: public sf::NonCopyable
29 {
30 private:
31     int refCount;
32     bool _destroyed_flag;
33 
34     //Make the P template a friend so it can access the private refCount and destroyed.
35     template<typename> friend class P;
36 public:
37 #ifdef DEBUG
38     PObject* DEBUG_PobjListNext;
39 #endif
40     PObject();
41 
42     virtual ~PObject();
43 
destroy()44     virtual void destroy()
45     {
46         _destroyed_flag = true;
47     }
48 
getRefCount()49     int getRefCount() const
50     {
51         return refCount;
52     }
isDestroyed()53     bool isDestroyed() const
54     {
55         return _destroyed_flag;
56     }
57 };
58 
59 template<class T>
60 class P
61 {
62 private:
63     T* ptr;
64 
65 public:
P()66     P()
67     {
68         ptr = NULL;
69     }
P(const P & p)70     P(const P& p)
71     {
72         ptr = NULL;
73         set(p.ptr);
74     }
P(T * p)75     P(T* p)
76     {
77         ptr = NULL;
78         set(p);
79     }
80 
~P()81     ~P()
82     {
83         release();
84     }
85 
86     P& operator = (T* p)
87     {
88         set(p);
89         return *this;
90     }
91 
92     P& operator = (const P& p)
93     {
94         if (&p != this) set(p.ptr);
95         return *this;
96     }
97 
98     T* operator->() const
99     {
100 #ifdef DEBUG
101         if(!ptr || ptr->_destroyed_flag)
102         {
103             LOG(ERROR) << "Oh noes! Better find me and put a breakpoint here!";
104         }
105         assert(ptr);
106         assert(!ptr->_destroyed_flag);
107 #endif
108         return ptr;
109     }
110     T* operator*()
111     {
112         check_release();
113         return ptr;
114     }
115 
116     T* operator*() const
117     {
118         return ptr;
119     }
120 
121     explicit operator bool()
122     {
123         check_release();
124         return ptr != NULL;
125     }
126 
127     explicit operator bool() const
128     {
129         return ptr != nullptr && !ptr->isDestroyed();
130     }
131 
132     template<class T2> operator P<T2>()
133     {
134         return dynamic_cast<T2*>(**this);
135     }
136 
137     template<class T2> operator P<T2>() const
138     {
139         return dynamic_cast<T2*>(**this);
140     }
141 
142 protected:
check_release()143     void check_release()
144     {
145         if (ptr != NULL && ptr->_destroyed_flag)
146             release();
147     }
148 
release()149     void release()
150     {
151         if (ptr)
152         {
153             ptr->refCount--;
154             if (ptr->refCount == 0)
155                 delete ptr;
156             ptr = NULL;
157         }
158     }
set(T * p)159     void set(T* p)
160     {
161         release();
162         ptr = p;
163         if (ptr != NULL)
164             ptr->refCount ++;
165     }
166 };
167 
168 template<class T>
169 class PVector: public std::vector<P<T> > {
170 public:
has(const P<T> & obj)171     bool has(const P<T>& obj)
172     {
173         for(unsigned int n=0; n<std::vector<P<T> >::size(); n++)
174             if ((*this)[n] == obj)
175                 return true;
176         return false;
177     }
178 
remove(const P<T> & obj)179     void remove(const P<T>& obj)
180     {
181         for(unsigned int n=0; n<std::vector<P<T> >::size(); n++)
182         {
183             if ((*this)[n] == obj)
184             {
185                 std::vector<P<T> >::erase(std::vector<P<T> >::begin() + n);
186                 n--;
187             }
188         }
189     }
190 
update()191     void update()
192     {
193         for(unsigned int n=0; n<std::vector<P<T> >::size(); n++)
194         {
195             if (!(*this)[n])
196             {
197                 std::vector<P<T> >::erase(std::vector<P<T> >::begin() + n);
198                 n--;
199             }
200         }
201     }
202 };
203 
204 template<class T>
205 class Piterator : public P<T>
206 {
207 private:
208     PVector<T>& list;
209     unsigned int index;
210 public:
Piterator(PVector<T> & list)211     Piterator(PVector<T>& list)
212     : P<T>(NULL), list(list), index(0)
213     {
214        next();
215     }
216 
next()217     void next()
218     {
219         while(true)
220         {
221             if (index >= list.size())
222             {
223                 P<T>::set(NULL);
224                 return;
225             }
226             P<T>::set(*list[index]);
227             if (*this)
228             {
229                 index++;
230                 return;
231             }
232             list.erase(list.begin() + index);
233         }
234     }
235 };
236 #define foreach(type, var, list) for(Piterator<type> var(list); var; var.next())
237 
238 template<class T> bool operator == (P<T>& p, const PObject* ptr)
239 {
240     return *p == ptr;
241 }
242 template<class T> bool operator != (P<T>& p, const PObject* ptr)
243 {
244     return *p != ptr;
245 }
246 template<class T1, class T2> bool operator == (P<T1>& p1, P<T2>& p2)
247 {
248     return *p1 == *p2;
249 }
250 template<class T1, class T2> bool operator != (P<T1>& p1, P<T2>& p2)
251 {
252     return *p1 != *p2;
253 }
254 template<class T1, class T2> bool operator == (const P<T1>& p1, const P<T2>& p2)
255 {
256     return *p1 == *p2;
257 }
258 template<class T1, class T2> bool operator != (const P<T1>& p1, const P<T2>& p2)
259 {
260     return *p1 != *p2;
261 }
262 
263 namespace std
264 {
265     //Make a specialization of std::hash
266     template <class T> struct hash<P<T>>
267     {
268         size_t operator()(const P<T>& k) const noexcept
269         {
270             return hash<void*>{}(*k);
271         }
272     };
273 }
274 
275 #endif//PEE_POINTER_H
276