BWAPI
|
00001 #pragma once 00002 00003 #if defined(_DEBUG) && defined(_DEBUG_REFERENCE_COUNTED) 00004 #include <map> 00005 #else 00006 #include <string> 00007 #endif 00008 00009 #include "Utils.h" 00010 #include <iostream> 00011 #include <boost/tuple/tuple.hpp> 00012 #include <boost/type_traits.hpp> 00013 00014 template <class ReferenceCounted> 00015 class AutoPtr; 00016 00017 class ReferenceCounted 00018 { 00019 public: 00020 ReferenceCounted() 00021 : m_nbRef(0) 00022 { 00023 #if defined(_DEBUG) && defined(_DEBUG_REFERENCE_COUNTED) 00024 this->m_previous = s_head; 00025 this->m_next = NULL; 00026 if (s_head != NULL) 00027 s_head->m_next = this; 00028 s_head = this; 00029 #endif 00030 } 00031 00032 ReferenceCounted(const ReferenceCounted&) 00033 : m_nbRef(0) 00034 { 00035 #if defined(_DEBUG) && defined(_DEBUG_REFERENCE_COUNTED) 00036 this->m_previous = s_head; 00037 this->m_next = NULL; 00038 if (s_head != NULL) 00039 s_head->m_next = this; 00040 s_head = this; 00041 #endif 00042 } 00043 00044 virtual ~ReferenceCounted() 00045 { 00046 #if defined(_DEBUG) && defined(_DEBUG_REFERENCE_COUNTED) 00047 removeFromList(); 00048 #endif 00049 } 00050 00051 #if defined(_DEBUG) && defined(_DEBUG_REFERENCE_COUNTED) 00052 void removeFromList() 00053 { 00054 if (this->m_previous != NULL) 00055 this->m_previous->m_next = this->m_next; 00056 if (this->m_next != NULL) 00057 this->m_next->m_previous = this->m_previous; 00058 if (s_head == this) 00059 s_head = this->m_previous; 00060 } 00061 #endif 00062 00063 void markAsStatic() 00064 { 00065 // This reference is never going to be released as to not accidentally delete a static object 00066 ++m_nbRef; 00067 00068 #if defined(_DEBUG) && defined(_DEBUG_REFERENCE_COUNTED) 00069 removeFromList(); 00070 #endif 00071 } 00072 00073 template <class Acquirer> 00074 void acquire(const Acquirer *acquirer) const 00075 { 00076 ++m_nbRef; 00077 00078 #if defined(_DEBUG) && defined(_DEBUG_REFERENCE_COUNTED) 00079 std::pair<std::map<const void*, boost::tuple<const type_info*, size_t, bool>>::iterator, bool> result = 00080 m_acquirers.insert(std::make_pair(convertToVoidPtr(acquirer), 00081 boost::make_tuple(&typeid(acquirer), 0, isReferenceCounted(acquirer)))); 00082 00083 ++(result.first->second.get<1>()); 00084 #else 00085 unused(acquirer); 00086 #endif 00087 } 00088 00089 template <class Acquirer> 00090 void release(const Acquirer *acquirer) const 00091 { 00092 #if defined(_DEBUG) && defined(_DEBUG_REFERENCE_COUNTED) 00093 std::map<const void*, boost::tuple<const type_info*, size_t, bool>>::iterator it = m_acquirers.find(convertToVoidPtr(acquirer)); 00094 if (it == m_acquirers.end()) { 00095 const char* typeName = typeid(acquirer).name(); 00096 std::cout << "Error: '" << typeName 00097 << " " << std::hex << convertToVoidPtr(acquirer) << "' attempted to release '" 00098 << this->toString() << "' without acquiring it first" << std::endl; 00099 } 00100 else 00101 { 00102 if (--(it->second.get<1>()) == 0) 00103 m_acquirers.erase(it); 00104 } 00105 #else 00106 unused(acquirer); 00107 #endif 00108 if (--m_nbRef == 0) 00109 delete this; 00110 } 00111 00112 void considerDeletion() const 00113 { 00114 if (m_nbRef == 0) 00115 { 00116 delete this; 00117 } 00118 } 00119 00120 virtual std::string toString() const = 0; 00121 00122 #if defined(_DEBUG) && defined(_DEBUG_REFERENCE_COUNTED) 00123 static size_t signalMemoryLeaks(); 00124 #endif 00125 00126 private: 00127 template <class ReferenceCounted> 00128 friend class AutoPtr; 00129 00130 struct ReferenceCountedType 00131 { 00132 template <class T> 00133 static const void* convertToVoidPtr(const T* t) 00134 { 00135 const ReferenceCounted* r = dynamic_cast<const ReferenceCounted*>(t); 00136 assert(r != NULL); 00137 return r; 00138 } 00139 static void considerDeletion(const ReferenceCounted& referenceCounted) 00140 { 00141 referenceCounted.considerDeletion(); 00142 } 00143 }; 00144 00145 struct NotReferenceCountedType 00146 { 00147 template <class T> 00148 static const void* convertToVoidPtr(const T* t) 00149 { 00150 return static_cast<const void*>(t); 00151 } 00152 template <class T> 00153 static void considerDeletion(const T& t) 00154 { 00155 delete &t; 00156 } 00157 }; 00158 00159 template <class Acquirer> 00160 static const void* convertToVoidPtr(const Acquirer* acquirer) 00161 { 00162 return static_if_else<boost::is_convertible<Acquirer*, ReferenceCounted*>::value, 00163 ReferenceCountedType, 00164 NotReferenceCountedType>::type::convertToVoidPtr(acquirer); 00165 } 00166 00167 template <class Acquirer> 00168 static bool isReferenceCounted(const Acquirer* acquirer) 00169 { 00170 return boost::is_convertible<Acquirer*, ReferenceCounted*>::value; 00171 } 00172 00173 mutable size_t m_nbRef; 00174 00175 #if defined(_DEBUG) && defined(_DEBUG_REFERENCE_COUNTED) 00176 static const ReferenceCounted *s_head; 00177 00178 mutable const ReferenceCounted* m_previous; 00179 00180 mutable const ReferenceCounted* m_next; 00181 00182 mutable std::map<const void*, boost::tuple<const type_info*, size_t, bool>> m_acquirers; 00183 #endif 00184 00185 }; 00186 00187 template <class ReferenceCounted> 00188 class AutoPtr 00189 { 00190 public: 00191 template <class Acquirer> 00192 AutoPtr(ReferenceCounted* ref, const Acquirer& acquirer) 00193 : m_ref(ref) 00194 , m_acquirer(ReferenceCounted::convertToVoidPtr(&acquirer)) 00195 { 00196 if (m_ref != NULL) 00197 m_ref->acquire(&acquirer); 00198 } 00199 AutoPtr(const AutoPtr& other) 00200 : m_ref(other.m_ref) 00201 , m_acquirer(other.m_acquirer) 00202 { 00203 if (m_ref != NULL) 00204 m_ref->acquire(m_acquirer); 00205 } 00206 ~AutoPtr() 00207 { 00208 if (m_ref != NULL) 00209 m_ref->release(m_acquirer); 00210 } 00211 const ReferenceCounted* operator->() const 00212 { 00213 return m_ref; 00214 } 00215 ReferenceCounted* operator->() 00216 { 00217 return m_ref; 00218 } 00219 const ReferenceCounted& operator*() const 00220 { 00221 return *m_ref; 00222 } 00223 ReferenceCounted& operator*() 00224 { 00225 return *m_ref; 00226 } 00227 operator const ReferenceCounted* () const 00228 { 00229 return m_ref; 00230 } 00231 operator ReferenceCounted* () 00232 { 00233 return m_ref; 00234 } 00235 AutoPtr& operator=(const ReferenceCounted* ref) 00236 { 00237 if (ref != NULL) 00238 ref->acquire(m_acquirer): 00239 if (m_ref != NULL) 00240 ref->release(m_acquirer); 00241 m_ref = ref; 00242 return *this; 00243 } 00244 00245 protected: 00246 const void* const m_acquirer; 00247 ReferenceCounted* const m_ref; 00248 00249 private: 00250 AutoPtr& operator=(const AutoPtr& other); 00251 }; 00252 00253 namespace memory 00254 { 00255 // These methods are wrapped in 'memory' to avoid name clashes with ReferenceCounted methods (like acquire()) 00256 00257 template <class Acquirer> 00258 void acquire(const Acquirer* acquirer, const ReferenceCounted& referenceCounted) 00259 { 00260 referenceCounted.acquire(acquirer); 00261 } 00262 00263 template <class Acquirer, class T> 00264 void acquire(const Acquirer* acquirer, const T* const t) 00265 { 00266 acquire(acquirer, *t); 00267 } 00268 00269 template <class Acquirer, class T> 00270 void acquire(const Acquirer* acquirer, T* const t) 00271 { 00272 acquire(acquirer, *t); 00273 } 00274 00275 template <class Acquirer, class Iterator> 00276 void acquire(const Acquirer* acquirer, Iterator begin, Iterator end) 00277 { 00278 for (; begin != end; ++begin) 00279 { 00280 acquire(acquirer, *begin); 00281 } 00282 } 00283 00284 template <class Acquirer> 00285 void release(const Acquirer* acquirer, const ReferenceCounted& referenceCounted) 00286 { 00287 referenceCounted.release(acquirer); 00288 } 00289 00290 template <class Acquirer, class T> 00291 void release(const Acquirer* acquirer, const T* const t) 00292 { 00293 release(acquirer, *t); 00294 } 00295 00296 template <class Acquirer, class T> 00297 void release(const Acquirer* acquirer, T* const t) 00298 { 00299 release(acquirer, *t); 00300 } 00301 00302 template <class Acquirer, class Iterator> 00303 void release(const Acquirer* acquirer, Iterator begin, Iterator end) 00304 { 00305 for (; begin != end; ++begin) 00306 { 00307 release(acquirer, *begin); 00308 } 00309 } 00310 00311 inline void considerDeletion(const ReferenceCounted& referenceCounted) 00312 { 00313 referenceCounted.considerDeletion(); 00314 } 00315 00316 template <class T> 00317 void considerDeletion(const T* const t) 00318 { 00319 considerDeletion(*t); 00320 } 00321 00322 template <class T> 00323 void considerDeletion(T* const t) 00324 { 00325 considerDeletion(*t); 00326 } 00327 00328 template <class Iterator> 00329 void considerDeletion(Iterator begin, Iterator end) 00330 { 00331 for (; begin != end; ++begin) 00332 { 00333 considerDeletion(*begin); 00334 } 00335 } 00336 };