1 // Copyright (C) 2004-2009 Mathias Froehlich - Mathias.Froehlich@web.de
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Library General Public
5 // License as published by the Free Software Foundation; either
6 // version 2 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Library General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 //
17
18 #ifndef SGWeakReferenced_HXX
19 #define SGWeakReferenced_HXX
20
21 #include "SGReferenced.hxx"
22 #include "SGSharedPtr.hxx"
23
24 #ifdef _MSC_VER
25 # pragma warning(push)
26 // C4355: 'this' : used in base member initializer list
27 // Tell MSVC we know what we do and really want to do it this way.
28 # pragma warning(disable: 4355)
29 #endif
30
31 template<typename T>
32 class SGWeakPtr;
33 class SGVirtualWeakReferenced;
34
35 /**
36 * Base class for all reference counted SimGear objects supporting weak
37 * references, not incrementing the reference count.
38 *
39 * Classes derived from this one are meant to be managed with the SGSharedPtr
40 * and SGWeakPtr classes.
41 *
42 * If the class hierarchy contains virtual base classes use
43 * SGVirtualWeakReferenced instead.
44 */
45 class SGWeakReferenced {
46 public:
47 /// The object backref and the reference count for this object need to be
48 /// there in any case. Also these are per object and shall not be copied nor
49 /// assigned.
50 /// The reference count for this object is stored in a secondary object that
51 /// is shared with all weak pointers to this current object. This way we
52 /// have an atomic decision using the reference count of this current object
53 /// if the backref is still valid. At the time where the atomic count is
54 /// equal to zero the object is considered dead.
SGWeakReferenced(void)55 SGWeakReferenced(void) :
56 mWeakData(new WeakData(this))
57 {}
SGWeakReferenced(const SGWeakReferenced & weakReferenced)58 SGWeakReferenced(const SGWeakReferenced& weakReferenced) :
59 mWeakData(new WeakData(this))
60 {}
~SGWeakReferenced(void)61 ~SGWeakReferenced(void)
62 { mWeakData->mWeakReferenced = 0; }
63
64 /// Do not copy the weak backward references ...
operator =(const SGWeakReferenced &)65 SGWeakReferenced& operator=(const SGWeakReferenced&)
66 { return *this; }
67
68 /// The usual operations on weak pointers.
69 /// The interface should stay the same then what we have in Referenced.
get(const SGWeakReferenced * ref)70 static unsigned get(const SGWeakReferenced* ref)
71 { if (ref) return ++(ref->mWeakData->mRefcount); else return 0; }
put(const SGWeakReferenced * ref)72 static unsigned put(const SGWeakReferenced* ref)
73 { if (ref) return --(ref->mWeakData->mRefcount); else return 0; }
count(const SGWeakReferenced * ref)74 static unsigned count(const SGWeakReferenced* ref)
75 { if (ref) return ref->mWeakData->mRefcount; else return 0; }
76
77 private:
78 /// Support for weak references, not increasing the reference count
79 /// that is done through that small helper class which holds an uncounted
80 /// reference which is zeroed out on destruction of the current object
81 class WeakData : public SGReferenced {
82 public:
WeakData(SGWeakReferenced * weakReferenced)83 WeakData(SGWeakReferenced* weakReferenced) :
84 mRefcount(0u),
85 mWeakReferenced(weakReferenced)
86 { }
87
88 template<typename T>
getPointer()89 T* getPointer()
90 {
91 // Try to increment the reference count if the count is greater
92 // then zero. Since it should only be incremented iff it is nonzero, we
93 // need to check that value and try to do an atomic test and set. If this
94 // fails, try again. The usual lockless algorithm ...
95 unsigned count;
96 do {
97 count = mRefcount;
98 if (count == 0)
99 return 0;
100 } while (!mRefcount.compareAndExchange(count, count + 1));
101 // We know that as long as the refcount is not zero, the pointer still
102 // points to valid data. So it is safe to work on it.
103 return up_cast<T>(mWeakReferenced);
104 }
105
106 SGAtomic mRefcount;
107 SGWeakReferenced* mWeakReferenced;
108
109 private:
110 WeakData(void);
111 WeakData(const WeakData&);
112 WeakData& operator=(const WeakData&);
113
114 /// Upcast in a class hierarchy with a virtual base class
115 template<class T>
116 static
117 typename std::enable_if<
118 std::is_base_of<SGVirtualWeakReferenced, T>::value,
119 T*
120 >::type
121 up_cast(SGWeakReferenced* ptr);
122
123 /// Upcast in a non-virtual class hierarchy
124 template<class T>
125 static
126 typename std::enable_if<
127 !std::is_base_of<SGVirtualWeakReferenced, T>::value,
128 T*
129 >::type
up_cast(SGWeakReferenced * ptr)130 up_cast(SGWeakReferenced* ptr)
131 {
132 return static_cast<T*>(ptr);
133 }
134 };
135
136 SGSharedPtr<WeakData> mWeakData;
137
138 template<typename T>
139 friend class SGWeakPtr;
140 };
141
142 /**
143 * Base class for all reference counted SimGear objects with virtual base
144 * classes, supporting weak references.
145 *
146 * Classes derived from this one are meant to be managed with the SGSharedPtr
147 * and SGWeakPtr classes.
148 *
149 * @code{cpp}
150 *
151 * class Base1:
152 * public virtual SGVirtualWeakReferenced
153 * {};
154 *
155 * class Base2:
156 * public virtual SGVirtualWeakReferenced
157 * {};
158 *
159 * class Derived:
160 * public Base1,
161 * public Base2
162 * {};
163 *
164 * SGSharedPtr<Derived> ptr( new Derived() );
165 * SGWeakPtr<Derived> weak_ptr( ptr );
166 * SGSharedPtr<Base1> ptr1( weak_ptr.lock() );
167 * SGSharedPtr<Base2> ptr2( weak_ptr.lock() );
168 *
169 * @endcode
170 */
171 class SGVirtualWeakReferenced:
172 public SGWeakReferenced
173 {
174 public:
~SGVirtualWeakReferenced()175 virtual ~SGVirtualWeakReferenced() {}
176 };
177
178 /// Upcast in a class hierarchy with a virtual base class
179 // We (clang) need the definition of SGVirtualWeakReferenced for the static_cast
180 template<class T>
181 typename std::enable_if<
182 std::is_base_of<SGVirtualWeakReferenced, T>::value,
183 T*
184 >::type
up_cast(SGWeakReferenced * ptr)185 SGWeakReferenced::WeakData::up_cast(SGWeakReferenced* ptr)
186 {
187 // First get the virtual base class, which then can be used to further
188 // upcast.
189 return dynamic_cast<T*>(static_cast<SGVirtualWeakReferenced*>(ptr));
190 }
191
192 #ifdef _MSC_VER
193 # pragma warning(pop)
194 #endif
195
196 #endif
197