aboutsummaryrefslogtreecommitdiff
path: root/test/source/TestSmartPtr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'test/source/TestSmartPtr.cpp')
-rw-r--r--test/source/TestSmartPtr.cpp2230
1 files changed, 0 insertions, 2230 deletions
diff --git a/test/source/TestSmartPtr.cpp b/test/source/TestSmartPtr.cpp
deleted file mode 100644
index 8052392..0000000
--- a/test/source/TestSmartPtr.cpp
+++ /dev/null
@@ -1,2230 +0,0 @@
-/////////////////////////////////////////////////////////////////////////////
-// 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/atomic.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;
- };
-
- struct CheckUPtrEmptyInDestructor
- {
- ~CheckUPtrEmptyInDestructor()
- {
- if(mpUPtr)
- mCheckUPtrEmpty = (*mpUPtr == nullptr);
- }
-
- eastl::unique_ptr<CheckUPtrEmptyInDestructor>* mpUPtr{};
- static bool mCheckUPtrEmpty;
- };
-
- bool CheckUPtrEmptyInDestructor::mCheckUPtrEmpty = false;
-
- struct CheckUPtrArrayEmptyInDestructor
- {
- ~CheckUPtrArrayEmptyInDestructor()
- {
- if(mpUPtr)
- mCheckUPtrEmpty = (*mpUPtr == nullptr);
- }
-
- eastl::unique_ptr<CheckUPtrArrayEmptyInDestructor[]>* mpUPtr{};
- static bool mCheckUPtrEmpty;
- };
-
- bool CheckUPtrArrayEmptyInDestructor::mCheckUPtrEmpty = false;
-} // 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);
- }
- }
-
- {
- // Test that unique_ptr internal pointer is reset before calling the destructor
- CheckUPtrEmptyInDestructor::mCheckUPtrEmpty = false;
-
- unique_ptr<CheckUPtrEmptyInDestructor> uptr(new CheckUPtrEmptyInDestructor);
- uptr->mpUPtr = &uptr;
- uptr.reset();
- EATEST_VERIFY(CheckUPtrEmptyInDestructor::mCheckUPtrEmpty);
- }
-
- {
- // Test that unique_ptr<[]> internal pointer is reset before calling the destructor
- CheckUPtrArrayEmptyInDestructor::mCheckUPtrEmpty = false;
-
- unique_ptr<CheckUPtrArrayEmptyInDestructor[]> uptr(new CheckUPtrArrayEmptyInDestructor[1]);
- uptr[0].mpUPtr = &uptr;
- uptr.reset();
- EATEST_VERIFY(CheckUPtrArrayEmptyInDestructor::mCheckUPtrEmpty);
- }
-
- {
- #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
-
- #if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
- {
- unique_ptr<int> pT1(new int(5));
- unique_ptr<int> pT2(new int(10));
- unique_ptr<int> pT3(new int(0));
-
- EATEST_VERIFY((pT1 <=> pT2) != 0);
- EATEST_VERIFY((pT2 <=> pT1) != 0);
-
- EATEST_VERIFY((pT1 <=> pT2) < 0);
- EATEST_VERIFY((pT1 <=> pT2) <= 0);
- EATEST_VERIFY((pT2 <=> pT1) > 0);
- EATEST_VERIFY((pT2 <=> pT1) >= 0);
-
- EATEST_VERIFY((pT3 <=> pT1) < 0);
- EATEST_VERIFY((pT3 <=> pT2) < 0);
- EATEST_VERIFY((pT1 <=> pT3) > 0);
- EATEST_VERIFY((pT2 <=> pT3) > 0);
-
- unique_ptr<A> pT4(new A(5));
- unique_ptr<A> pT5(new A(10));
-
- EATEST_VERIFY((pT4 <=> pT5) != 0);
- EATEST_VERIFY((pT5 <=> pT4) != 0);
-
- EATEST_VERIFY((pT4 <=> pT5) < 0);
- EATEST_VERIFY((pT4 <=> pT5) <= 0);
- EATEST_VERIFY((pT5 <=> pT4) > 0);
- EATEST_VERIFY((pT5 <=> pT4) >= 0);
- }
- #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 shared_ptr lambda deleter
- auto deleter = [](int*) {};
- eastl::shared_ptr<int> ptr(nullptr, deleter);
-
- EATEST_VERIFY(!ptr);
- EATEST_VERIFY(ptr.get() == nullptr);
- }
-
-
- { // 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;
- eastl::atomic<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.load(eastl::memory_order_relaxed))
- {
- 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.store(false, eastl::memory_order_relaxed);
-
- 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);
-
- spTO = atomic_exchange_explicit(&spTO2, spTO);
- EATEST_VERIFY(spTO->mX == 77);
- EATEST_VERIFY(spTO2->mX == 56);
-
- // 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 == 56);
- EATEST_VERIFY(spTO->mX == 56);
-
- result = atomic_compare_exchange_strong(&spTO3, &spTO2, make_shared<TestObject>(88)); // spTO3 == spTO2, so this should succeed.
- EATEST_VERIFY(result);
- EATEST_VERIFY(spTO2->mX == 56);
- 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
- }
-
- { // weak_from_this const
- shared_ptr<const foo> pFoo(new foo);
- weak_ptr<const foo> qFoo = pFoo->weak_from_this();
-
- EATEST_VERIFY(pFoo == qFoo.lock());
- EATEST_VERIFY(!(pFoo < qFoo.lock()) && !(qFoo.lock() < pFoo)); // p and q share ownership
- }
-
- { // weak_from_this
- shared_ptr<foo> pFoo(new foo);
- weak_ptr<foo> qFoo = pFoo->weak_from_this();
-
- EATEST_VERIFY(pFoo == qFoo.lock());
- EATEST_VERIFY(!(pFoo < qFoo.lock()) && !(qFoo.lock() < 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
-
-
-
-
-
-
-