3D Audio GSoC:
[blender.git] / intern / audaspace / intern / AUD_Reference.h
index 3232ca3b609644fa66fdb2984e6ac5e7b71feef2..3977b22a1dd5ad0d3b18e56ba274b8caa57decc4 100644 (file)
  *  \ingroup audaspaceintern
  */
 
-
 #ifndef AUD_REFERENCE
 #define AUD_REFERENCE
 
+#include <map>
+
+// #define MEM_DEBUG
+
+#ifdef MEM_DEBUG
+#include <iostream>
+#include <typeinfo>
+#endif
+
+/**
+ * This class handles the reference counting.
+ */
+class AUD_ReferenceHandler
+{
+private:
+       /**
+        * Saves the reference counts.
+        */
+       static std::map<void*, int> m_references;
+
+public:
+       /**
+        * Reference increment.
+        * \param reference The reference.
+        */
+       static inline void incref(void* reference)
+       {
+               if(!reference)
+                       return;
+
+               std::map<void*, int>::iterator result = m_references.find(reference);
+               if(result != m_references.end())
+               {
+                       m_references[reference]++;
+               }
+               else
+               {
+                       m_references[reference] = 1;
+               }
+       }
+
+       /**
+        * Reference decrement.
+        * \param reference The reference.
+        * \return Whether the reference has to be deleted.
+        */
+       static inline bool decref(void* reference)
+       {
+               if(!reference)
+                       return false;
+
+               if(!--m_references[reference])
+               {
+                       m_references.erase(reference);
+                       return true;
+               }
+               return false;
+       }
+};
+
 template <class T>
 /**
  * This class provides reference counting functionality.
@@ -41,18 +100,28 @@ class AUD_Reference
 private:
        /// The reference.
        T* m_reference;
-       /// The reference counter.
-       int* m_refcount;
+       void* m_original;
 public:
        /**
         * Creates a new reference counter.
         * \param reference The reference.
         */
-       AUD_Reference(T* reference = 0)
+       template <class U>
+       AUD_Reference(U* reference)
+       {
+               m_original = reference;
+               m_reference = dynamic_cast<T*>(reference);
+               AUD_ReferenceHandler::incref(m_original);
+#ifdef MEM_DEBUG
+               if(m_reference != 0)
+                       std::cerr << "+" << typeid(*m_reference).name() << std::endl;
+#endif
+       }
+
+       AUD_Reference()
        {
-               m_reference = reference;
-               m_refcount = new int;
-               *m_refcount = 1;
+               m_original = 0;
+               m_reference = 0;
        }
 
        /**
@@ -61,9 +130,25 @@ public:
         */
        AUD_Reference(const AUD_Reference& ref)
        {
+               m_original = ref.m_original;
                m_reference = ref.m_reference;
-               m_refcount = ref.m_refcount;
-               (*m_refcount)++;
+               AUD_ReferenceHandler::incref(m_original);
+#ifdef MEM_DEBUG
+               if(m_reference != 0)
+                       std::cerr << "+" << typeid(*m_reference).name() << std::endl;
+#endif
+       }
+
+       template <class U>
+       explicit AUD_Reference(const AUD_Reference<U>& ref)
+       {
+               m_original = ref.get();
+               m_reference = dynamic_cast<T*>(ref.get());
+               AUD_ReferenceHandler::incref(m_original);
+#ifdef MEM_DEBUG
+               if(m_reference != 0)
+                       std::cerr << "+" << typeid(*m_reference).name() << std::endl;
+#endif
        }
 
        /**
@@ -72,15 +157,12 @@ public:
         */
        ~AUD_Reference()
        {
-               (*m_refcount)--;
-               if(*m_refcount == 0)
-               {
-                       if(m_reference)
-                       {
-                               delete m_reference;
-                       }
-                       delete m_refcount;
-               }
+#ifdef MEM_DEBUG
+               if(m_reference != 0)
+                       std::cerr << "-" << typeid(*m_reference).name() << std::endl;
+#endif
+               if(AUD_ReferenceHandler::decref(m_original))
+                       delete m_reference;
        }
 
        /**
@@ -92,30 +174,75 @@ public:
                if(&ref == this)
                        return *this;
 
-               (*m_refcount)--;
-               if(*m_refcount == 0)
-               {
-                       if(m_reference)
-                       {
-                               delete m_reference;
-                       }
-                       delete m_refcount;
-               }
+#ifdef MEM_DEBUG
+               if(m_reference != 0)
+                       std::cerr << "-" << typeid(*m_reference).name() << std::endl;
+#endif
+               if(AUD_ReferenceHandler::decref(m_original))
+                       delete m_reference;
 
+               m_original = ref.m_original;
                m_reference = ref.m_reference;
-               m_refcount = ref.m_refcount;
-               (*m_refcount)++;
+               AUD_ReferenceHandler::incref(m_original);
+#ifdef MEM_DEBUG
+               if(m_reference != 0)
+                       std::cerr << "+" << typeid(*m_reference).name() << std::endl;
+#endif
 
                return *this;
        }
 
+       /**
+        * Returns whether the reference is NULL.
+        */
+       inline bool isNull() const
+       {
+               return m_reference == 0;
+       }
+
        /**
         * Returns the reference.
         */
-       T* get() const
+       inline T* get() const
+       {
+               return m_reference;
+       }
+
+       /**
+        * Returns the original pointer.
+        */
+       inline void* getOriginal() const
+       {
+               return m_original;
+       }
+
+       /**
+        * Returns the reference.
+        */
+       inline T& operator*() const
+       {
+               return *m_reference;
+       }
+
+       /**
+        * Returns the reference.
+        */
+       inline T* operator->() const
        {
                return m_reference;
        }
 };
 
+template<class T, class U>
+inline bool operator==(const AUD_Reference<T>& a, const AUD_Reference<U>& b)
+{
+       return a.getOriginal() == b.getOriginal();
+}
+
+template<class T, class U>
+inline bool operator!=(const AUD_Reference<T>& a, const AUD_Reference<U>& b)
+{
+       return a.getOriginal() != b.getOriginal();
+}
+
 #endif // AUD_REFERENCE