1/*
2 * Copyright 2009, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
5#ifndef _WEAK_REFERENCEABLE_H
6#define _WEAK_REFERENCEABLE_H
7
8
9#include <Referenceable.h>
10
11#include <new>
12
13
14namespace BPrivate {
15
16
17class BWeakReferenceable;
18
19
20class WeakPointer : public BReferenceable {
21public:
22								WeakPointer(BWeakReferenceable* object);
23								~WeakPointer();
24
25			BWeakReferenceable*	Get();
26			bool				Put();
27
28			int32				UseCount() const;
29
30			void				GetUnchecked();
31
32private:
33			int32				fUseCount;
34			BWeakReferenceable*	fObject;
35};
36
37
38class BWeakReferenceable {
39public:
40								BWeakReferenceable();
41	virtual						~BWeakReferenceable();
42
43			status_t			InitCheck();
44
45			void				AcquireReference()
46									{ fPointer->GetUnchecked(); }
47
48			bool				ReleaseReference()
49									{ return fPointer->Put(); }
50
51			int32				CountReferences() const
52									{ return fPointer->UseCount(); }
53
54			WeakPointer*		GetWeakPointer();
55private:
56			WeakPointer*		fPointer;
57};
58
59
60template<typename Type>
61class BWeakReference {
62public:
63	BWeakReference()
64		:
65		fPointer(NULL)
66	{
67	}
68
69	BWeakReference(Type* object)
70		:
71		fPointer(NULL)
72	{
73		SetTo(object);
74	}
75
76	BWeakReference(const BWeakReference<Type>& other)
77		:
78		fPointer(NULL)
79	{
80		SetTo(other);
81	}
82
83	BWeakReference(const BReference<Type>& other)
84		:
85		fPointer(NULL)
86	{
87		SetTo(other);
88	}
89
90	template<typename OtherType>
91	BWeakReference(const BReference<OtherType>& other)
92		:
93		fPointer(NULL)
94	{
95		SetTo(other.Get());
96	}
97
98	template<typename OtherType>
99	BWeakReference(const BWeakReference<OtherType>& other)
100		:
101		fPointer(NULL)
102	{
103		SetTo(other);
104	}
105
106	~BWeakReference()
107	{
108		Unset();
109	}
110
111	void SetTo(Type* object)
112	{
113		Unset();
114
115		if (object != NULL)
116			fPointer = object->GetWeakPointer();
117	}
118
119	void SetTo(const BWeakReference<Type>& other)
120	{
121		Unset();
122
123		if (other.fPointer) {
124			fPointer = other.fPointer;
125			fPointer->AcquireReference();
126		}
127	}
128
129	template<typename OtherType>
130	void SetTo(const BWeakReference<OtherType>& other)
131	{
132		// Just a compiler check if the types are compatible.
133		OtherType* otherDummy = NULL;
134		Type* dummy = otherDummy;
135		dummy = NULL;
136
137		Unset();
138
139		if (other.PrivatePointer()) {
140			fPointer = const_cast<WeakPointer*>(other.PrivatePointer());
141			fPointer->AcquireReference();
142		}
143	}
144
145	void SetTo(const BReference<Type>& other)
146	{
147		SetTo(other.Get());
148	}
149
150	void Unset()
151	{
152		if (fPointer != NULL) {
153			fPointer->ReleaseReference();
154			fPointer = NULL;
155		}
156	}
157
158	bool IsAlive()
159	{
160		if (fPointer == NULL)
161			return false;
162		Type* object = static_cast<Type*>(fPointer->Get());
163		if (object == NULL)
164			return false;
165		fPointer->Put();
166		return true;
167	}
168
169	BReference<Type> GetReference()
170	{
171		Type* object = static_cast<Type*>(fPointer->Get());
172		return BReference<Type>(object, true);
173	}
174
175	BWeakReference& operator=(const BWeakReference<Type>& other)
176	{
177		if (this == &other)
178			return *this;
179
180		SetTo(other);
181		return *this;
182	}
183
184	BWeakReference& operator=(Type* other)
185	{
186		SetTo(other);
187		return *this;
188	}
189
190	BWeakReference& operator=(const BReference<Type>& other)
191	{
192		SetTo(other.Get());
193		return *this;
194	}
195
196	template<typename OtherType>
197	BWeakReference& operator=(const BReference<OtherType>& other)
198	{
199		SetTo(other.Get());
200		return *this;
201	}
202
203	template<typename OtherType>
204	BWeakReference& operator=(const BWeakReference<OtherType>& other)
205	{
206		SetTo(other);
207		return *this;
208	}
209
210	bool operator==(const BWeakReference<Type>& other) const
211	{
212		return fPointer == other.fPointer;
213	}
214
215	bool operator!=(const BWeakReference<Type>& other) const
216	{
217		return fPointer != other.fPointer;
218	}
219
220	/*!	Do not use this if you do not know what you are doing. The WeakPointer
221		is for internal use only.
222	*/
223	const WeakPointer* PrivatePointer() const
224	{
225		return fPointer;
226	}
227
228private:
229	WeakPointer*	fPointer;
230};
231
232
233//	#pragma mark -
234
235
236inline
237WeakPointer::WeakPointer(BWeakReferenceable* object)
238	:
239	fUseCount(1),
240	fObject(object)
241{
242}
243
244
245inline
246WeakPointer::~WeakPointer()
247{
248}
249
250
251inline BWeakReferenceable*
252WeakPointer::Get()
253{
254	int32 count = -11;
255
256	do {
257		count = atomic_get(&fUseCount);
258		if (count == 0)
259			return NULL;
260	} while (atomic_test_and_set(&fUseCount, count + 1, count) != count);
261
262	return fObject;
263}
264
265
266inline bool
267WeakPointer::Put()
268{
269	if (atomic_add(&fUseCount, -1) == 1) {
270		delete fObject;
271		return true;
272	}
273
274	return false;
275}
276
277
278inline int32
279WeakPointer::UseCount() const
280{
281	return fUseCount;
282}
283
284
285inline void
286WeakPointer::GetUnchecked()
287{
288	atomic_add(&fUseCount, 1);
289}
290
291
292//	#pragma -
293
294
295inline
296BWeakReferenceable::BWeakReferenceable()
297	:
298	fPointer(new(std::nothrow) WeakPointer(this))
299{
300}
301
302
303inline
304BWeakReferenceable::~BWeakReferenceable()
305{
306	fPointer->ReleaseReference();
307}
308
309
310inline status_t
311BWeakReferenceable::InitCheck()
312{
313	if (fPointer == NULL)
314		return B_NO_MEMORY;
315	return B_OK;
316}
317
318
319inline WeakPointer*
320BWeakReferenceable::GetWeakPointer()
321{
322	fPointer->AcquireReference();
323	return fPointer;
324}
325
326}	// namespace BPrivate
327
328using BPrivate::BWeakReferenceable;
329using BPrivate::BWeakReference;
330
331#endif	// _WEAK_REFERENCEABLE_H
332