/*------------------------------------------------------------------------- * drawElements C++ Base Library * ----------------------------- * * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief Shared pointer. *//*--------------------------------------------------------------------*/ #include "deSharedPtr.hpp" #include "deThread.hpp" #include "deClock.h" #include namespace de { namespace { enum { THREAD_TEST_TIME = 200*1000 }; class Object { public: Object (bool& exists) : m_exists(exists) { m_exists = true; } virtual ~Object (void) { m_exists = false; } private: bool& m_exists; }; class DerivedObject : public Object { public: DerivedObject (bool& exists) : Object(exists) { } }; class SharedPtrTestThread : public Thread { public: SharedPtrTestThread (const SharedPtr& ptr, const bool& exists) : m_ptr (ptr) , m_exists (exists) { } void run (void) { deUint64 startTime = deGetMicroseconds(); deUint64 cnt = 0; for (;; cnt++) { if (((cnt&(1<<14)) != 0) && (deGetMicroseconds()-startTime >= THREAD_TEST_TIME)) break; { SharedPtr ptrA(m_ptr); { SharedPtr ptrB; ptrB = ptrA; ptrA = SharedPtr(); } } DE_TEST_ASSERT(m_exists); } } private: SharedPtr m_ptr; const bool& m_exists; }; class WeakPtrTestThread : public Thread { public: WeakPtrTestThread (const SharedPtr& ptr, const bool& exists) : m_ptr (ptr) , m_exists (exists) { } void run (void) { deUint64 startTime = deGetMicroseconds(); deUint64 cnt = 0; for (;; cnt++) { if (((cnt&(1<<14)) != 0) && (deGetMicroseconds()-startTime >= THREAD_TEST_TIME)) break; { WeakPtr ptrA(m_ptr); { WeakPtr ptrB; ptrB = ptrA; ptrA = SharedPtr(); } } DE_TEST_ASSERT(m_exists); } } private: SharedPtr m_ptr; const bool& m_exists; }; SharedPtr makeObject (bool& exists) { return SharedPtr(new Object(exists)); } struct CustomDeleter { CustomDeleter (bool* called) : m_called(called) {} void operator() (Object* ptr) { DE_TEST_ASSERT(!*m_called); delete ptr; *m_called = true; } bool* m_called; }; } // anonymous void SharedPtr_selfTest (void) { // Empty pointer test. { SharedPtr ptr; DE_TEST_ASSERT(ptr.get() == DE_NULL); DE_TEST_ASSERT(!ptr); } // Empty pointer copy. { SharedPtr ptrA; SharedPtr ptrB(ptrA); DE_TEST_ASSERT(ptrB.get() == DE_NULL); } // Empty pointer assignment. { SharedPtr ptrA; SharedPtr ptrB; ptrB = ptrA; ptrB = ptrB; } // Basic test. { bool exists = false; { SharedPtr ptr(new Object(exists)); DE_TEST_ASSERT(exists); DE_TEST_ASSERT(ptr.get() != DE_NULL); DE_TEST_ASSERT(ptr); } DE_TEST_ASSERT(!exists); } // Exception test. { bool exists = false; try { SharedPtr ptr(new Object(exists)); DE_TEST_ASSERT(exists); DE_TEST_ASSERT(ptr.get() != DE_NULL); throw std::exception(); } catch (const std::exception&) { DE_TEST_ASSERT(!exists); } DE_TEST_ASSERT(!exists); } // Expression test. { bool exists = false; bool test = (SharedPtr(new Object(exists))).get() != DE_NULL && exists; DE_TEST_ASSERT(!exists); DE_TEST_ASSERT(test); } // Assignment test. { bool exists = false; SharedPtr ptr(new Object(exists)); DE_TEST_ASSERT(exists); ptr = SharedPtr(); DE_TEST_ASSERT(!exists); } // Self-assignment test. { bool exists = false; { SharedPtr ptr(new Object(exists)); DE_TEST_ASSERT(exists); DE_TEST_ASSERT(ptr.get() != DE_NULL); ptr = ptr; } DE_TEST_ASSERT(!exists); } // Basic multi-reference via copy ctor. { bool exists = false; { SharedPtr ptrA(new Object(exists)); DE_TEST_ASSERT(exists); { SharedPtr ptrB(ptrA); DE_TEST_ASSERT(exists); } DE_TEST_ASSERT(exists); } DE_TEST_ASSERT(!exists); } // Basic multi-reference via assignment to empty. { bool exists = false; { SharedPtr ptrA(new Object(exists)); DE_TEST_ASSERT(exists); { SharedPtr ptrB; ptrB = ptrA; DE_TEST_ASSERT(exists); } DE_TEST_ASSERT(exists); } DE_TEST_ASSERT(!exists); } // Multi-reference via assignment to non-empty. { bool existsA = false; bool existsB = false; { SharedPtr ptrA(new Object(existsA)); DE_TEST_ASSERT(existsA); { SharedPtr ptrB(new Object(existsB)); DE_TEST_ASSERT(existsB); ptrA = ptrB; DE_TEST_ASSERT(!existsA); DE_TEST_ASSERT(existsB); } DE_TEST_ASSERT(existsB); } DE_TEST_ASSERT(!existsB); } // Return from function. { bool exists = false; { SharedPtr ptr; ptr = makeObject(exists); DE_TEST_ASSERT(exists); } DE_TEST_ASSERT(!exists); } // Equality comparison. { bool existsA = false; bool existsB = false; SharedPtr ptrA(new Object(existsA)); SharedPtr ptrB(new Object(existsB)); SharedPtr ptrC(ptrA); DE_TEST_ASSERT(ptrA == ptrA); DE_TEST_ASSERT(ptrA != ptrB); DE_TEST_ASSERT(ptrA == ptrC); DE_TEST_ASSERT(ptrC != ptrB); } // Conversion via assignment. { bool exists = false; { SharedPtr basePtr; { SharedPtr derivedPtr(new DerivedObject(exists)); DE_TEST_ASSERT(exists); basePtr = derivedPtr; DE_TEST_ASSERT(exists); } DE_TEST_ASSERT(exists); } DE_TEST_ASSERT(!exists); } // Conversion via copy ctor. { bool exists = false; { SharedPtr derivedPtr (new DerivedObject(exists)); SharedPtr basePtr (derivedPtr); DE_TEST_ASSERT(exists); derivedPtr = SharedPtr(); DE_TEST_ASSERT(exists); } DE_TEST_ASSERT(!exists); } // Explicit conversion operator. { bool exists = false; { SharedPtr derivedPtr (new DerivedObject(exists)); DE_TEST_ASSERT(exists); SharedPtr basePtr = (SharedPtr)(derivedPtr); derivedPtr = SharedPtr(); DE_TEST_ASSERT(exists); } DE_TEST_ASSERT(!exists); } // Basic weak reference. { bool exists = false; SharedPtr ptr(new Object(exists)); DE_TEST_ASSERT(exists); WeakPtr weakPtr(ptr); try { SharedPtr newRef(weakPtr); DE_TEST_ASSERT(exists); } catch (const DeadReferenceException&) { DE_TEST_ASSERT(false); } ptr = SharedPtr(); DE_TEST_ASSERT(!exists); try { SharedPtr newRef(weakPtr); DE_TEST_ASSERT(false); } catch (const DeadReferenceException&) { } } // Basic SharedPtr threaded test. { bool exists = false; { SharedPtr ptr(new Object(exists)); SharedPtrTestThread threadA(ptr, exists); SharedPtrTestThread threadB(ptr, exists); threadA.start(); threadB.start(); threadA.join(); threadB.join(); DE_TEST_ASSERT(exists); } DE_TEST_ASSERT(!exists); } // Basic WeakPtr threaded test. { bool exists = false; { SharedPtr ptr(new Object(exists)); WeakPtrTestThread threadA(ptr, exists); WeakPtrTestThread threadB(ptr, exists); threadA.start(); threadB.start(); threadA.join(); threadB.join(); DE_TEST_ASSERT(exists); } DE_TEST_ASSERT(!exists); } // Basic custom deleter. { bool exists = false; bool deleterCalled = false; { SharedPtr ptr(new Object(exists), CustomDeleter(&deleterCalled)); DE_TEST_ASSERT(exists); DE_TEST_ASSERT(!deleterCalled); DE_TEST_ASSERT(ptr.get() != DE_NULL); } DE_TEST_ASSERT(!exists); DE_TEST_ASSERT(deleterCalled); } } } // de