/*-------------------------------------------------------------------------
* 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 <exception>
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<Object>& 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<Object> ptrA(m_ptr);
{
SharedPtr<Object> ptrB;
ptrB = ptrA;
ptrA = SharedPtr<Object>();
}
}
DE_TEST_ASSERT(m_exists);
}
}
private:
SharedPtr<Object> m_ptr;
const bool& m_exists;
};
class WeakPtrTestThread : public Thread
{
public:
WeakPtrTestThread (const SharedPtr<Object>& 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<Object> ptrA(m_ptr);
{
WeakPtr<Object> ptrB;
ptrB = ptrA;
ptrA = SharedPtr<Object>();
}
}
DE_TEST_ASSERT(m_exists);
}
}
private:
SharedPtr<Object> m_ptr;
const bool& m_exists;
};
SharedPtr<Object> makeObject (bool& exists)
{
return SharedPtr<Object>(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<Object> ptr;
DE_TEST_ASSERT(ptr.get() == DE_NULL);
DE_TEST_ASSERT(!ptr);
}
// Empty pointer copy.
{
SharedPtr<Object> ptrA;
SharedPtr<Object> ptrB(ptrA);
DE_TEST_ASSERT(ptrB.get() == DE_NULL);
}
// Empty pointer assignment.
{
SharedPtr<Object> ptrA;
SharedPtr<Object> ptrB;
ptrB = ptrA;
ptrB = ptrB;
}
// Basic test.
{
bool exists = false;
{
SharedPtr<Object> 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<Object> 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<Object>(new Object(exists))).get() != DE_NULL && exists;
DE_TEST_ASSERT(!exists);
DE_TEST_ASSERT(test);
}
// Assignment test.
{
bool exists = false;
SharedPtr<Object> ptr(new Object(exists));
DE_TEST_ASSERT(exists);
ptr = SharedPtr<Object>();
DE_TEST_ASSERT(!exists);
}
// Self-assignment test.
{
bool exists = false;
{
SharedPtr<Object> 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<Object> ptrA(new Object(exists));
DE_TEST_ASSERT(exists);
{
SharedPtr<Object> 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<Object> ptrA(new Object(exists));
DE_TEST_ASSERT(exists);
{
SharedPtr<Object> 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<Object> ptrA(new Object(existsA));
DE_TEST_ASSERT(existsA);
{
SharedPtr<Object> 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<Object> ptr;
ptr = makeObject(exists);
DE_TEST_ASSERT(exists);
}
DE_TEST_ASSERT(!exists);
}
// Equality comparison.
{
bool existsA = false;
bool existsB = false;
SharedPtr<Object> ptrA(new Object(existsA));
SharedPtr<Object> ptrB(new Object(existsB));
SharedPtr<Object> 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<Object> basePtr;
{
SharedPtr<DerivedObject> 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<DerivedObject> derivedPtr (new DerivedObject(exists));
SharedPtr<Object> basePtr (derivedPtr);
DE_TEST_ASSERT(exists);
derivedPtr = SharedPtr<DerivedObject>();
DE_TEST_ASSERT(exists);
}
DE_TEST_ASSERT(!exists);
}
// Explicit conversion operator.
{
bool exists = false;
{
SharedPtr<DerivedObject> derivedPtr (new DerivedObject(exists));
DE_TEST_ASSERT(exists);
SharedPtr<Object> basePtr = (SharedPtr<Object>)(derivedPtr);
derivedPtr = SharedPtr<DerivedObject>();
DE_TEST_ASSERT(exists);
}
DE_TEST_ASSERT(!exists);
}
// Basic weak reference.
{
bool exists = false;
SharedPtr<Object> ptr(new Object(exists));
DE_TEST_ASSERT(exists);
WeakPtr<Object> weakPtr(ptr);
try
{
SharedPtr<Object> newRef(weakPtr);
DE_TEST_ASSERT(exists);
}
catch (const DeadReferenceException&)
{
DE_TEST_ASSERT(false);
}
ptr = SharedPtr<Object>();
DE_TEST_ASSERT(!exists);
try
{
SharedPtr<Object> newRef(weakPtr);
DE_TEST_ASSERT(false);
}
catch (const DeadReferenceException&)
{
}
}
// Basic SharedPtr threaded test.
{
bool exists = false;
{
SharedPtr<Object> 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<Object> 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<Object> 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