2e07417154b85828ea822c048628ab834ff940d0
[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
35 // #define MEM_DEBUG
36
37 #ifdef MEM_DEBUG
38 #include <iostream>
39 #include <typeinfo>
40 #endif
41
42 /**
43  * This class handles the reference counting.
44  */
45 class AUD_ReferenceHandler
46 {
47 private:
48         /**
49          * Saves the reference counts.
50          */
51         static std::map<void*, unsigned int> m_references;
52
53 public:
54         /**
55          * Reference increment.
56          * \param reference The reference.
57          */
58         static inline void incref(void* reference)
59         {
60                 if(!reference)
61                         return;
62
63                 std::map<void*, unsigned int>::iterator result = m_references.find(reference);
64                 if(result != m_references.end())
65                 {
66                         m_references[reference]++;
67                 }
68                 else
69                 {
70                         m_references[reference] = 1;
71                 }
72         }
73
74         /**
75          * Reference decrement.
76          * \param reference The reference.
77          * \return Whether the reference has to be deleted.
78          */
79         static inline bool decref(void* reference)
80         {
81                 if(!reference)
82                         return false;
83
84                 if(!--m_references[reference])
85                 {
86                         m_references.erase(reference);
87                         return true;
88                 }
89                 return false;
90         }
91 };
92
93 template <class T>
94 /**
95  * This class provides reference counting functionality.
96  */
97 class AUD_Reference
98 {
99 private:
100         /// The reference.
101         T* m_reference;
102         void* m_original;
103 public:
104         /**
105          * Creates a new reference counter.
106          * \param reference The reference.
107          */
108         template <class U>
109         AUD_Reference(U* reference)
110         {
111                 m_original = reference;
112                 m_reference = dynamic_cast<T*>(reference);
113                 AUD_ReferenceHandler::incref(m_original);
114 #ifdef MEM_DEBUG
115                 if(m_reference != NULL)
116                         std::cerr << "+" << typeid(*m_reference).name() << std::endl;
117 #endif
118         }
119
120         AUD_Reference()
121         {
122                 m_original = NULL;
123                 m_reference = NULL;
124         }
125
126         /**
127          * Copies an AUD_Reference object.
128          * \param ref The AUD_Reference object to copy.
129          */
130         AUD_Reference(const AUD_Reference& ref)
131         {
132                 m_original = ref.m_original;
133                 m_reference = ref.m_reference;
134                 AUD_ReferenceHandler::incref(m_original);
135 #ifdef MEM_DEBUG
136                 if(m_reference != NULL)
137                         std::cerr << "+" << typeid(*m_reference).name() << std::endl;
138 #endif
139         }
140
141         template <class U>
142         explicit AUD_Reference(const AUD_Reference<U>& ref)
143         {
144                 m_original = ref.get();
145                 m_reference = dynamic_cast<T*>(ref.get());
146                 AUD_ReferenceHandler::incref(m_original);
147 #ifdef MEM_DEBUG
148                 if(m_reference != NULL)
149                         std::cerr << "+" << typeid(*m_reference).name() << std::endl;
150 #endif
151         }
152
153         /**
154          * Destroys a AUD_Reference object, if there's no furthere reference on the
155          * reference, it is destroyed as well.
156          */
157         ~AUD_Reference()
158         {
159 #ifdef MEM_DEBUG
160                 if(m_reference != NULL)
161                         std::cerr << "-" << typeid(*m_reference).name() << std::endl;
162 #endif
163                 if(AUD_ReferenceHandler::decref(m_original))
164                         delete m_reference;
165         }
166
167         /**
168          * Assigns an AUD_Reference to this object.
169          * \param ref The AUD_Reference object to assign.
170          */
171         AUD_Reference& operator=(const AUD_Reference& ref)
172         {
173                 if(&ref == this)
174                         return *this;
175
176 #ifdef MEM_DEBUG
177                 if(m_reference != NULL)
178                         std::cerr << "-" << typeid(*m_reference).name() << std::endl;
179 #endif
180                 if(AUD_ReferenceHandler::decref(m_original))
181                         delete m_reference;
182
183                 m_original = ref.m_original;
184                 m_reference = ref.m_reference;
185                 AUD_ReferenceHandler::incref(m_original);
186 #ifdef MEM_DEBUG
187                 if(m_reference != NULL)
188                         std::cerr << "+" << typeid(*m_reference).name() << std::endl;
189 #endif
190
191                 return *this;
192         }
193
194         /**
195          * Returns whether the reference is NULL.
196          */
197         inline bool isNull() const
198         {
199                 return m_reference == NULL;
200         }
201
202         /**
203          * Returns the reference.
204          */
205         inline T* get() const
206         {
207                 return m_reference;
208         }
209
210         /**
211          * Returns the original pointer.
212          */
213         inline void* getOriginal() const
214         {
215                 return m_original;
216         }
217
218         /**
219          * Returns the reference.
220          */
221         inline T& operator*() const
222         {
223                 return *m_reference;
224         }
225
226         /**
227          * Returns the reference.
228          */
229         inline T* operator->() const
230         {
231                 return m_reference;
232         }
233 };
234
235 template<class T, class U>
236 inline bool operator==(const AUD_Reference<T>& a, const AUD_Reference<U>& b)
237 {
238         return a.getOriginal() == b.getOriginal();
239 }
240
241 template<class T, class U>
242 inline bool operator!=(const AUD_Reference<T>& a, const AUD_Reference<U>& b)
243 {
244         return a.getOriginal() != b.getOriginal();
245 }
246
247 #endif // __AUD_REFERENCE_H__