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