1/*-------------------------------------------------------------------------
2 * drawElements C++ Base Library
3 * -----------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Shared pointer.
22 *//*--------------------------------------------------------------------*/
23
24#include "deSharedPtr.hpp"
25#include "deThread.hpp"
26#include "deClock.h"
27
28#include <exception>
29
30namespace de
31{
32
33namespace
34{
35
36enum
37{
38	THREAD_TEST_TIME = 200*1000
39};
40
41class Object
42{
43public:
44	Object (bool& exists)
45		: m_exists(exists)
46	{
47		m_exists = true;
48	}
49
50	virtual ~Object (void)
51	{
52		m_exists = false;
53	}
54
55private:
56	bool& m_exists;
57};
58
59class DerivedObject : public Object
60{
61public:
62	DerivedObject (bool& exists)
63		: Object(exists)
64	{
65	}
66};
67
68class SharedPtrTestThread : public Thread
69{
70public:
71	SharedPtrTestThread (const SharedPtr<Object>& ptr, const bool& exists)
72		: m_ptr		(ptr)
73		, m_exists	(exists)
74	{
75	}
76
77	void run (void)
78	{
79		deUint64 startTime	= deGetMicroseconds();
80		deUint64 cnt		= 0;
81
82		for (;; cnt++)
83		{
84			if (((cnt&(1<<14)) != 0) && (deGetMicroseconds()-startTime >= THREAD_TEST_TIME))
85				break;
86
87			{
88				SharedPtr<Object> ptrA(m_ptr);
89				{
90					SharedPtr<Object> ptrB;
91					ptrB = ptrA;
92					ptrA = SharedPtr<Object>();
93				}
94			}
95			DE_TEST_ASSERT(m_exists);
96		}
97	}
98
99private:
100	SharedPtr<Object>	m_ptr;
101	const bool&			m_exists;
102};
103
104class WeakPtrTestThread : public Thread
105{
106public:
107	WeakPtrTestThread (const SharedPtr<Object>& ptr, const bool& exists)
108		: m_ptr		(ptr)
109		, m_exists	(exists)
110	{
111	}
112
113	void run (void)
114	{
115		deUint64 startTime	= deGetMicroseconds();
116		deUint64 cnt		= 0;
117
118		for (;; cnt++)
119		{
120			if (((cnt&(1<<14)) != 0) && (deGetMicroseconds()-startTime >= THREAD_TEST_TIME))
121				break;
122
123			{
124				WeakPtr<Object> ptrA(m_ptr);
125				{
126					WeakPtr<Object> ptrB;
127					ptrB = ptrA;
128					ptrA = SharedPtr<Object>();
129				}
130			}
131			DE_TEST_ASSERT(m_exists);
132		}
133	}
134
135private:
136	SharedPtr<Object>	m_ptr;
137	const bool&			m_exists;
138};
139
140SharedPtr<Object> makeObject (bool& exists)
141{
142	return SharedPtr<Object>(new Object(exists));
143}
144
145struct CustomDeleter
146{
147	CustomDeleter (bool* called) : m_called(called) {}
148
149	void operator() (Object* ptr)
150	{
151		DE_TEST_ASSERT(!*m_called);
152		delete ptr;
153		*m_called = true;
154	}
155
156	bool* m_called;
157};
158
159} // anonymous
160
161void SharedPtr_selfTest (void)
162{
163	// Empty pointer test.
164	{
165		SharedPtr<Object> ptr;
166		DE_TEST_ASSERT(ptr.get() == DE_NULL);
167		DE_TEST_ASSERT(!ptr);
168	}
169
170	// Empty pointer copy.
171	{
172		SharedPtr<Object> ptrA;
173		SharedPtr<Object> ptrB(ptrA);
174		DE_TEST_ASSERT(ptrB.get() == DE_NULL);
175	}
176
177	// Empty pointer assignment.
178	{
179		SharedPtr<Object> ptrA;
180		SharedPtr<Object> ptrB;
181		ptrB = ptrA;
182		ptrB = ptrB;
183	}
184
185	// Basic test.
186	{
187		bool exists = false;
188		{
189			SharedPtr<Object> ptr(new Object(exists));
190			DE_TEST_ASSERT(exists);
191			DE_TEST_ASSERT(ptr.get() != DE_NULL);
192			DE_TEST_ASSERT(ptr);
193		}
194		DE_TEST_ASSERT(!exists);
195	}
196
197	// Exception test.
198	{
199		bool exists = false;
200		try
201		{
202			SharedPtr<Object> ptr(new Object(exists));
203			DE_TEST_ASSERT(exists);
204			DE_TEST_ASSERT(ptr.get() != DE_NULL);
205			throw std::exception();
206		}
207		catch (const std::exception&)
208		{
209			DE_TEST_ASSERT(!exists);
210		}
211		DE_TEST_ASSERT(!exists);
212	}
213
214	// Expression test.
215	{
216		bool exists = false;
217		bool test	= (SharedPtr<Object>(new Object(exists))).get() != DE_NULL && exists;
218		DE_TEST_ASSERT(!exists);
219		DE_TEST_ASSERT(test);
220	}
221
222	// Assignment test.
223	{
224		bool exists = false;
225		SharedPtr<Object> ptr(new Object(exists));
226		DE_TEST_ASSERT(exists);
227		ptr = SharedPtr<Object>();
228		DE_TEST_ASSERT(!exists);
229	}
230
231	// Self-assignment test.
232	{
233		bool exists = false;
234		{
235			SharedPtr<Object> ptr(new Object(exists));
236			DE_TEST_ASSERT(exists);
237			DE_TEST_ASSERT(ptr.get() != DE_NULL);
238			ptr = ptr;
239		}
240		DE_TEST_ASSERT(!exists);
241	}
242
243	// Basic multi-reference via copy ctor.
244	{
245		bool exists = false;
246		{
247			SharedPtr<Object> ptrA(new Object(exists));
248			DE_TEST_ASSERT(exists);
249			{
250				SharedPtr<Object> ptrB(ptrA);
251				DE_TEST_ASSERT(exists);
252			}
253			DE_TEST_ASSERT(exists);
254		}
255		DE_TEST_ASSERT(!exists);
256	}
257
258	// Basic multi-reference via assignment to empty.
259	{
260		bool exists = false;
261		{
262			SharedPtr<Object> ptrA(new Object(exists));
263			DE_TEST_ASSERT(exists);
264			{
265				SharedPtr<Object> ptrB;
266				ptrB = ptrA;
267				DE_TEST_ASSERT(exists);
268			}
269			DE_TEST_ASSERT(exists);
270		}
271		DE_TEST_ASSERT(!exists);
272	}
273
274	// Multi-reference via assignment to non-empty.
275	{
276		bool existsA = false;
277		bool existsB = false;
278		{
279			SharedPtr<Object> ptrA(new Object(existsA));
280			DE_TEST_ASSERT(existsA);
281			{
282				SharedPtr<Object> ptrB(new Object(existsB));
283				DE_TEST_ASSERT(existsB);
284				ptrA = ptrB;
285				DE_TEST_ASSERT(!existsA);
286				DE_TEST_ASSERT(existsB);
287			}
288			DE_TEST_ASSERT(existsB);
289		}
290		DE_TEST_ASSERT(!existsB);
291	}
292
293	// Return from function.
294	{
295		bool exists = false;
296		{
297			SharedPtr<Object> ptr;
298			ptr = makeObject(exists);
299			DE_TEST_ASSERT(exists);
300		}
301		DE_TEST_ASSERT(!exists);
302	}
303
304	// Equality comparison.
305	{
306		bool existsA = false;
307		bool existsB = false;
308		SharedPtr<Object> ptrA(new Object(existsA));
309		SharedPtr<Object> ptrB(new Object(existsB));
310		SharedPtr<Object> ptrC(ptrA);
311
312		DE_TEST_ASSERT(ptrA == ptrA);
313		DE_TEST_ASSERT(ptrA != ptrB);
314		DE_TEST_ASSERT(ptrA == ptrC);
315		DE_TEST_ASSERT(ptrC != ptrB);
316	}
317
318	// Conversion via assignment.
319	{
320		bool exists = false;
321		{
322			SharedPtr<Object> basePtr;
323			{
324				SharedPtr<DerivedObject> derivedPtr(new DerivedObject(exists));
325				DE_TEST_ASSERT(exists);
326				basePtr = derivedPtr;
327				DE_TEST_ASSERT(exists);
328			}
329			DE_TEST_ASSERT(exists);
330		}
331		DE_TEST_ASSERT(!exists);
332	}
333
334	// Conversion via copy ctor.
335	{
336		bool exists = false;
337		{
338			SharedPtr<DerivedObject>	derivedPtr	(new DerivedObject(exists));
339			SharedPtr<Object>			basePtr		(derivedPtr);
340			DE_TEST_ASSERT(exists);
341			derivedPtr = SharedPtr<DerivedObject>();
342			DE_TEST_ASSERT(exists);
343		}
344		DE_TEST_ASSERT(!exists);
345	}
346
347	// Explicit conversion operator.
348	{
349		bool exists = false;
350		{
351			SharedPtr<DerivedObject> derivedPtr (new DerivedObject(exists));
352			DE_TEST_ASSERT(exists);
353
354			SharedPtr<Object> basePtr = (SharedPtr<Object>)(derivedPtr);
355			derivedPtr = SharedPtr<DerivedObject>();
356			DE_TEST_ASSERT(exists);
357		}
358		DE_TEST_ASSERT(!exists);
359	}
360
361	// Basic weak reference.
362	{
363		bool exists = false;
364		SharedPtr<Object> ptr(new Object(exists));
365		DE_TEST_ASSERT(exists);
366
367		WeakPtr<Object> weakPtr(ptr);
368		try
369		{
370			SharedPtr<Object> newRef(weakPtr);
371			DE_TEST_ASSERT(exists);
372		}
373		catch (const DeadReferenceException&)
374		{
375			DE_TEST_ASSERT(false);
376		}
377
378		ptr = SharedPtr<Object>();
379		DE_TEST_ASSERT(!exists);
380		try
381		{
382			SharedPtr<Object> newRef(weakPtr);
383			DE_TEST_ASSERT(false);
384		}
385		catch (const DeadReferenceException&)
386		{
387		}
388	}
389
390	// Basic SharedPtr threaded test.
391	{
392		bool exists = false;
393		{
394			SharedPtr<Object> ptr(new Object(exists));
395
396			SharedPtrTestThread threadA(ptr, exists);
397			SharedPtrTestThread threadB(ptr, exists);
398
399			threadA.start();
400			threadB.start();
401
402			threadA.join();
403			threadB.join();
404			DE_TEST_ASSERT(exists);
405		}
406		DE_TEST_ASSERT(!exists);
407	}
408
409	// Basic WeakPtr threaded test.
410	{
411		bool exists = false;
412		{
413			SharedPtr<Object> ptr(new Object(exists));
414			WeakPtrTestThread threadA(ptr, exists);
415			WeakPtrTestThread threadB(ptr, exists);
416
417			threadA.start();
418			threadB.start();
419
420			threadA.join();
421			threadB.join();
422			DE_TEST_ASSERT(exists);
423		}
424		DE_TEST_ASSERT(!exists);
425	}
426
427	// Basic custom deleter.
428	{
429		bool exists = false;
430		bool deleterCalled = false;
431		{
432			SharedPtr<Object, CustomDeleter> ptr(new Object(exists), CustomDeleter(&deleterCalled));
433			DE_TEST_ASSERT(exists);
434			DE_TEST_ASSERT(!deleterCalled);
435			DE_TEST_ASSERT(ptr.get() != DE_NULL);
436		}
437		DE_TEST_ASSERT(!exists);
438		DE_TEST_ASSERT(deleterCalled);
439	}
440}
441
442} // de
443