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