BWAPI
SPAR/AIModule/Utils/ReferenceCounted.h
Go to the documentation of this file.
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 };
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines