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