text: /////////////////////////////////////////////////////////////////////////////
  // Copyright (c) Electronic Arts Inc. All rights reserved.
  /////////////////////////////////////////////////////////////////////////////
  
  
  #include <EABase/eabase.h>
  #include "EASTLTest.h"
  #include "GetTypeName.h"
  #include <EAStdC/EAString.h>
  #include <EAStdC/EAStopwatch.h>
  #include <EASTL/core_allocator_adapter.h>
  #include <EASTL/core_allocator.h>
  #include <EASTL/intrusive_ptr.h>
  #include <EASTL/linked_array.h>
  #include <EASTL/linked_ptr.h>
  #include <EASTL/safe_ptr.h>
  #include <EASTL/scoped_array.h>
  #include <EASTL/scoped_ptr.h>
  #include <EASTL/shared_array.h>
  #include <EASTL/shared_ptr.h>
  #include <EASTL/unique_ptr.h>
  #include <EASTL/weak_ptr.h>
  #include <eathread/eathread_thread.h>
  
  EA_DISABLE_ALL_VC_WARNINGS()
  #include <stdio.h>
  #include <string.h>
  #ifdef EA_PLATFORM_WINDOWS
  	#ifndef WIN32_LEAN_AND_MEAN
  		#define WIN32_LEAN_AND_MEAN
  	#endif
  	#include <Windows.h>
  #elif defined(EA_PLATFORM_ANDROID)
  	#include <android/log.h>
  #endif
  EA_RESTORE_ALL_VC_WARNINGS()
  
  EA_DISABLE_VC_WARNING(4702 4800)  // 4702: unreachable code
  								  // 4800: forcing value to bool 'true' or 'false'
  
  
  
  namespace SmartPtrTest
  {
  	/// CustomDeleter
  	///
  	/// Used for testing unique_ptr deleter overrides. Otherwise acts the same as the default deleter.
  	///
  	struct CustomDeleter
  	{
  		template <typename T>
  		void operator()(const T* p) const // We use a const argument type in order to be most flexible with what types we accept. 
  			{ delete const_cast<T*>(p); }
  
  		CustomDeleter() {}
  		CustomDeleter(const CustomDeleter&) {}
  		CustomDeleter(CustomDeleter&&) {}
  		CustomDeleter& operator=(const CustomDeleter&) { return *this; }
  		CustomDeleter& operator=(CustomDeleter&&) { return *this; }
  	};
  
  
  	struct CustomArrayDeleter
  	{
  		template <typename T>
  		void operator()(const T* p) const // We use a const argument type in order to be most flexible with what types we accept. 
  			{ delete[] const_cast<T*>(p); }
  
  		CustomArrayDeleter() {}
  		CustomArrayDeleter(const CustomArrayDeleter&) {}
  		CustomArrayDeleter(CustomArrayDeleter&&) {}
  		CustomArrayDeleter& operator=(const CustomArrayDeleter&) { return *this; }
  		CustomArrayDeleter& operator=(CustomArrayDeleter&&) { return *this; }
  	};
  
  
  	/// A
  	///
  	/// This is used for various tests. 
  	///
  	struct A
  	{
  		char mc;
  		static int mCount;
  
  		A(char c = 0) 
  			: mc(c) { ++mCount; }
  
  		A(const A& x) 
  			: mc(x.mc) { ++mCount; }
  
  		A& operator=(const A& x) 
  			{ mc = x.mc; return *this; }
  
  		virtual ~A() // Virtual because we subclass A below.
  			{ --mCount; }
  	};
  
  
  	int A::mCount = 0;
  
  
  	/// B
  	///
  	struct B : public A
  	{
  	};
  
  
  
  	/// RefCountTest
  	///
  	/// This is used for tests involving intrusive_ptr.
  	/// 
  	struct RefCountTest
  	{
  		int mRefCount;
  		static int mCount;
  
  		RefCountTest()
  			: mRefCount(0) { ++mCount; }
  
  		RefCountTest(const RefCountTest&)
  			: mRefCount(0) { ++mCount; }
  
  		RefCountTest& operator=(const RefCountTest&)
  			{ return *this; }
  
  		virtual ~RefCountTest()
  			{ --mCount; }
  
  		virtual int AddRef()
  			{ return (int)((mRefCount++) + 1); }
  
  		virtual int Release()
  		{
  			int rc = (int)((mRefCount--) - 1);
  			if(rc)
  				return rc;
  			mRefCount = 1;
  			delete this;
  			return 0;
  		}
  	};
  
  	int RefCountTest::mCount = 0;
  
  
  
  	/// Test
  	///
  	/// This is used for tests involving intrusive_ptr.
  	/// 
  	struct Test : public RefCountTest
  	{
  		bool* mpBool;
  
  		Test(bool* pBool)
  			: mpBool(pBool) { *pBool = true; }
  
  		Test(const Test& x): 
  			RefCountTest(x), mpBool(x.mpBool) { }
  
  		Test& operator=(const Test& x)
  			{ mpBool = x.mpBool; return *this; }
  
  	   ~Test()
  			{ *mpBool = false; }
  	};
  
  
  
  	/// IntrusiveParent / IntrusiveChild
  	///
  	/// This is used for tests involving intrusive_ptr.
  	/// 
  	struct IntrusiveParent : public RefCountTest
  	{
  	};
  
  	struct IntrusiveChild : public IntrusiveParent
  	{
  	};
  
  
  	/// intrusive_ptr_add_ref / intrusive_ptr_release
  	///
  	/// This is used for tests involving intrusive_ptr.
  	/// 
  	struct IntrusiveCustom : public RefCountTest
  	{
  		static int mAddRefCallCount;
  		static int mReleaseCallCount;
  
  		virtual int AddRef()
  		{
  			++mAddRefCallCount;
  			return RefCountTest::AddRef();
  		}
  
  		virtual int Release()
  		{
  			++mReleaseCallCount;
  			return RefCountTest::Release();
  		}
  	};
  
  	int IntrusiveCustom::mAddRefCallCount  = 0;
  	int IntrusiveCustom::mReleaseCallCount = 0;
  
  	void intrusive_ptr_add_ref(IntrusiveCustom* p)
  	{
  		p->AddRef();
  	}
  	 
  	void intrusive_ptr_release(IntrusiveCustom* p)
  	{
  		p->Release();
  	}
  
  
  	/// ParentClass / ChildClass / GrandChildClass
  	///
  	/// This is used for tests involving shared_ptr.
  	/// 
  	struct ParentClass
  	{
  		virtual ~ParentClass() { }
  		virtual void DoNothingParentClass() { }
  	};
  
  	struct ChildClass : public ParentClass
  	{
  		virtual void DoNothingChildClass() { }
  	};
  
  	struct GrandChildClass : public ChildClass
  	{
  		virtual void DoNothingGrandChildClass() { }
  	};
  
  
  
  	/// NamedClass
  	///
  	struct NamedClass
  	{
  		const char* mpName;
  		const char* mpName2;
  		static int  mnCount;
  
  		NamedClass(const char* pName = NULL)
  			: mpName(pName), mpName2(NULL) { ++mnCount; }
  
  		NamedClass(const char* pName, const char* pName2)
  			: mpName(pName), mpName2(pName2) { ++mnCount; }
  
  		NamedClass(const NamedClass& x)
  			: mpName(x.mpName), mpName2(x.mpName2) { ++mnCount; }
  
  		NamedClass& operator=(const NamedClass& x)
  			{ mpName = x.mpName; mpName2 = x.mpName2; return *this; }
  
  	   ~NamedClass()
  			{ --mnCount; }
  	};
  
  	int NamedClass::mnCount = 0;
  
  
  
  	/// Y
  	///
  	/// This is used for tests involving shared_ptr and enabled_shared_from_this.
  	/// 
  	struct Y : public eastl::enable_shared_from_this<Y>
  	{
  		static int mnCount;
  
  		Y() { ++mnCount; }
  		Y(const Y&) { ++mnCount; }
  		Y& operator=(const Y&) { return *this; }
  	   ~Y() { --mnCount; }
  
  		eastl::shared_ptr<Y> f()
  			{ return shared_from_this(); }
  	};
  
  	int Y::mnCount = 0;
  
  
  
  	/// ACLS / BCLS
  	///
  	/// This is used for tests involving shared_ptr.
  	/// 
  	class ACLS : public eastl::enable_shared_from_this<ACLS>
  	{
  	public:
  		static int mnCount;
  		int a;
  
  		ACLS(int _a_ = 0) : a(_a_) { ++mnCount; }
  		ACLS(const ACLS& x) : a(x.a) { ++mnCount; }
  		ACLS& operator=(const ACLS& x) { a = x.a; return *this; }
  	   ~ACLS() { --mnCount; }
  	};
  
  	int ACLS::mnCount = 0;
  
  
  	class BCLS : public ACLS
  	{
  	public:
  		static int mnCount;
  		int b;
  
  		BCLS(int _b_ = 0) : b(_b_) { ++mnCount; }
  		BCLS(const BCLS& x) : ACLS(x), b(x.b) { ++mnCount; }
  		BCLS& operator=(const BCLS& x) { b = x.b; ACLS::operator=(x); return *this; }
  	   ~BCLS() { --mnCount; }
  	};
  
  	int BCLS::mnCount = 0;
  
  
  
  	/// A1 / B1
  	///
  	/// This is used for tests involving shared_ptr.
  	/// 
  	struct A1
  	{
  		static int mnCount;
  		int a;
  
  		A1(int _a_ = 0) : a(_a_) { ++mnCount; }
  		A1(const A1& x) : a(x.a) { ++mnCount; }
  		A1& operator=(const A1& x) { a = x.a; return *this; }
  	   ~A1() { --mnCount; }
  	};
  
  	int A1::mnCount = 0;
  
  
  
  	struct B1 : public A1
  	{
  		static int mnCount;
  		int b;
  
  		B1(int _b_ = 0) : b(_b_) { ++mnCount; }
  		B1(const B1& x) : A1(x), b(x.b) { ++mnCount; }
  		B1& operator=(const B1& x) { b = x.b; A1::operator=(x); return *this; }
  	   ~B1() { --mnCount; }
  	};
  
  	int B1::mnCount = 0;
  
  
  
  	class MockObject
  	{
  	public:
  		MockObject(bool* pAlloc) 
  		  : mpAlloc(pAlloc){ *mpAlloc = true; }
  
  	   ~MockObject()
  			{ *mpAlloc = false; }
  
  		bool IsAllocated() const
  			{ return *mpAlloc; }
  
  		bool* GetAllocPtr() const
  			{ return mpAlloc; }
  
  	private:
  		bool* mpAlloc;
  	};
  
  	class DerivedMockObject : public MockObject
  	{
  	public:
  		DerivedMockObject(bool* pAlloc)
  		  : MockObject(pAlloc) {}
  	};
  
  
  	struct foo : public eastl::enable_shared_from_this<foo>
  	{
  		foo() : mX(0){}
  		int mX;
  	};
  
  } // namespace SmartPtrTest
  
  
  
  
  static int Test_unique_ptr()
  {
  	using namespace SmartPtrTest;
  	using namespace eastl;
  
  	int nErrorCount(0);
  
  	{
  		EATEST_VERIFY(A::mCount == 0);
  
  		// explicit unique_ptr(pointer pValue) noexcept
  		unique_ptr<int> pT1(new int(5));
  		EATEST_VERIFY(*pT1 == 5);
  
  		// (reference) operator*() const
  		*pT1 = 3;
  		EATEST_VERIFY(*pT1 == 3);
  
  		// explicit unique_ptr(pointer pValue) noexcept
  		unique_ptr<A> pT2(new A(1));
  		EATEST_VERIFY(pT2->mc == 1);
  		EATEST_VERIFY(A::mCount == 1);
  
  		// Pointers of derived types are allowed (unlike array unique_ptr) 
  		unique_ptr<A> pT1B(new B);
  		EATEST_VERIFY(pT1B.get() != NULL);
  		EATEST_VERIFY(A::mCount == 2);
  
  		A* pA = pT1B.release(); // release simply forgets the owned pointer.
  		EATEST_VERIFY(pT1B.get() == NULL);
  		EATEST_VERIFY(A::mCount == 2);
  
  		delete pA;
  		EATEST_VERIFY(A::mCount == 1);
  
  		// pointer operator->() const noexcept
  		pT2->mc = 5;
  		EATEST_VERIFY(pT2.get()->mc == 5);
  
  		// void reset(pointer pValue = pointer()) noexcept
  		pT2.reset(new A(2));
  		EATEST_VERIFY(pT2->mc == 2);
  		EATEST_VERIFY(A::mCount == 1);
  
  		pT2.reset(0);
  		EATEST_VERIFY(pT2.get() == (A*)0);
  		EATEST_VERIFY(A::mCount == 0);
  
  		pT2.reset(new A(3));
  		EATEST_VERIFY(pT2->mc == 3);
  		EATEST_VERIFY(A::mCount == 1);
  
  		unique_ptr<A> pT3(new A(4));
  		EATEST_VERIFY(pT3->mc == 4);
  		EATEST_VERIFY(A::mCount == 2);
  
  		// void swap(this_type& scopedPtr) noexcept
  		pT2.swap(pT3);
  		EATEST_VERIFY(pT2->mc == 4);
  		EATEST_VERIFY(pT3->mc == 3);
  		EATEST_VERIFY(A::mCount == 2);
  
  		// void swap(unique_ptr<T, D>& scopedPtr1, unique_ptr<T, D>& scopedPtr2) noexcept
  		swap(pT2, pT3);
  		EATEST_VERIFY(pT2->mc == 3);
  		EATEST_VERIFY(pT3->mc == 4);
  		EATEST_VERIFY((pT2 < pT3) == (pT2.get() < pT3.get()));
  		EATEST_VERIFY(A::mCount == 2);
  
  		// pointer release() noexcept
  		unique_ptr<A> pRelease(new A);
  		EATEST_VERIFY(A::mCount == 3);
  		pA = pRelease.release();
  		delete pA;
  		EATEST_VERIFY(A::mCount == 2);
  
  		// constexpr unique_ptr() noexcept
  		unique_ptr<A> pT4;
  		EATEST_VERIFY(pT4.get() == (A*)0);
  		if(pT4)
  			EATEST_VERIFY(pT4.get()); // Will fail
  		if(!(!pT4))
  			EATEST_VERIFY(pT4.get()); // Will fail
  
  		pT4.reset(new A(0));
  		if(!pT4)
  			EATEST_VERIFY(!pT4.get()); // Will fail
  
  		EATEST_VERIFY(A::mCount == 3);
  
  		// unique_ptr(nullptr_t) noexcept
  		unique_ptr<A> pT5(nullptr);
  		EATEST_VERIFY(pT5.get() == (A*)0);
  
  		// unique_ptr(pointer pValue, deleter) noexcept
  		CustomDeleter customADeleter;
  		unique_ptr<A, CustomDeleter> pT6(new A(17), customADeleter);
  		EATEST_VERIFY(pT6->mc == 17);
  
  		// unique_ptr(pointer pValue, typename eastl::remove_reference<Deleter>::type&& deleter) noexcept
  		unique_ptr<A, CustomDeleter> pT7(new A(18), CustomDeleter());
  		EATEST_VERIFY(pT7->mc == 18);
  
  		// unique_ptr(this_type&& x) noexcept
  		unique_ptr<A, CustomDeleter> pT8(eastl::move(pT7));
  		EATEST_VERIFY(pT8->mc == 18);
  
  		// unique_ptr(unique_ptr<U, E>&& u, ...)
  		unique_ptr<A, default_delete<A> > pT9(eastl::move(pT2));
  
  		// this_type& operator=(this_type&& u) noexcept
  		// operator=(unique_ptr<U, E>&& u) noexcept
  		//unique_ptr<void, CustomDeleter> pTVoid;
  		//unique_ptr<int, CustomDeleter>  pTInt(new int(1));
  		//pTVoid.operator=<int, CustomDeleter>(eastl::move(pTInt));  // This doesn't work because CustomDeleter doesn't know how to delete void*. Need to rework this test.
  
  		// this_type& operator=(nullptr_t) noexcept
  		pT6 = nullptr;
  		EATEST_VERIFY(pT6.get() == (A*)0);
  
  		// user reported regression
  		// ensure a unique_ptr containing nullptr doesn't call the deleter when its destroyed.
  		{
  			static bool sLocalDeleterCalled;
  			sLocalDeleterCalled = false;
  
  			struct LocalDeleter
  			{
  				void operator()(int* p) const
  				{
  					sLocalDeleterCalled = true;
  					delete p;
  				}
  			};
  
  			using local_unique_ptr = eastl::unique_ptr<int, LocalDeleter>;
  
  			local_unique_ptr pEmpty{nullptr};
  
  			pEmpty = local_unique_ptr{new int(42), LocalDeleter()};
  
  			EATEST_VERIFY(sLocalDeleterCalled == false);
  		}
  	}
  
  	{
  		#if EASTL_CORE_ALLOCATOR_ENABLED
  			// Test EA::Allocator::EASTLICoreDeleter usage within eastl::shared_ptr.
  			// http://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr
  
  			// Consider the following for standards compliance.
  			// eastl::shared_ptr<A, EASTLCoreDeleterAdapter> foo(pA, EASTLCoreDeleterAdapter());
  
  			const int cacheAllocationCount = gEASTLTest_AllocationCount;
  
  			using namespace EA::Allocator;
  
  			EASTLCoreAllocatorAdapter ta;
  			void* pMem = ta.allocate(sizeof(A));
  
  			EATEST_VERIFY(pMem != nullptr);     
  			EATEST_VERIFY(gEASTLTest_AllocationCount > cacheAllocationCount);
  			{            
  				A* pA = new (pMem) A();
  				eastl::shared_ptr<A> foo(pA, EASTLCoreDeleterAdapter());  // Not standards complaint code.  Update EASTL implementation to provide the type of the deleter.
  			}
  			EATEST_VERIFY(gEASTLTest_AllocationCount == cacheAllocationCount);
  			EATEST_VERIFY(A::mCount == 0);
  		#endif
  	}
  
  	{
  		// Test array specialization of unique_ptr
  
  		EATEST_VERIFY(A::mCount == 0);
  
  		// template <typename P>
  		// explicit unique_ptr(P pValue) noexcept
  		unique_ptr<int[]> pT1(new int[5]);
  		pT1[0] = 5;
  		EATEST_VERIFY(pT1[0] == 5);
  
  		// Arrays of derived types are not allowed (unlike regular unique_ptr) 
  		// unique_ptr<A[]> pT1B(new B[5]); // Disabled because it should not compile.
  
  		// (reference) operator[]() const
  		pT1[1] = 1;
  		EATEST_VERIFY(pT1[1] == 1);
  
  		// explicit unique_ptr(pointer pValue) noexcept
  		unique_ptr<A[]> pT2(new A[1]);
  		pT2[0].mc = 1;
  		EATEST_VERIFY(pT2[0].mc == 1);
  		EATEST_VERIFY(A::mCount == 1);
  
  		// pointer operator->() const noexcept
  		pT2[0].mc = 5;
  		EATEST_VERIFY(pT2[0].mc == 5);
  
  		// void reset(pointer pValue = pointer()) noexcept
  		pT2.reset(new A[2]);
  		pT2[0].mc = 2;
  		EATEST_VERIFY(pT2[0].mc == 2);
  
  		pT2.reset(0);
  		EATEST_VERIFY(pT2.get() == (A*)0);
  
  		pT2.reset(new A[3]);
  		pT2[0].mc = 3;
  		EATEST_VERIFY(pT2[0].mc == 3);
  
  		unique_ptr<A[]> pT3(new A[4]);
  		pT3[0].mc = 4;
  		EATEST_VERIFY(pT3[0].mc == 4);
  
  		// void swap(this_type& scopedPtr) noexcept
  		pT2.swap(pT3);
  		EATEST_VERIFY(pT2[0].mc == 4);
  		EATEST_VERIFY(pT3[0].mc == 3);
  
  		// void swap(unique_ptr<T, D>& scopedPtr1, unique_ptr<T, D>& scopedPtr2) noexcept
  		swap(pT2, pT3);
  		EATEST_VERIFY(pT2[0].mc == 3);
  		EATEST_VERIFY(pT3[0].mc == 4);
  		EATEST_VERIFY((pT2 < pT3) == (pT2.get() < pT3.get()));
  
  		// pointer release() noexcept
  		unique_ptr<A[]> pRelease(new A[1]);
  		A* pAArray = pRelease.release();
  		delete[] pAArray;
  
  		// constexpr unique_ptr() noexcept
  		unique_ptr<A[]> pT4;
  		EATEST_VERIFY(pT4.get() == (A*)0);
  		if(pT4)
  			EATEST_VERIFY(pT4.get()); // Will fail
  		if(!(!pT4))
  			EATEST_VERIFY(pT4.get()); // Will fail
  
  		pT4.reset(new A[1]);
  		if(!pT4)
  			EATEST_VERIFY(!pT4.get()); // Will fail
  
  		EATEST_VERIFY(A::mCount == 8);  // There were a number of array creations and deletions above that make this so.
  
  		// unique_ptr(nullptr_t) noexcept
  		unique_ptr<A[]> pT5(nullptr);
  		EATEST_VERIFY(pT5.get() == (A*)0);
  
  		// unique_ptr(pointer pValue, deleter) noexcept
  		CustomArrayDeleter customADeleter;
  		unique_ptr<A[], CustomArrayDeleter> pT6(new A[17], customADeleter);
  		pT6[0].mc = 17;
  		EATEST_VERIFY(pT6[0].mc == 17);
  
  		// unique_ptr(pointer pValue, typename eastl::remove_reference<Deleter>::type&& deleter) noexcept
  		unique_ptr<A[], CustomArrayDeleter> pT7(new A[18], CustomArrayDeleter());
  		pT7[0].mc = 18;
  		EATEST_VERIFY(pT7[0].mc == 18);
  
  		// unique_ptr(this_type&& x) noexcept
  		unique_ptr<A[], CustomArrayDeleter> pT8(eastl::move(pT7));
  		EATEST_VERIFY(pT8[0].mc == 18);
  
  		// unique_ptr(unique_ptr<U, E>&& u, ...)
  		unique_ptr<A[], default_delete<A[]> > pT9(eastl::move(pT2));
  		EATEST_VERIFY(pT9[0].mc == 3);
  
  		// this_type& operator=(this_type&& u) noexcept
  		// operator=(unique_ptr<U, E>&& u) noexcept
  		//unique_ptr<void, CustomDeleter> pTVoid;
  		//unique_ptr<int, CustomDeleter>  pTInt(new int(1));
  		//pTVoid.operator=<int, CustomDeleter>(eastl::move(pTInt));  // This doesn't work because CustomDeleter doesn't know how to delete void*. Need to rework this test.
  
  		// this_type& operator=(nullptr_t) noexcept
  		pT6 = nullptr;
  		EATEST_VERIFY(pT6.get() == (A*)0);
  
  		// unique_ptr<> make_unique(Args&&... args);
  		unique_ptr<NamedClass> p = eastl::make_unique<NamedClass>("test", "test2");
  		EATEST_VERIFY(EA::StdC::Strcmp(p->mpName, "test") == 0 && EA::StdC::Strcmp(p->mpName2, "test2") == 0);
  
  		unique_ptr<NamedClass[]> pArray = eastl::make_unique<NamedClass[]>(4);
  		pArray[0].mpName = "test";
  		EATEST_VERIFY(EA::StdC::Strcmp(p->mpName, "test") == 0);
  
  		#ifdef EASTL_TEST_DISABLED_PENDING_SUPPORT
  		{
  			const size_t kAlignedStructAlignment = 512;
  			struct AlignedStruct {} EA_ALIGN(kAlignedStructAlignment);
  
  			unique_ptr<AlignedStruct> pAlignedStruct = eastl::make_unique<AlignedStruct>();
  			EATEST_VERIFY_F(intptr_t(pAlignedStruct.get()) % kAlignedStructAlignment == 0, "pAlignedStruct didn't have proper alignment");
  		}
  		#endif
  
  		//Expected to not be valid:
  		//unique_ptr<NamedClass[4]> p2Array4 = eastl::make_unique<NamedClass[4]>();
  		//p2Array4[0].mpName = "test";
  		//EATEST_VERIFY(EA::StdC::Strcmp(p2Array4[0].mpName, "test") == 0);
  	}
  
  	EATEST_VERIFY(A::mCount == 0); // This check verifies that no A instances were lost, which also verifies that the [] version of the deleter was used in all cases.
  
  	// validate unique_ptr's compressed_pair implementation is working. 
  	{
  		const int ARBITRARY_SIZE = 256;
  		static_assert(sizeof(unique_ptr<short>)     == sizeof(uintptr_t), "");
  		static_assert(sizeof(unique_ptr<long>)      == sizeof(uintptr_t), "");
  
  		// unique_ptr should be the same size as a pointer. The deleter object is empty so the
  		// eastl::compressed_pair implementation will remove that deleter data member from the unique_ptr.
  		{
  			auto deleter = [](void* pMem) { free(pMem); };
  			unique_ptr<void, decltype(deleter)> sptr(malloc(ARBITRARY_SIZE), deleter);
  			static_assert(sizeof(sptr) == (sizeof(uintptr_t)), "unexpected unique_ptr size");
  		}
  
  		// unique_ptr should be larger than a pointer when the deleter functor is capturing state.  This state forces
  		// the compressed_pair to cached the data in unique_ptr locally. 
  		{
  			int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0;
  			auto deleter = [=](void* pMem) { auto result = (a+b+c+d+e+f); EA_UNUSED(result); free(pMem); };
  			unique_ptr<void, decltype(deleter)> sptr(malloc(ARBITRARY_SIZE), deleter);
  			static_assert(sizeof(sptr) == ((6 * sizeof(int)) + (sizeof(uintptr_t))), "unexpected unique_ptr size");
  		}
  
  		// Simply test moving the one unique pointer to another.
  		// Exercising operator=(T&&)
  		{
  			{
  				unique_ptr<int> ptr(new int(3));
  				EATEST_VERIFY(ptr.get() && *ptr == 3);
  
  				unique_ptr<int> newPtr(new int(4));
  				EATEST_VERIFY(newPtr.get() && *newPtr == 4);
  
  				ptr = eastl::move(newPtr);  // Deletes int(3) and assigns mpValue to int(4)
  				EATEST_VERIFY(ptr.get() && *ptr == 4);
  				EATEST_VERIFY(newPtr.get() == nullptr);
  			}
  
  		#if EA_HAVE_CPP11_INITIALIZER_LIST
  			{
  				unique_ptr<int[]> ptr(new int[3]{ 0, 1, 2 });
  				EATEST_VERIFY(ptr.get() && ptr[0] == 0 && ptr[1] == 1 && ptr[2] == 2);
  
  				unique_ptr<int[]> newPtr(new int[3]{ 3, 4, 5 });
  				EATEST_VERIFY(newPtr.get() && newPtr[0] == 3 && newPtr[1] == 4 && newPtr[2] == 5);
  
  				ptr = eastl::move(newPtr);  // Deletes int(3) and assigns mpValue to int(4)
  				EATEST_VERIFY(ptr.get() && ptr[0] == 3 && ptr[1] == 4 && ptr[2] == 5);
  				EATEST_VERIFY(newPtr.get() == nullptr);
  			}
  		#endif
  
  			// ToDo: Test move assignment between two convertible types with an is_assignable deleter_type
  			//{
  			//	struct Base {};
  			//	struct Child : public Base {};
  
  			//	typedef unique_ptr<Base, CustomDeleter> BaseSPtr;
  			//	typedef unique_ptr<Child, CustomDeleter> ChildSPtr;
  
  			//	static_assert(!is_array<BaseSPtr::element_type>::value, "This test requires a non-array type");
  			//	static_assert(is_convertible<ChildSPtr::pointer, BaseSPtr::pointer>::value, "UniquePtr ptr types must be convertible for this test");
  			//	static_assert(is_assignable<BaseSPtr::deleter_type&, ChildSPtr::deleter_type&&>::value, "Deleter types must be assignable to one another");
  
  			//	BaseSPtr ptr(new Base);
  			//	EATEST_VERIFY(ptr.get());
  
  			//	unique_ptr<Child> newPtr(new Child);
  			//	EATEST_VERIFY(newPtr.get());
  
  			//	ptr = eastl::move(newPtr);
  			//	EATEST_VERIFY(ptr);
  			//	EATEST_VERIFY(newPtr.get() == nullptr);
  			//}
  		}
  	}
  
  	return nErrorCount;
  }
  
  
  static int Test_scoped_ptr()
  {
  	using namespace SmartPtrTest;
  	using namespace eastl;
  
  	int nErrorCount(0);
  
  	{
  		EATEST_VERIFY(A::mCount == 0);
  
  		scoped_ptr<int> pT1(new int(5));
  		EATEST_VERIFY(*pT1 == 5);
  
  		*pT1 = 3;
  		EATEST_VERIFY(*pT1 == 3);
  		EATEST_VERIFY(pT1.get() == get_pointer(pT1));
  
  		scoped_ptr<A> pT2(new A(1));
  		EATEST_VERIFY(pT2->mc == 1);
  		EATEST_VERIFY(A::mCount == 1);
  
  		pT2.reset(new A(2));
  		EATEST_VERIFY(pT2->mc == 2);
  
  		pT2.reset(0);
  		EATEST_VERIFY(pT2.get() == (A*)0);
  		EATEST_VERIFY(pT2.get() == get_pointer(pT2));
  
  		pT2.reset(new A(3));
  		EATEST_VERIFY(pT2->mc == 3);
  
  		scoped_ptr<A> pT3(new A(4));
  		EATEST_VERIFY(pT3->mc == 4);
  
  		pT2.swap(pT3);
  		EATEST_VERIFY(pT2->mc == 4);
  		EATEST_VERIFY(pT3->mc == 3);
  
  		swap(pT2, pT3);
  		EATEST_VERIFY(pT2->mc == 3);
  		EATEST_VERIFY(pT3->mc == 4);
  		EATEST_VERIFY((pT2 < pT3) == (pT2.get() < pT3.get()));
  
  		scoped_ptr<A> pT4;
  		EATEST_VERIFY(pT4.get() == (A*)0);
  		if(pT4)
  			EATEST_VERIFY(pT4.get()); // Will fail
  		if(!(!pT4))
  			EATEST_VERIFY(pT4.get()); // Will fail
  
  		pT4.reset(new A(0));
  		if(!pT4)
  			EATEST_VERIFY(!pT4.get()); // Will fail
  
  		EATEST_VERIFY(A::mCount == 3);
  	}
  
  	{   // Test the detach function.
  		scoped_ptr<A> ptr(new A);
  		A* pA = ptr.detach();
  		delete pA;
  	}
  
  	{
  		scoped_ptr<void> ptr(new int);
  		(void)ptr;
  	}
  
  	EATEST_VERIFY(A::mCount == 0);
  
  	return nErrorCount;
  }
  
  
  
  static int Test_scoped_array()
  {
  	using namespace SmartPtrTest;
  	using namespace eastl;
  
  	int nErrorCount(0);
  
  	{
  		scoped_array<int> pT1(new int[5]);
  		pT1[0] = 5;
  		EATEST_VERIFY(pT1[0] == 5);
  		EATEST_VERIFY(pT1.get()[0] == 5);
  
  		scoped_array<A> pT2(new A[2]);
  		EATEST_VERIFY(A::mCount == 2);
  		EATEST_VERIFY(pT2[0].mc == 0);
  		EATEST_VERIFY(pT2.get()[0].mc == 0);
  		EATEST_VERIFY(get_pointer(pT2)[0].mc == 0);
  
  		pT2.reset(new A[4]);
  		EATEST_VERIFY(A::mCount == 4);
  		if(!pT2)
  			EATEST_VERIFY(!pT2.get()); // Will fail
  
  		pT2.reset(0);
  		EATEST_VERIFY(A::mCount == 0);
  		if(pT2)
  			EATEST_VERIFY(pT2.get()); // Will fail
  		if(!(!pT2))
  			EATEST_VERIFY(pT2.get()); // Will fail
  
  		scoped_array<A> pT3(new A[3]);
  		EATEST_VERIFY(A::mCount == 3);
  
  		pT2.swap(pT3);
  		EATEST_VERIFY(A::mCount == 3);
  
  		swap(pT2, pT3);
  		EATEST_VERIFY(A::mCount == 3);
  		EATEST_VERIFY((pT2 < pT3) == (pT2.get() < pT3.get()));
  
  		EATEST_VERIFY(A::mCount == 3);
  	}
  
  	{   // Test the detach function.
  		scoped_array<A> ptr(new A[6]);
  		A* pArray = ptr.detach();
  		delete[] pArray;
  	}
  
  	{
  		scoped_array<void> ptr(new int[6]);
  		(void)ptr;
  	}
  
  	EATEST_VERIFY(A::mCount == 0);
  
  	return nErrorCount;
  }
  
  
  static int Test_shared_ptr()
  {
  	using namespace SmartPtrTest;
  	using namespace eastl;
  
  	int nErrorCount(0);
  
  	// Name test.
  	#if EASTLTEST_GETTYPENAME_AVAILABLE
  		//eastl::string sTypeName = GetTypeName<typename eastl::unique_ptr<int>::pointer>();
  		//EA::UnitTest::Report("type name of (typename shared_ptr<int>::pointer): %s", sTypeName.c_str());
  
  		//sTypeName = GetTypeName<typename eastl::common_type<int*, int*>::type>();
  		//EA::UnitTest::Report("type name of (typename eastl::common_type<int*, int*>::type): %s", sTypeName.c_str());
  	#endif
  
  	{
  		shared_ptr<int> pT1;
  		EATEST_VERIFY(pT1.get() == NULL);
  	}
  
  	{
  		shared_ptr<int> pT1(new int(5));
  		EATEST_VERIFY(*pT1 == 5);
  		EATEST_VERIFY(pT1.get() == get_pointer(pT1));
  		EATEST_VERIFY(pT1.use_count() == 1);
  		EATEST_VERIFY(pT1.unique() );
  
  		shared_ptr<int> pT2;
  		EATEST_VERIFY(pT1 != pT2);
  		EATEST_VERIFY(pT1.use_count() == 1);
  		EATEST_VERIFY(pT1.unique());
  
  		pT2 = pT1;
  		EATEST_VERIFY(pT1.use_count() == 2);
  		EATEST_VERIFY(pT2.use_count() == 2);
  		EATEST_VERIFY(!pT1.unique());
  		EATEST_VERIFY(!(pT1 < pT2)); // They should be equal
  		EATEST_VERIFY(pT1 == pT2);
  
  		*pT1 = 3;
  		EATEST_VERIFY(*pT1 == 3);
  		EATEST_VERIFY(*pT1 == 3);
  		EATEST_VERIFY(*pT2 == 3);
  
  		pT2.reset((int*)NULL);
  		EATEST_VERIFY(pT2.unique());
  		EATEST_VERIFY(pT2.use_count() == 1);
  		EATEST_VERIFY(pT1.unique());
  		EATEST_VERIFY(pT1.use_count() == 1);
  		EATEST_VERIFY(pT1 != pT2);
  	}
  
  	{
  		EATEST_VERIFY(A::mCount == 0);
  
  		shared_ptr<A> pT2(new A(0));
  		EATEST_VERIFY(A::mCount == 1);
  		EATEST_VERIFY(pT2->mc == 0);
  		EATEST_VERIFY(pT2.use_count() == 1);
  		EATEST_VERIFY(pT2.unique());
  
  		pT2.reset(new A(1));
  		EATEST_VERIFY(pT2->mc == 1);
  		EATEST_VERIFY(A::mCount == 1);
  		EATEST_VERIFY(pT2.use_count() == 1);
  		EATEST_VERIFY(pT2.unique());
  
  		shared_ptr<A> pT3(new A(2));
  		EATEST_VERIFY(A::mCount == 2);
  
  		pT2.swap(pT3);
  		EATEST_VERIFY(pT2->mc == 2);
  		EATEST_VERIFY(pT3->mc == 1);
  		EATEST_VERIFY(A::mCount == 2);
  
  		swap(pT2, pT3);
  		EATEST_VERIFY(pT2->mc == 1);
  		EATEST_VERIFY(pT3->mc == 2);
  		EATEST_VERIFY(A::mCount == 2);
  		if(!pT2)
  			EATEST_VERIFY(!pT2.get()); // Will fail
  
  		shared_ptr<A> pT4;
  		EATEST_VERIFY(pT2.use_count() == 1);
  		EATEST_VERIFY(pT2.unique());
  		EATEST_VERIFY(A::mCount == 2);
  		if(pT4)
  			EATEST_VERIFY(pT4.get()); // Will fail
  		if(!(!pT4))
  			EATEST_VERIFY(pT4.get()); // Will fail
  
  		pT4 = pT2;
  		EATEST_VERIFY(pT2.use_count() == 2);
  		EATEST_VERIFY(pT4.use_count() == 2);
  		EATEST_VERIFY(!pT2.unique());
  		EATEST_VERIFY(!pT4.unique());
  		EATEST_VERIFY(A::mCount == 2);
  		EATEST_VERIFY(pT2 == pT4);
  		EATEST_VERIFY(pT2 != pT3);
  		EATEST_VERIFY(!(pT2 < pT4)); // They should be equal
  
  		shared_ptr<A> pT5(pT4);
  		EATEST_VERIFY(pT4 == pT5);
  		EATEST_VERIFY(pT2.use_count() == 3);
  		EATEST_VERIFY(pT4.use_count() == 3);
  		EATEST_VERIFY(pT5.use_count() == 3);
  		EATEST_VERIFY(!pT5.unique());
  
  		pT4 = shared_ptr<A>((A*)NULL);
  		EATEST_VERIFY(pT4.unique());
  		EATEST_VERIFY(pT4.use_count() == 1);
  		EATEST_VERIFY(pT2.use_count() == 2);
  
  		EATEST_VERIFY(A::mCount == 2);
  	}
  
  
  	// Regression test reported by a user.
  	// typename eastl::enable_if<!eastl::is_array<U>::value && eastl::is_convertible<U*, element_type*>::value, this_type&>::type
  	// operator=(unique_ptr<U, Deleter> && uniquePtr)
  	{
  		{
  			shared_ptr<A> rT1(new A(42));
  			unique_ptr<B> rT2(new B);  // default ctor uses 0
  			rT2->mc = 115;
  
  			EATEST_VERIFY(rT1->mc == 42);
  			EATEST_VERIFY(rT2->mc == 115);
  
  			rT1 = eastl::move(rT2);
  
  			EATEST_VERIFY(rT1->mc == 115);
  			// EATEST_VERIFY(rT2->mc == 115);  // state of object post-move is undefined.
  		}
  
  		// test the state of the shared_ptr::operator= return
  		{
  			shared_ptr<A> rT1(new A(42));
  			unique_ptr<B> rT2(new B);  // default ctor uses 0
  			rT2->mc = 115;
  
  			shared_ptr<A> operatorReturn = (rT1 = eastl::move(rT2));
  
  			EATEST_VERIFY(operatorReturn == rT1);
  
  			EATEST_VERIFY(operatorReturn->mc == 115);
  			// EATEST_VERIFY(rT1->mc == 115); // implied as both are pointing to the same address
  		}
  	}
  
  
  	{ // Test member template functions.
  		shared_ptr<ChildClass>      pCC(new GrandChildClass);
  		shared_ptr<ParentClass>     pPC(pCC);
  		shared_ptr<GrandChildClass> pGCC(static_pointer_cast<GrandChildClass>(pPC));
  	}
  
  
  	{ // Test enable_shared_from_this
  		shared_ptr<Y> p(new Y);
  		shared_ptr<Y> q = p->f();
  
  		EATEST_VERIFY(p == q);
  		EATEST_VERIFY(!(p < q || q < p)); // p and q must share ownership
  
  		shared_ptr<BCLS> bctrlp = shared_ptr<BCLS>(new BCLS);
  	}
  
  
  	{ // Test static_pointer_cast, etc.
  		shared_ptr<GrandChildClass> pGCC(new GrandChildClass);
  		shared_ptr<ParentClass>     pPC = static_pointer_cast<ParentClass>(pGCC);
  
  		EATEST_VERIFY(pPC == pGCC);
  
  		#if EASTL_RTTI_ENABLED
  		shared_ptr<ChildClass>      pCC = dynamic_pointer_cast<ChildClass>(pPC);
  		EATEST_VERIFY(pCC == pGCC);
  		#endif
  
  		#if !defined(__GNUC__) ||  (__GNUC__ >= 3) // If not using old GCC (GCC 2.x is broken)...
  			eastl::shared_ptr<const void> pVoidPtr = shared_ptr<ParentClass>(new ParentClass);
  			shared_ptr<ParentClass> ap = const_pointer_cast<ParentClass>(static_pointer_cast<const ParentClass>(pVoidPtr));
  		#endif
  
  		//typedef shared_ptr<void const> ASPtr;
  		//shared_ptr<void const> pVoidPtr = ASPtr(new ParentClass);
  		//ASPtr ap = const_pointer_cast<ParentClass>(static_pointer_cast<const ParentClass>(pVoidPtr));
  	}
  
  
  	{ // Test static_shared_pointer_cast, etc.
  		shared_ptr<GrandChildClass> pGCC(new GrandChildClass);
  		shared_ptr<ParentClass>     pPC = static_shared_pointer_cast<ParentClass /*, EASTLAllocatorType, smart_ptr_deleter<ParentClass>*/ >(pGCC);
  
  		EATEST_VERIFY(pPC == pGCC);
  
  		#if EASTL_RTTI_ENABLED
  		shared_ptr<ChildClass>      pCC = dynamic_shared_pointer_cast<ChildClass /*, EASTLAllocatorType, smart_ptr_deleter<ParentClass>*/ >(pPC);
  		EATEST_VERIFY(pCC == pGCC);
  		#endif
  	}
  
  
  	{ // Test smart_ptr_deleter
  		shared_ptr<void> pVoid(new ParentClass, smart_ptr_deleter<ParentClass>());
  		EATEST_VERIFY(pVoid.get() != NULL);
  
  		pVoid = shared_ptr<ParentClass>(new ParentClass, smart_ptr_deleter<ParentClass>());
  		EATEST_VERIFY(pVoid.get() != NULL);
  	}
  
  
  	{ // Test of shared_ptr<void const>
  		#if !defined(__GNUC__) ||  (__GNUC__ >= 3) // If not using old GCC (GCC 2.x is broken)...
  			shared_ptr<void const> voidPtr = shared_ptr<A1>(new A1);
  			shared_ptr<A1>         a1Ptr   = const_pointer_cast<A1>(static_pointer_cast<const A1>(voidPtr));
  		#endif
  	}
  
  
  	{ // Test of static_pointer_cast
  		shared_ptr<B1> bPtr = shared_ptr<B1>(new B1);
  		shared_ptr<A1> aPtr = static_pointer_cast<A1, B1>(bPtr);
  	}
  
  
  	{ // Test shared_ptr<void>
  		{
  			#if !defined(__GNUC__) ||  (__GNUC__ >= 3) // If not using old GCC (GCC 2.x is broken)...
  				const char* const pName = "NamedClassTest";
  
  				NamedClass* const pNamedClass0 = new NamedClass(pName);
  				EATEST_VERIFY(pNamedClass0->mpName == pName);
  
  			  //shared_ptr<void const, EASTLAllocatorType, smart_ptr_deleter<NamedClass> > voidPtr(pNamedClass0);
  				shared_ptr<void const> voidPtr(pNamedClass0);
  				EATEST_VERIFY(voidPtr.get() == pNamedClass0);
  
  				NamedClass* const pNamedClass1 = (NamedClass*)voidPtr.get();
  				EATEST_VERIFY(pNamedClass1->mpName == pName);
  			#endif
  		}
  
  		{
  			#if !defined(__GNUC__) ||  (__GNUC__ >= 3) // If not using old GCC (GCC 2.x is broken)...
  				const char* const pName = "NamedClassTest";
  
  				NamedClass* const pNamedClass0 = new NamedClass(pName);
  				EATEST_VERIFY(pNamedClass0->mpName == pName);
  
  				shared_ptr<void const> voidPtr(pNamedClass0, smart_ptr_deleter<NamedClass>());
  				EATEST_VERIFY(voidPtr.get() == pNamedClass0);
  
  				NamedClass* const pNamedClass1 = (NamedClass*)voidPtr.get();
  				EATEST_VERIFY(pNamedClass1->mpName == pName);
  			#endif
  		}
  	}
  
  
  	{
  		const char* const pName1 = "NamedClassTest1";
  		const char* const pName2 = "NamedClassTest2";
  
  		shared_ptr<NamedClass> sp(new NamedClass(pName1));
  		EATEST_VERIFY(!sp == false);
  		EATEST_VERIFY(sp.unique());
  		EATEST_VERIFY(sp->mpName == pName1);
  
  		shared_ptr<NamedClass> sp2 = sp;
  		EATEST_VERIFY(sp2.use_count() == 2);
  
  		sp2.reset(new NamedClass(pName2));
  		EATEST_VERIFY(sp2.use_count() == 1);
  		EATEST_VERIFY(sp.unique());
  		EATEST_VERIFY(sp2->mpName == pName2);
  
  		sp.reset();
  		EATEST_VERIFY(!sp == true);
  	}
  
  	{
  		// Exception handling tests
  		#if EASTL_EXCEPTIONS_ENABLED
  			try {
  				weak_ptr<A>   pWeakA;             // leave uninitalized
  				shared_ptr<A> pSharedA(pWeakA);   // This should throw eastl::bad_weak_ptr
  				EATEST_VERIFY(false);
  			}
  			catch(eastl::bad_weak_ptr&)
  			{
  				EATEST_VERIFY(true);            // This pathway should be taken.
  			}
  			catch(...)
  			{
  				EATEST_VERIFY(false);
  			}
  
  
  			ThrowingAllocator<true> throwingAllocator; // Throw on first attempt to allocate.
  			shared_ptr<A> pA0;
  
  			try {
  				A::mCount = 0;
  				pA0 = eastl::allocate_shared<A, ThrowingAllocator<true> >(throwingAllocator, 'a');
  				EATEST_VERIFY(false);
  			}
  			catch(std::bad_alloc&)
  			{
  				EATEST_VERIFY(true);                // This pathway should be taken.
  				EATEST_VERIFY(pA0.get() == NULL);   // The C++11 Standard doesn't seem to require this, but that's how we currently do it until we learn it should be otherwise.
  				EATEST_VERIFY(pA0.use_count() == 0);
  				EATEST_VERIFY(A::mCount == 0);      // Verify that there were no surviving A instances since the exception.
  			}
  			catch(...)
  			{
  				EATEST_VERIFY(false);
  			}
  
  
  			try {
  				shared_ptr<A> pA1(new A('a'), default_delete<A>(), throwingAllocator);
  				EATEST_VERIFY(false);
  			}
  			catch(std::bad_alloc&)
  			{
  				EATEST_VERIFY(true);                // This pathway should be taken.
  				EATEST_VERIFY(A::mCount == 0);
  			}
  			catch(...)
  			{
  				EATEST_VERIFY(false);
  			}
  
  		#endif
  
  	}
  
  	#if EASTL_RTTI_ENABLED
  	{
  		// template <typename U, typename A, typename D>
  		// shared_ptr(const shared_ptr<U, A, D>& sharedPtr, dynamic_cast_tag);
  		// To do.
  
  		// template <typename U, typename A, typename D, typename UDeleter>
  		// shared_ptr(const shared_ptr<U, A, D>& sharedPtr, dynamic_cast_tag, const UDeleter&);
  		// To do.
  	}
  	#endif
  
  	EATEST_VERIFY(A::mCount == 0);
  
  	return nErrorCount;
  }
  
  
  
  
  #if EASTL_THREAD_SUPPORT_AVAILABLE
  	// C++ Standard section 20.7.2.5 -- shared_ptr atomic access
  	// shared_ptr thread safety is about safe use of the pointer itself and not about what it points to. shared_ptr thread safety
  	// allows you to safely use shared_ptr from different threads, but if the object shared_ptr holds requires thread safety then
  	// you need to separately handle that in a thread-safe way. A good way to think about it is this: "shared_ptr is as thread-safe as a raw pointer."
  	//
  	// Some helper links:
  	//     http://stackoverflow.com/questions/9127816/stdshared-ptr-thread-safety-explained
  	//     http://stackoverflow.com/questions/14482830/stdshared-ptr-thread-safety
  	//     http://cppwisdom.quora.com/shared_ptr-is-almost-thread-safe
  	// 
  
  	// Test the ability of Futex to report the callstack of another thread holding a futex.
  	struct SharedPtrTestThread : public EA::Thread::IRunnable
  	{
  		EA::Thread::ThreadParameters    mThreadParams;
  		EA::Thread::Thread              mThread;
  		volatile bool                   mbShouldContinue;
  		int                             mnErrorCount;
  		eastl::shared_ptr<TestObject>*  mpSPTO;
  		eastl::weak_ptr<TestObject>*    mpWPTO;
  
  		SharedPtrTestThread() : mThreadParams(), mThread(), mbShouldContinue(true), mnErrorCount(0), mpSPTO(NULL), mpWPTO(NULL) {}
  		SharedPtrTestThread(const SharedPtrTestThread&){}
  		void operator=(const SharedPtrTestThread&){}
  
  		intptr_t Run(void*)
  		{
  			int& nErrorCount = mnErrorCount; // declare nErrorCount so that EATEST_VERIFY can work, as it depends on it being declared.
  
  			while(mbShouldContinue)
  			{
  				EA::UnitTest::ThreadSleepRandom(1, 10);
  
  				EATEST_VERIFY(mpSPTO->get()->mX == 99);
  
  				eastl::shared_ptr<TestObject> temp(mpWPTO->lock());
  				EATEST_VERIFY(temp->mX == 99);
  
  				eastl::shared_ptr<TestObject> spTO2(*mpSPTO);
  				EATEST_VERIFY(spTO2->mX == 99);
  				EATEST_VERIFY(spTO2.use_count() >= 2);
  
  				eastl::weak_ptr<TestObject> wpTO2(spTO2);
  				temp = mpWPTO->lock();
  				EATEST_VERIFY(temp->mX == 99);
  
  				temp = spTO2;
  				spTO2.reset();
  				EATEST_VERIFY(mpSPTO->get()->mX == 99);
  			}
  
  			return nErrorCount;
  		}
  	};
  #endif
  
  
  static int Test_shared_ptr_thread()
  {
  	using namespace SmartPtrTest;
  	using namespace eastl;
  	using namespace EA::Thread;
  
  	int nErrorCount(0);
  
  	#if EASTL_THREAD_SUPPORT_AVAILABLE
  		{
  			SharedPtrTestThread    thread[4];
  			shared_ptr<TestObject> spTO(new TestObject(99));
  			weak_ptr<TestObject>   wpTO(spTO);
  
  			for(size_t i = 0; i < EAArrayCount(thread); i++)
  			{
  				thread[i].mpSPTO = &spTO;
  				thread[i].mpWPTO = &wpTO;
  				thread[i].mThreadParams.mpName = "SharedPtrTestThread";
  			}
  
  			for(size_t i = 0; i < EAArrayCount(thread); i++)
  				thread[i].mThread.Begin(&thread[0], NULL, &thread[0].mThreadParams);
  
  			EA::UnitTest::ThreadSleep(2000);
  
  			for(size_t i = 0; i < EAArrayCount(thread); i++)
  				thread[i].mbShouldContinue = false;
  
  			for(size_t i = 0; i < EAArrayCount(thread); i++)
  			{
  				thread[i].mThread.WaitForEnd();
  				nErrorCount += thread[i].mnErrorCount;
  			}
  		}
  	#endif
  
  	#if EASTL_THREAD_SUPPORT_AVAILABLE
  		{
  			// We currently do light testing of the atomic functions. It would take a bit of work to fully test
  			// the memory behavior of these in a rigorous way. Also, as of this writing we don't have a portable
  			// way to use the std::memory_order functionality.
  
  			shared_ptr<TestObject> spTO(new TestObject(55));
  
  			// bool atomic_is_lock_free(const shared_ptr<T>*);
  			EATEST_VERIFY(!atomic_is_lock_free(&spTO));
  
  			// shared_ptr<T> atomic_load(const shared_ptr<T>* pSharedPtr);
  			// shared_ptr<T> atomic_load_explicit(const shared_ptr<T>* pSharedPtr, ... /*std::memory_order memoryOrder*/);
  			shared_ptr<TestObject> spTO2 = atomic_load(&spTO);
  			EATEST_VERIFY(spTO->mX == 55);
  			EATEST_VERIFY(spTO2->mX == 55);
  
  			// void atomic_store(shared_ptr<T>* pSharedPtrA, shared_ptr<T> sharedPtrB);
  			// void atomic_store_explicit(shared_ptr<T>* pSharedPtrA, shared_ptr<T> sharedPtrB, ... /*std::memory_order memoryOrder*/);
  			spTO2->mX = 56;
  			EATEST_VERIFY(spTO->mX == 56);
  			EATEST_VERIFY(spTO2->mX == 56);
  
  			atomic_store(&spTO, shared_ptr<TestObject>(new TestObject(77)));
  			EATEST_VERIFY(spTO->mX == 77);
  			EATEST_VERIFY(spTO2->mX == 56);
  
  			// shared_ptr<T> atomic_exchange(shared_ptr<T>* pSharedPtrA, shared_ptr<T> sharedPtrB);
  			// shared_ptr<T> atomic_exchange_explicit(shared_ptr<T>* pSharedPtrA, shared_ptr<T> sharedPtrB, ... /*std::memory_order memoryOrder*/);
  			spTO = atomic_exchange(&spTO2, spTO);
  			EATEST_VERIFY(spTO->mX == 56);
  			EATEST_VERIFY(spTO2->mX == 77);
  
  			// bool atomic_compare_exchange_strong(shared_ptr<T>* pSharedPtr, shared_ptr<T>* pSharedPtrCondition, shared_ptr<T> sharedPtrNew);
  			// bool atomic_compare_exchange_weak(shared_ptr<T>* pSharedPtr, shared_ptr<T>* pSharedPtrCondition, shared_ptr<T> sharedPtrNew);
  			// bool atomic_compare_exchange_strong_explicit(shared_ptr<T>* pSharedPtr, shared_ptr<T>* pSharedPtrCondition, shared_ptr<T> sharedPtrNew, ... /*memory_order memoryOrderSuccess, memory_order memoryOrderFailure*/);
  			// bool atomic_compare_exchange_weak_explicit(shared_ptr<T>* pSharedPtr, shared_ptr<T>* pSharedPtrCondition, shared_ptr<T> sharedPtrNew, ... /*memory_order memoryOrderSuccess, memory_order memoryOrderFailure*/);
  			shared_ptr<TestObject> spTO3 = atomic_load(&spTO2);
  			bool result = atomic_compare_exchange_strong(&spTO3, &spTO, make_shared<TestObject>(88));   // spTO3 != spTO, so this should do no exchange and return false.
  			EATEST_VERIFY(!result);
  			EATEST_VERIFY(spTO3->mX == 77);
  			EATEST_VERIFY(spTO->mX == 77);
  
  			result = atomic_compare_exchange_strong(&spTO3, &spTO2, make_shared<TestObject>(88));       // spTO3 == spTO2, so this should succeed.
  			EATEST_VERIFY(result);
  			EATEST_VERIFY(spTO2->mX == 77);
  			EATEST_VERIFY(spTO3->mX == 88);
  		}
  	#endif
  
  	EATEST_VERIFY(A::mCount == 0);
  	TestObject::Reset();
  
  	return nErrorCount;
  }
  
  
  static int Test_weak_ptr()
  {
  	using namespace SmartPtrTest;
  	using namespace eastl;
  
  	int nErrorCount(0);
  
  	{
  		weak_ptr<int>   pW0;
  		shared_ptr<int> pS0(new int(0));
  		shared_ptr<int> pS1(new int(1));
  		weak_ptr<int>   pW1(pS1);
  		weak_ptr<int>   pW2;
  		weak_ptr<int>   pW3(pW2);
  
  		EATEST_VERIFY(pS1.use_count() == 1);
  		EATEST_VERIFY(pW1.use_count() == 1);
  		EATEST_VERIFY(pW2.use_count() == 0);
  		EATEST_VERIFY(pW3.use_count() == 0);
  		EATEST_VERIFY(pW1.expired() == false);
  		EATEST_VERIFY(pW2.expired() == true);
  		EATEST_VERIFY(pW3.expired() == true);
  		pS1.reset();
  		EATEST_VERIFY(pW1.expired() == true);
  		pW1 = pS0;
  		EATEST_VERIFY(pW1.expired() == false);
  		pW1.swap(pW2);
  		EATEST_VERIFY(pW1.expired() == true);
  		EATEST_VERIFY(pW2.expired() == false);
  		pW1 = pW2;
  		EATEST_VERIFY(pW1.expired() == false);
  		pW3 = pW1;
  		EATEST_VERIFY(pW3.expired() == false);
  		EATEST_VERIFY(pS1.use_count() == 0);
  		pW3.reset();
  		EATEST_VERIFY(pW3.expired() == true);
  		pS1.reset(new int(3));
  		EATEST_VERIFY(pS1.use_count() == 1);
  		pW3 = pS1;
  		EATEST_VERIFY(pS1.use_count() == 1);
  		EATEST_VERIFY(pS1.use_count() == pW3.use_count());
  
  		shared_ptr<int> pShared2(pW2.lock());
  		shared_ptr<int> pShared3(pW3.lock());
  
  		EATEST_VERIFY(pShared2.use_count() == 2);
  		EATEST_VERIFY(pShared3.use_count() == 2); 
  		swap(pW2, pW3);
  		EATEST_VERIFY(pW2.use_count() == 2);
  		EATEST_VERIFY(pW3.use_count() == 2);
  		pW1 = pW3;
  		EATEST_VERIFY(pW3.use_count() == 2);
  
  		EATEST_VERIFY((pW2 < pW3) || (pW3 < pW2));
  
  		EATEST_VERIFY(pS0.use_count() == 2);
  		pW0 = pS0; // This tests the deletion of a weak_ptr after its associated shared_ptr has destructed.
  		EATEST_VERIFY(pS0.use_count() == 2);
  	}
  
  
  	{
  		weak_ptr<NamedClass> wp;
  
  		EATEST_VERIFY(wp.use_count() == 0);
  		EATEST_VERIFY(wp.expired() == true);
  
  		{
  			shared_ptr<NamedClass> sp(new NamedClass("NamedClass"));
  			wp = sp;
  
  			EATEST_VERIFY(wp.use_count() == 1);
  			EATEST_VERIFY(wp.expired() == false);
  		}
  
  		EATEST_VERIFY(wp.use_count() == 0);
  		EATEST_VERIFY(wp.expired() == true);
  	}
  
  	{   // shared_from_this
  		// This example is taken from the C++11 Standard doc.
  		shared_ptr<const foo> pFoo(new foo);
  		shared_ptr<const foo> qFoo = pFoo->shared_from_this();
  
  		EATEST_VERIFY(pFoo == qFoo);
  		EATEST_VERIFY(!(pFoo < qFoo) && !(qFoo < pFoo)); // p and q share ownership
  	}
  
  	return nErrorCount;
  }
  
  
  static int Test_shared_array()
  {
  	using namespace SmartPtrTest;
  	using namespace eastl;
  
  	int nErrorCount(0);
  
  	{
  		shared_array<int> pT1(new int[5]);
  		pT1[0] = 5;
  		EATEST_VERIFY(pT1[0] == 5);
  		EATEST_VERIFY(pT1.get() == get_pointer(pT1));
  		EATEST_VERIFY(pT1.use_count() == 1);
  		EATEST_VERIFY(pT1.unique());
  
  		shared_array<int> pT2;
  		EATEST_VERIFY(pT1 != pT2);
  		EATEST_VERIFY(pT1.use_count() == 1);
  		EATEST_VERIFY(pT1.unique());
  
  		pT2 = pT1;
  		EATEST_VERIFY(pT1.use_count() == 2);
  		EATEST_VERIFY(pT2.use_count() == 2);
  		EATEST_VERIFY(!pT1.unique());
  		EATEST_VERIFY(!(pT1 < pT2)); // They should be equal
  		EATEST_VERIFY(pT1 == pT2);
  
  		*pT1 = 3;
  		EATEST_VERIFY(*pT1 == 3);
  		EATEST_VERIFY(*pT1 == 3);
  		EATEST_VERIFY(*pT2 == 3);
  
  		pT2.reset(0);
  		EATEST_VERIFY(pT2.unique());
  		EATEST_VERIFY(pT2.use_count() == 1);
  		EATEST_VERIFY(pT1.unique());
  		EATEST_VERIFY(pT1.use_count() == 1);
  		EATEST_VERIFY(pT1 != pT2);
  	}
  
  	{
  		EATEST_VERIFY(A::mCount == 0);
  
  		shared_array<A> pT2(new A[5]);
  		EATEST_VERIFY(A::mCount == 5);
  		EATEST_VERIFY(pT2->mc == 0);
  		EATEST_VERIFY(pT2.use_count() == 1);
  		EATEST_VERIFY(pT2.unique());
  
  		pT2.reset(new A[1]);
  		pT2[0].mc = 1;
  		EATEST_VERIFY(pT2->mc == 1);
  		EATEST_VERIFY(A::mCount == 1);
  		EATEST_VERIFY(pT2.use_count() == 1);
  		EATEST_VERIFY(pT2.unique());
  
  		shared_array<A> pT3(new A[2]);
  		EATEST_VERIFY(A::mCount == 3);
  
  		pT2.swap(pT3);
  		pT2[0].mc = 2;
  		EATEST_VERIFY(pT2->mc == 2);
  		EATEST_VERIFY(pT3->mc == 1);
  		EATEST_VERIFY(A::mCount == 3);
  
  		swap(pT2, pT3);
  		EATEST_VERIFY(pT2->mc == 1);
  		EATEST_VERIFY(pT3->mc == 2);
  		EATEST_VERIFY(A::mCount == 3);
  		if(!pT2)
  			EATEST_VERIFY(!pT2.get()); // Will fail
  
  		shared_array<A> pT4;
  		EATEST_VERIFY(pT2.use_count() == 1);
  		EATEST_VERIFY(pT2.unique());
  		EATEST_VERIFY(A::mCount == 3);
  		if(pT4)
  			EATEST_VERIFY(pT4.get()); // Will fail
  		if(!(!pT4))
  			EATEST_VERIFY(pT4.get()); // Will fail
  
  		pT4 = pT2;
  		EATEST_VERIFY(pT2.use_count() == 2);
  		EATEST_VERIFY(pT4.use_count() == 2);
  		EATEST_VERIFY(!pT2.unique());
  		EATEST_VERIFY(!pT4.unique());
  		EATEST_VERIFY(A::mCount == 3);
  		EATEST_VERIFY(pT2 == pT4);
  		EATEST_VERIFY(pT2 != pT3);
  		EATEST_VERIFY(!(pT2 < pT4)); // They should be equal
  
  		shared_array<A> pT5(pT4);
  		EATEST_VERIFY(pT4 == pT5);
  		EATEST_VERIFY(pT2.use_count() == 3);
  		EATEST_VERIFY(pT4.use_count() == 3);
  		EATEST_VERIFY(pT5.use_count() == 3);
  		EATEST_VERIFY(!pT5.unique());
  
  		pT4 = shared_array<A>(0);
  		EATEST_VERIFY(pT4.unique());
  		EATEST_VERIFY(pT4.use_count() == 1);
  		EATEST_VERIFY(pT2.use_count() == 2);
  
  		EATEST_VERIFY(A::mCount == 3);
  	}
  
  	EATEST_VERIFY(A::mCount == 0);
  
  	return nErrorCount;
  }
  
  
  
  static int Test_linked_ptr()
  {
  	using namespace SmartPtrTest;
  	using namespace eastl;
  
  	int nErrorCount(0);
  
  	{
  		linked_ptr<int> pT1(new int(5));
  		EATEST_VERIFY(*pT1.get() == 5);
  		EATEST_VERIFY(pT1.get() == get_pointer(pT1));
  		EATEST_VERIFY(pT1.use_count() == 1);
  		EATEST_VERIFY(pT1.unique());
  
  		linked_ptr<int> pT2;
  		EATEST_VERIFY(pT1 != pT2);
  		EATEST_VERIFY(pT1.use_count() == 1);
  		EATEST_VERIFY(pT1.unique());
  
  		pT2 = pT1;
  		EATEST_VERIFY(pT1.use_count() == 2);
  		EATEST_VERIFY(pT2.use_count() == 2);
  		EATEST_VERIFY(!pT1.unique());
  		EATEST_VERIFY(!(pT1 < pT2)); // They should be equal
  		EATEST_VERIFY(pT1 == pT2);
  
  		*pT1 = 3;
  		EATEST_VERIFY(*pT1.get() == 3);
  		EATEST_VERIFY(*pT1 == 3);
  		EATEST_VERIFY(*pT2 == 3);
  
  		pT2.reset((int*)NULL);
  		EATEST_VERIFY(pT2.unique());
  		EATEST_VERIFY(pT2.use_count() == 1);
  		EATEST_VERIFY(pT1.unique());
  		EATEST_VERIFY(pT1.use_count() == 1);
  		EATEST_VERIFY(pT1 != pT2);
  	}
  
  	{
  		EATEST_VERIFY(A::mCount == 0);
  
  		linked_ptr<A> pT2(new A(0));
  		EATEST_VERIFY(A::mCount == 1);
  		EATEST_VERIFY(pT2->mc == 0);
  		EATEST_VERIFY(pT2.use_count() == 1);
  		EATEST_VERIFY(pT2.unique());
  
  		pT2.reset(new A(1));
  		EATEST_VERIFY(pT2->mc == 1);
  		EATEST_VERIFY(A::mCount == 1);
  		EATEST_VERIFY(pT2.use_count() == 1);
  		EATEST_VERIFY(pT2.unique());
  
  		linked_ptr<A> pT3(new A(2));
  		EATEST_VERIFY(A::mCount == 2);
  
  		linked_ptr<A> pT4;
  		EATEST_VERIFY(pT2.use_count() == 1);
  		EATEST_VERIFY(pT2.unique());
  		EATEST_VERIFY(A::mCount == 2);
  		if(pT4)
  			EATEST_VERIFY(pT4.get()); // Will fail
  		if(!(!pT4))
  			EATEST_VERIFY(pT4.get()); // Will fail
  
  		pT4 = pT2;
  		EATEST_VERIFY(pT2.use_count() == 2);
  		EATEST_VERIFY(pT4.use_count() == 2);
  		EATEST_VERIFY(!pT2.unique());
  		EATEST_VERIFY(!pT4.unique());
  		EATEST_VERIFY(A::mCount == 2);
  		EATEST_VERIFY(pT2 == pT4);
  		EATEST_VERIFY(pT2 != pT3);
  		EATEST_VERIFY(!(pT2 < pT4)); // They should be equal
  
  		linked_ptr<A> pT5(pT4);
  		EATEST_VERIFY(pT4 == pT5);
  		EATEST_VERIFY(pT2.use_count() == 3);
  		EATEST_VERIFY(pT4.use_count() == 3);
  		EATEST_VERIFY(pT5.use_count() == 3);
  		EATEST_VERIFY(!pT5.unique());
  
  		pT4 = linked_ptr<A>((A*)NULL);
  		EATEST_VERIFY(pT4.unique());
  		EATEST_VERIFY(pT4.use_count() == 1);
  		EATEST_VERIFY(pT2.use_count() == 2);
  
  		EATEST_VERIFY(A::mCount == 2);
  	}
  		
  	{  // Do some force_delete tests.
  		linked_ptr<A> pT2(new A(0));
  		linked_ptr<A> pT3(pT2);
  		pT2.force_delete();
  		pT3.force_delete();
  	}
  
  	EATEST_VERIFY(A::mCount == 0);
  
  
  	{   // Verify that subclasses are usable.
  		bool bAlloc = false;
  
  		eastl::linked_ptr<DerivedMockObject> pDMO(new DerivedMockObject(&bAlloc));
  		eastl::linked_ptr<MockObject> a1(pDMO);
  		eastl::linked_ptr<MockObject> a2;
  
  		a2 = pDMO;
  	}
  
  	{ // Test regression for a bug.
  		linked_ptr<A> pT2;
  		linked_ptr<A> pT3(pT2);     // In the bug linked_ptr::mpPrev and mpNext were not initialized via this ctor.
  		pT3.reset(new A);           // In the bug this would crash due to unintialized mpPrev/mpNext.
  
  		linked_ptr<B> pT4;
  		linked_ptr<A> pT5(pT4);
  		pT5.reset(new A);
  
  		linked_array<A> pT6;
  		linked_array<A> pT7(pT6);
  		pT7.reset(new A[1]);
  	}
  
  	return nErrorCount;
  }
  
  
  
  static int Test_linked_array()
  {
  	using namespace SmartPtrTest;
  	using namespace eastl;
  
  	int nErrorCount(0);
  
  	{
  		// Tests go here.
  	}
  
  	{  // Do some force_delete tests.
  		linked_array<A> pT2(new A[2]);
  		linked_array<A> pT3(pT2);
  		pT2.force_delete();
  		pT3.force_delete();
  	}
  
  	EATEST_VERIFY(A::mCount == 0);
  
  
  	return nErrorCount;
  }
  
  
  
  static int Test_intrusive_ptr()
  {
  	using namespace SmartPtrTest;
  	using namespace eastl;
  
  	int nErrorCount = 0;
  
  	{   // Test ctor/dtor
  		intrusive_ptr<RefCountTest> ip1;
  		intrusive_ptr<RefCountTest> ip2(NULL, false);
  		intrusive_ptr<RefCountTest> ip3(NULL, true);
  		intrusive_ptr<RefCountTest> ip4(new RefCountTest, true);
  		intrusive_ptr<RefCountTest> ip5(new RefCountTest, false);
  		intrusive_ptr<RefCountTest> ip6(ip1);
  		intrusive_ptr<RefCountTest> ip7(ip4);
  
  		EATEST_VERIFY(ip1.get() == NULL);
  		EATEST_VERIFY(!ip1);
  
  		EATEST_VERIFY(ip2.get() == NULL);
  		EATEST_VERIFY(!ip2);
  
  		EATEST_VERIFY(ip3.get() == NULL);
  		EATEST_VERIFY(!ip3);
  
  		EATEST_VERIFY(ip4.get() != NULL);
  		EATEST_VERIFY(ip4.get()->mRefCount == 2);
  		EATEST_VERIFY(ip4);
  
  		EATEST_VERIFY(ip5.get() != NULL);
  		EATEST_VERIFY(ip5.get()->mRefCount == 0);
  		ip5.get()->AddRef();
  		EATEST_VERIFY(ip5.get()->mRefCount == 1);
  		EATEST_VERIFY(ip5);
  
  		EATEST_VERIFY(ip6.get() == NULL);
  		EATEST_VERIFY(!ip6);
  
  		EATEST_VERIFY(ip7.get() != NULL);
  		EATEST_VERIFY(ip7.get()->mRefCount == 2);
  		EATEST_VERIFY(ip7);
  	}
  
  	{ 
  		// Test move-ctor
  		{
  			VERIFY(RefCountTest::mCount == 0);
  			intrusive_ptr<RefCountTest> ip1(new RefCountTest);
  			VERIFY(RefCountTest::mCount == 1);
  			VERIFY(ip1->mRefCount == 1);
  			{
  				intrusive_ptr<RefCountTest> ip2(eastl::move(ip1));
  				VERIFY(ip1.get() != ip2.get());
  				VERIFY(ip2->mRefCount == 1);
  				VERIFY(RefCountTest::mCount == 1);
  			}
  			VERIFY(ip1.get() == nullptr);
  			VERIFY(RefCountTest::mCount == 0);
  		}
  
  		// Test move-assignment
  		{
  			VERIFY(RefCountTest::mCount == 0);
  			intrusive_ptr<RefCountTest> ip1(new RefCountTest);
  			VERIFY(RefCountTest::mCount == 1);
  			VERIFY(ip1->mRefCount == 1);
  			{
  				intrusive_ptr<RefCountTest> ip2; 
  				ip2 = eastl::move(ip1);
  				VERIFY(ip1.get() != ip2.get());
  				VERIFY(ip2->mRefCount == 1);
  				VERIFY(RefCountTest::mCount == 1);
  			}
  			VERIFY(ip1.get() == nullptr);
  			VERIFY(RefCountTest::mCount == 0);
  		}
  	}
  
  	{   // Test modifiers (assign, attach, detach, reset, swap)
  		RefCountTest* const p1 = new RefCountTest;
  		RefCountTest* const p2 = new RefCountTest;
  		intrusive_ptr<RefCountTest> ip1;
  		intrusive_ptr<RefCountTest> ip2;
  
  		ip1 = p1;
  		ip2 = p2;
  		EATEST_VERIFY(ip1.get() == p1);
  		EATEST_VERIFY((*ip1).mRefCount == 1);
  		EATEST_VERIFY(ip1->mRefCount == 1);
  		ip1.detach();
  		EATEST_VERIFY(ip1.get() == NULL);
  		ip1.attach(p1);
  		EATEST_VERIFY(ip1.get() == p1);
  		EATEST_VERIFY(ip1->mRefCount == 1);
  		ip1.swap(ip2);
  		EATEST_VERIFY(ip1.get() == p2);
  		EATEST_VERIFY(ip2.get() == p1);
  		ip1.swap(ip2);
  		ip1 = ip2;
  		EATEST_VERIFY(ip1 == p2);
  		ip1.reset();
  		EATEST_VERIFY(ip1.get() == NULL);
  		EATEST_VERIFY(ip2.get() == p2);
  		ip2.reset();
  		EATEST_VERIFY(ip2.get() == NULL);
  	}
  
  	{   // Test external functions
  		intrusive_ptr<RefCountTest> ip1;
  		intrusive_ptr<RefCountTest> ip2(new RefCountTest);
  		intrusive_ptr<RefCountTest> ip3(ip1);
  		intrusive_ptr<RefCountTest> ip4(ip2);
  
  		// The VC++ code scanner crashes when it scans this code. 
  		EATEST_VERIFY(get_pointer(ip1) == NULL);
  		EATEST_VERIFY(get_pointer(ip2) != NULL);
  		EATEST_VERIFY(get_pointer(ip3) == get_pointer(ip1));
  		EATEST_VERIFY(get_pointer(ip4) == get_pointer(ip2));
  
  		EATEST_VERIFY(ip3 == ip1);
  		EATEST_VERIFY(ip4 == ip2);
  		EATEST_VERIFY(ip1 == ip3);
  		EATEST_VERIFY(ip2 == ip4);
  
  		EATEST_VERIFY(ip1 != ip2);
  		EATEST_VERIFY(ip3 != ip4);
  		EATEST_VERIFY(ip2 != ip1);
  		EATEST_VERIFY(ip4 != ip3);
  
  		EATEST_VERIFY(ip3 == ip1.get());
  		EATEST_VERIFY(ip4 == ip2.get());
  		EATEST_VERIFY(ip1 == ip3.get());
  		EATEST_VERIFY(ip2 == ip4.get());
  
  		EATEST_VERIFY(ip1 != ip2.get());
  		EATEST_VERIFY(ip3 != ip4.get());
  		EATEST_VERIFY(ip2 != ip1.get());
  		EATEST_VERIFY(ip4 != ip3.get());
  
  		EATEST_VERIFY(ip3.get() == ip1);
  		EATEST_VERIFY(ip4.get() == ip2);
  		EATEST_VERIFY(ip1.get() == ip3);
  		EATEST_VERIFY(ip2.get() == ip4);
  
  		EATEST_VERIFY(ip1.get() != ip2);
  		EATEST_VERIFY(ip3.get() != ip4);
  		EATEST_VERIFY(ip2.get() != ip1);
  		EATEST_VERIFY(ip4.get() != ip3);
  
  		EATEST_VERIFY((ip4 < ip3) || (ip3 < ip4));
  
  		swap(ip1, ip3);
  		EATEST_VERIFY(get_pointer(ip3) == get_pointer(ip1));
  
  		swap(ip2, ip4);
  		EATEST_VERIFY(get_pointer(ip2) == get_pointer(ip4));
  
  		swap(ip1, ip2);
  		EATEST_VERIFY(get_pointer(ip1) != NULL);
  		EATEST_VERIFY(get_pointer(ip2) == NULL);
  		EATEST_VERIFY(get_pointer(ip1) == get_pointer(ip4));
  		EATEST_VERIFY(get_pointer(ip2) == get_pointer(ip3));
  	}
  
  	{   // Misc tests.
  		intrusive_ptr<Test> ip;
  		EATEST_VERIFY(ip.get() == NULL);
  
  		ip.reset();
  		EATEST_VERIFY(ip.get() == NULL);
  
  		intrusive_ptr<Test> ip2(NULL, false);
  		EATEST_VERIFY(ip.get() == NULL);
  
  		bool boolValue = false;
  		Test* pTest = new Test(&boolValue);
  		EATEST_VERIFY(boolValue);
  		pTest->AddRef();
  		intrusive_ptr<Test> ip3(pTest, false);
  		EATEST_VERIFY(ip3.get() == pTest);
  		ip3.reset();
  		EATEST_VERIFY(!boolValue);
  	}
  
  	{   // Misc tests.
  		bool boolArray[3];
  		memset(boolArray, 0, sizeof(boolArray));
  
  		Test* p1 = new Test(boolArray + 0);
  		EATEST_VERIFY(boolArray[0] && !boolArray[1] && !boolArray[2]);
  		intrusive_ptr<Test> arc1(p1);
  		EATEST_VERIFY(boolArray[0] && !boolArray[1] && !boolArray[2]);
  
  		Test* p2 = new Test(boolArray + 1);
  		EATEST_VERIFY(boolArray[0] && boolArray[1] && !boolArray[2]);
  		arc1 = p2;
  		EATEST_VERIFY(!boolArray[0] && boolArray[1] && !boolArray[2]);
  
  		Test* p3 = new Test(boolArray + 2);
  		EATEST_VERIFY(!boolArray[0] && boolArray[1] && boolArray[2]);
  		arc1 = p3;
  		EATEST_VERIFY(!boolArray[0] && !boolArray[1] && boolArray[2]);
  		arc1 = NULL;
  		
  		EATEST_VERIFY(!boolArray[0] && !boolArray[1] && !boolArray[2]);
  	}
  
  	{ // Test intrusive_ptr_add_ref() / intrusive_ptr_release()
  		IntrusiveCustom* const pIC = new IntrusiveCustom;
  
  		{
  			intrusive_ptr<IntrusiveCustom> bp = intrusive_ptr<IntrusiveCustom>(pIC);
  			intrusive_ptr<IntrusiveCustom> ap = bp;
  		}
  		
  		EATEST_VERIFY((IntrusiveCustom::mAddRefCallCount > 0) && (IntrusiveCustom::mReleaseCallCount == IntrusiveCustom::mAddRefCallCount));
  	}
  
  	{ // Regression
  		intrusive_ptr<IntrusiveChild>  bp = intrusive_ptr<IntrusiveChild>(new IntrusiveChild);
  		intrusive_ptr<IntrusiveParent> ap = bp;
  	}
  
  	return nErrorCount;
  }
  
  
  struct RandomLifetimeObject : public eastl::safe_object
  {
  	void DoSomething() const { }
  };
  
  
  
  static int Test_safe_ptr()
  {
  	using namespace SmartPtrTest;
  	using namespace eastl;
  
  	int nErrorCount = 0;
  
  	{   // non-const RandomLifetimeObject
  		RandomLifetimeObject* pObject = new RandomLifetimeObject;
  		eastl::safe_ptr<RandomLifetimeObject> pSafePtr(pObject);
  
  		eastl::safe_ptr<RandomLifetimeObject> pSafePtrCopy1 = pSafePtr;
  		eastl::safe_ptr<RandomLifetimeObject> pSafePtrCopy2(pSafePtr);
  
  		pSafePtr->DoSomething();
  
  		eastl::safe_ptr<RandomLifetimeObject>* pSafePtrCopy3 = new eastl::safe_ptr<RandomLifetimeObject>(pSafePtr);
  		eastl::safe_ptr<RandomLifetimeObject>* pSafePtrCopy4 = new eastl::safe_ptr<RandomLifetimeObject>(pSafePtr);
  		EATEST_VERIFY(pSafePtrCopy3->get() == pObject);
  		EATEST_VERIFY(pSafePtrCopy4->get() == pObject);
  		delete pSafePtrCopy3;
  		delete pSafePtrCopy4;
  
  		delete pSafePtr;
  
  		EATEST_VERIFY(pSafePtrCopy1.get() == NULL);
  		EATEST_VERIFY(pSafePtrCopy2.get() == NULL);
  	}
  
  	{   // const RandomLifetimeObject
  		RandomLifetimeObject* pObject = new RandomLifetimeObject;
  		eastl::safe_ptr<const RandomLifetimeObject> pSafePtr(pObject);
  
  		eastl::safe_ptr<const RandomLifetimeObject> pSafePtrCopy1(pSafePtr);
  		eastl::safe_ptr<const RandomLifetimeObject> pSafePtrCopy2 = pSafePtr;
  
  		pSafePtr->DoSomething();
  
  		eastl::safe_ptr<const RandomLifetimeObject>* pSafePtrCopy3 = new eastl::safe_ptr<const RandomLifetimeObject>(pSafePtr);
  		eastl::safe_ptr<const RandomLifetimeObject>* pSafePtrCopy4 = new eastl::safe_ptr<const RandomLifetimeObject>(pSafePtr);
  		EATEST_VERIFY(pSafePtrCopy3->get() == pObject);
  		EATEST_VERIFY(pSafePtrCopy4->get() == pObject);
  		delete pSafePtrCopy3;
  		delete pSafePtrCopy4;
  
  		delete pSafePtr;
  
  		EATEST_VERIFY(pSafePtrCopy1.get() == NULL);
  		EATEST_VERIFY(pSafePtrCopy2.get() == NULL);
  	}
  
  	return nErrorCount;
  }
  
  
  int TestSmartPtr()
  {
  	using namespace SmartPtrTest;
  	using namespace eastl;
  
  	int nErrorCount = 0;
  
  	nErrorCount += Test_unique_ptr();
  	nErrorCount += Test_scoped_ptr();
  	nErrorCount += Test_scoped_array();
  	nErrorCount += Test_shared_ptr();
  	nErrorCount += Test_shared_ptr_thread();
  	nErrorCount += Test_weak_ptr();
  	nErrorCount += Test_shared_array();
  	nErrorCount += Test_linked_ptr();
  	nErrorCount += Test_linked_array();
  	nErrorCount += Test_intrusive_ptr();
  	nErrorCount += Test_safe_ptr();
  
  	EATEST_VERIFY(A::mCount == 0);
  	EATEST_VERIFY(RefCountTest::mCount == 0);
  	EATEST_VERIFY(NamedClass::mnCount == 0);
  	EATEST_VERIFY(Y::mnCount == 0);
  	EATEST_VERIFY(ACLS::mnCount == 0);
  	EATEST_VERIFY(BCLS::mnCount == 0);
  	EATEST_VERIFY(A1::mnCount == 0);
  	EATEST_VERIFY(B1::mnCount == 0);
  
  	return nErrorCount;
  }
  
  EA_RESTORE_VC_WARNING()  // 4702
  
  
  
  
  
  
  
  