Hopefully a fix for [#31097] glibc error when playing sound using BGE
[blender.git] / intern / audaspace / intern / AUD_Reference.h
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * Copyright 2009-2011 Jörg Hermann Müller
5  *
6  * This file is part of AudaSpace.
7  *
8  * Audaspace is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * AudaSpace is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with Audaspace; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 /** \file audaspace/intern/AUD_Reference.h
26  *  \ingroup audaspaceintern
27  */
28
29 #ifndef __AUD_REFERENCE_H__
30 #define __AUD_REFERENCE_H__
31
32 #include <map>
33 #include <cstddef>
34 #include <pthread.h>
35
36 // #define MEM_DEBUG
37
38 #ifdef MEM_DEBUG
39 #include <iostream>
40 #include <typeinfo>
41 #endif
42
43 /**
44  * This class handles the reference counting.
45  */
46 class AUD_ReferenceHandler
47 {
48 private:
49         /**
50          * Saves the reference counts.
51          */
52         static std::map<void*, unsigned int> m_references;
53         static pthread_mutex_t m_mutex;
54         static bool m_mutex_initialised;
55
56 public:
57
58         static pthread_mutex_t* getMutex();
59
60         /**
61          * Reference increment.
62          * \param reference The reference.
63          */
64         static inline void incref(void* reference)
65         {
66                 if(!reference)
67                         return;
68
69                 std::map<void*, unsigned int>::iterator result = m_references.find(reference);
70                 if(result != m_references.end())
71                 {
72                         m_references[reference]++;
73                 }
74                 else
75                 {
76                         m_references[reference] = 1;
77                 }
78         }
79
80         /**
81          * Reference decrement.
82          * \param reference The reference.
83          * \return Whether the reference has to be deleted.
84          */
85         static inline bool decref(void* reference)
86         {
87                 if(!reference)
88                         return false;
89
90                 if(!--m_references[reference])
91                 {
92                         m_references.erase(reference);
93                         return true;
94                 }
95                 return false;
96         }
97 };
98
99 template <class T>
100 /**
101  * This class provides reference counting functionality.
102  */
103 class AUD_Reference
104 {
105 private:
106         /// The reference.
107         T* m_reference;
108         void* m_original;
109 public:
110         /**
111          * Creates a new reference counter.
112          * \param reference The reference.
113          */
114         template <class U>
115         AUD_Reference(U* reference)
116         {
117                 pthread_mutex_lock(AUD_ReferenceHandler::getMutex());
118                 m_original = reference;
119                 m_reference = dynamic_cast<T*>(reference);
120                 AUD_ReferenceHandler::incref(m_original);
121 #ifdef MEM_DEBUG
122                 if(m_reference != NULL)
123                         std::cerr << "+" << typeid(*m_reference).name() << std::endl;
124 #endif
125                 pthread_mutex_unlock(AUD_ReferenceHandler::getMutex());
126         }
127
128         AUD_Reference()
129         {
130                 m_original = NULL;
131                 m_reference = NULL;
132         }
133
134         /**
135          * Copies an AUD_Reference object.
136          * \param ref The AUD_Reference object to copy.
137          */
138         AUD_Reference(const AUD_Reference& ref)
139         {
140                 pthread_mutex_lock(AUD_ReferenceHandler::getMutex());
141                 m_original = ref.m_original;
142                 m_reference = ref.m_reference;
143                 AUD_ReferenceHandler::incref(m_original);
144 #ifdef MEM_DEBUG
145                 if(m_reference != NULL)
146                         std::cerr << "+" << typeid(*m_reference).name() << std::endl;
147 #endif
148                 pthread_mutex_unlock(AUD_ReferenceHandler::getMutex());
149         }
150
151         template <class U>
152         explicit AUD_Reference(const AUD_Reference<U>& ref)
153         {
154                 pthread_mutex_lock(AUD_ReferenceHandler::getMutex());
155                 m_original = ref.get();
156                 m_reference = dynamic_cast<T*>(ref.get());
157                 AUD_ReferenceHandler::incref(m_original);
158 #ifdef MEM_DEBUG
159                 if(m_reference != NULL)
160                         std::cerr << "+" << typeid(*m_reference).name() << std::endl;
161 #endif
162                 pthread_mutex_unlock(AUD_ReferenceHandler::getMutex());
163         }
164
165         /**
166          * Destroys a AUD_Reference object, if there's no furthere reference on the
167          * reference, it is destroyed as well.
168          */
169         ~AUD_Reference()
170         {
171                 pthread_mutex_lock(AUD_ReferenceHandler::getMutex());
172 #ifdef MEM_DEBUG
173                 if(m_reference != NULL)
174                         std::cerr << "-" << typeid(*m_reference).name() << std::endl;
175 #endif
176                 if(AUD_ReferenceHandler::decref(m_original))
177                         delete m_reference;
178                 pthread_mutex_unlock(AUD_ReferenceHandler::getMutex());
179         }
180
181         /**
182          * Assigns an AUD_Reference to this object.
183          * \param ref The AUD_Reference object to assign.
184          */
185         AUD_Reference& operator=(const AUD_Reference& ref)
186         {
187                 if(&ref == this)
188                         return *this;
189
190                 pthread_mutex_lock(AUD_ReferenceHandler::getMutex());
191
192 #ifdef MEM_DEBUG
193                 if(m_reference != NULL)
194                         std::cerr << "-" << typeid(*m_reference).name() << std::endl;
195 #endif
196                 if(AUD_ReferenceHandler::decref(m_original))
197                         delete m_reference;
198
199                 m_original = ref.m_original;
200                 m_reference = ref.m_reference;
201                 AUD_ReferenceHandler::incref(m_original);
202 #ifdef MEM_DEBUG
203                 if(m_reference != NULL)
204                         std::cerr << "+" << typeid(*m_reference).name() << std::endl;
205 #endif
206
207                 pthread_mutex_unlock(AUD_ReferenceHandler::getMutex());
208
209                 return *this;
210         }
211
212         /**
213          * Returns whether the reference is NULL.
214          */
215         inline bool isNull() const
216         {
217                 return m_reference == NULL;
218         }
219
220         /**
221          * Returns the reference.
222          */
223         inline T* get() const
224         {
225                 return m_reference;
226         }
227
228         /**
229          * Returns the original pointer.
230          */
231         inline void* getOriginal() const
232         {
233                 return m_original;
234         }
235
236         /**
237          * Returns the reference.
238          */
239         inline T& operator*() const
240         {
241                 return *m_reference;
242         }
243
244         /**
245          * Returns the reference.
246          */
247         inline T* operator->() const
248         {
249                 return m_reference;
250         }
251 };
252
253 template<class T, class U>
254 inline bool operator==(const AUD_Reference<T>& a, const AUD_Reference<U>& b)
255 {
256         return a.getOriginal() == b.getOriginal();
257 }
258
259 template<class T, class U>
260 inline bool operator!=(const AUD_Reference<T>& a, const AUD_Reference<U>& b)
261 {
262         return a.getOriginal() != b.getOriginal();
263 }
264
265 #endif // __AUD_REFERENCE_H__