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