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