/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http:mozilla.org/MPL/2.0/. */
class nsFoo : public nsISupports {
NS_DECL_ISUPPORTS
nsresult DoFoo(bool* aBool) {
*aBool = true; return NS_OK;
}
private: virtual ~nsFoo() = default;
};
NS_IMPL_ISUPPORTS0(nsFoo)
class TestSuicide : public mozilla::Runnable { public:
TestSuicide() : mozilla::Runnable("TestSuicide") {}
NS_IMETHOD Run() override { // Runs first time on thread "Suicide", then dies on MainThread if (!NS_IsMainThread()) {
mThread = do_GetCurrentThread();
NS_DispatchToMainThread(this); return NS_OK;
}
MOZ_RELEASE_ASSERT(mThread);
mThread->Shutdown();
gRunnableExecuted[TEST_CALL_NEWTHREAD_SUICIDAL] = true; return NS_OK;
}
private:
nsCOMPtr<nsIThread> mThread;
};
class nsBar : public nsISupports { virtual ~nsBar() = default;
TEST(ThreadUtils, NewNamedRunnableFunction)
{ // The named overload shall behave identical to the non-named counterpart.
TestRunnableFactory<BasicRunnableFactory>(/*aNamed*/ true);
TEST(ThreadUtils, NewNamedCancelableRunnableFunction)
{ // The named overload shall behave identical to the non-named counterpart.
TestRunnableFactory<CancelableRunnableFactory>(/*aNamed*/ true);
staticvoid TestNewRunnableMethod(bool aNamed) {
memset(gRunnableExecuted, false, MAX_TESTS * sizeof(bool)); // Scope the smart ptrs so that the runnables need to hold on to whatever they // need
{
RefPtr<nsFoo> foo = new nsFoo();
RefPtr<nsBar> bar = new nsBar();
RefPtr<const nsBar> constBar = bar;
// This pointer will be freed at the end of the block // Do not dereference this pointer in the runnable method!
RefPtr<nsFoo> rawFoo = new nsFoo();
// Read only string. Dereferencing in runnable method to check this works. char* message = (char*)"Test message";
NS_DispatchToMainThread(
aNamed ? NewRunnableMethod("unused", bar, &nsBar::DoBar1)
: NewRunnableMethod("nsBar::DoBar1", bar, &nsBar::DoBar1));
NS_DispatchToMainThread(
aNamed ? NewRunnableMethod("unused", constBar, &nsBar::DoBar1Const)
: NewRunnableMethod("nsBar::DoBar1Const", constBar,
&nsBar::DoBar1Const));
NS_DispatchToMainThread(
aNamed ? NewRunnableMethod("unused", bar, &nsBar::DoBar2)
: NewRunnableMethod("nsBar::DoBar2", bar, &nsBar::DoBar2));
NS_DispatchToMainThread(
aNamed ? NewRunnableMethod<RefPtr<nsFoo>>("unused", bar, &nsBar::DoBar3,
foo)
: NewRunnableMethod<RefPtr<nsFoo>>("nsBar::DoBar3", bar,
&nsBar::DoBar3, foo));
NS_DispatchToMainThread(
aNamed ? NewRunnableMethod<RefPtr<nsFoo>>("unused", bar, &nsBar::DoBar4,
foo)
: NewRunnableMethod<RefPtr<nsFoo>>("nsBar::DoBar4", bar,
&nsBar::DoBar4, foo));
NS_DispatchToMainThread(
aNamed
? NewRunnableMethod<nsFoo*>("unused", bar, &nsBar::DoBar5, rawFoo)
: NewRunnableMethod<nsFoo*>("nsBar::DoBar5", bar, &nsBar::DoBar5,
rawFoo));
NS_DispatchToMainThread(
aNamed
? NewRunnableMethod<char*>("unused", bar, &nsBar::DoBar6, message)
: NewRunnableMethod<char*>("nsBar::DoBar6", bar, &nsBar::DoBar6,
message)); #ifdef HAVE_STDCALL
NS_DispatchToMainThread(
aNamed ? NewRunnableMethod("unused", bar, &nsBar::DoBar1std)
: NewRunnableMethod(bar, &nsBar::DoBar1std));
NS_DispatchToMainThread(
aNamed ? NewRunnableMethod("unused", bar, &nsBar::DoBar2std)
: NewRunnableMethod(bar, &nsBar::DoBar2std));
NS_DispatchToMainThread(
aNamed ? NewRunnableMethod<RefPtr<nsFoo>>("unused", bar,
&nsBar::DoBar3std, foo)
: NewRunnableMethod<RefPtr<nsFoo>>(bar, &nsBar::DoBar3std, foo));
NS_DispatchToMainThread(
aNamed ? NewRunnableMethod<RefPtr<nsFoo>>("unused", bar,
&nsBar::DoBar4std, foo)
: NewRunnableMethod<RefPtr<nsFoo>>(bar, &nsBar::DoBar4std, foo));
NS_DispatchToMainThread(
aNamed ? NewRunnableMethod<nsFoo*>("unused", bar, &nsBar::DoBar5std,
rawFoo)
: NewRunnableMethod<nsFoo*>(bar, &nsBar::DoBar5std, rawFoo));
NS_DispatchToMainThread(
aNamed ? NewRunnableMethod<char*>("unused", bar, &nsBar::DoBar6std,
message)
: NewRunnableMethod<char*>(bar, &nsBar::DoBar6std, message)); #endif
}
// Spin the event loop
NS_ProcessPendingEvents(nullptr);
// Now test a suicidal event in NS_New(Named)Thread
nsCOMPtr<nsIThread> thread;
NS_NewNamedThread("SuicideThread", getter_AddRefs(thread), new TestSuicide());
ASSERT_TRUE(thread);
while (!gRunnableExecuted[TEST_CALL_NEWTHREAD_SUICIDAL]) {
NS_ProcessPendingEvents(nullptr);
}
for (uint32_t i = 0; i < MAX_TESTS; i++) {
EXPECT_TRUE(gRunnableExecuted[i]) << "Error in test " << i;
}
}
TEST(ThreadUtils, NamedRunnableMethod)
{ // The named overloads shall behave identical to the non-named counterparts.
TestNewRunnableMethod(/* aNamed */ true);
// Disable test due to frequent failures #if 0 // because test fails on multiple platforms
TEST(ThreadUtils, IdleRunnableMethod)
{
{
RefPtr<IdleObject> idle = new IdleObject();
RefPtr<IdleObjectWithoutSetDeadline> idleNoSetDeadline = new IdleObjectWithoutSetDeadline();
RefPtr<IdleObjectInheritedSetDeadline> idleInheritedSetDeadline = new IdleObjectInheritedSetDeadline();
// Non-repeating but callback always return false so it's still repeating. int cnt2 = 0;
RefPtr<IdleTaskRunner> runner2 = IdleTaskRunner::Create(
[&cnt2](TimeStamp) {
cnt2++; returnfalse;
}, "runner2", 0, TimeDuration::FromMilliseconds(10),
TimeDuration::FromMilliseconds(3), false, nullptr);
// Repeating until cnt3 >= 2 by returning 'true' in MayStopProcessing // callback. The strategy is to stop repeating as early as possible so that we // are more probable to catch the bug if it didn't stop as expected. int cnt3 = 0;
RefPtr<IdleTaskRunner> runner3 = IdleTaskRunner::Create(
[&cnt3](TimeStamp) {
cnt3++; returntrue;
}, "runner3", 0, TimeDuration::FromMilliseconds(10),
TimeDuration::FromMilliseconds(3), true, [&cnt3] { return cnt3 >= 2; });
// Non-repeating can callback return true so the callback will // be only run once. int cnt4 = 0;
RefPtr<IdleTaskRunner> runner4 = IdleTaskRunner::Create(
[&cnt4](TimeStamp) {
cnt4++; returntrue;
}, "runner4", 0, TimeDuration::FromMilliseconds(10),
TimeDuration::FromMilliseconds(3), false, nullptr);
// Firstly we wait until the two repeating tasks reach their limits.
MOZ_ALWAYS_TRUE(
SpinEventLoopUntil("xpcom:TEST(ThreadUtils, IdleTaskRunner) cnt1"_ns,
[&]() { return cnt1 >= 100; }));
MOZ_ALWAYS_TRUE(
SpinEventLoopUntil("xpcom:TEST(ThreadUtils, IdleTaskRunner) cnt2"_ns,
[&]() { return cnt2 >= 100; }));
// At any point ==> 0 <= cnt3 <= 2 since MayStopProcessing() would return // true when cnt3 >= 2.
MOZ_ALWAYS_TRUE(SpinEventLoopUntil( "xpcom:TEST(ThreadUtils, IdleTaskRunner) cnt3"_ns, [&]() { if (cnt3 > 2) {
EXPECT_TRUE(false) << "MaybeContinueProcess() doesn't work."; returntrue; // Stop on failure.
} return cnt3 == 2; // Stop finish if we have reached its max value.
}));
// At any point ==> 0 <= cnt4 <= 1 since this is a non-repeating // idle runner.
MOZ_ALWAYS_TRUE(SpinEventLoopUntil( "xpcom:TEST(ThreadUtils, IdleTaskRunner) cnt4"_ns, [&]() { // At any point: 0 <= cnt4 <= 1 if (cnt4 > 1) {
EXPECT_TRUE(false) << "The 'mRepeating' flag doesn't work."; returntrue; // Stop on failure.
} return cnt4 == 1;
}));
// The repeating timers require an explicit Cancel() call.
runner1->Cancel();
runner2->Cancel();
}
TEST(ThreadUtils, TypeTraits)
{
static_assert(std::is_same_v<int, mozilla::RemoveSmartPointer<int>>, "RemoveSmartPointer should be int");
static_assert(std::is_same_v<int*, mozilla::RemoveSmartPointer<int*>>, "RemoveSmartPointer should be int*");
static_assert(std::is_same_v<UniquePtr<int>,
mozilla::RemoveSmartPointer<UniquePtr<int>>>, "RemoveSmartPointer> should be UniquePtr");
static_assert(std::is_same_v<int, mozilla::RemoveSmartPointer<RefPtr<int>>>, "RemoveSmartPointer> should be int");
static_assert(
std::is_same_v<int, mozilla::RemoveSmartPointer<const RefPtr<int>>>, "RemoveSmartPointer> should be int");
static_assert(
std::is_same_v<int, mozilla::RemoveSmartPointer<volatile RefPtr<int>>>, "RemoveSmartPointer> should be int");
static_assert(
std::is_same_v<int,
mozilla::RemoveSmartPointer<constvolatile RefPtr<int>>>, "RemoveSmartPointer> should be int");
static_assert(std::is_same_v<int, mozilla::RemoveSmartPointer<nsCOMPtr<int>>>, "RemoveSmartPointer> should be int");
static_assert(
std::is_same_v<int, mozilla::RemoveSmartPointer<const nsCOMPtr<int>>>, "RemoveSmartPointer> should be int");
static_assert(
std::is_same_v<int, mozilla::RemoveSmartPointer<volatile nsCOMPtr<int>>>, "RemoveSmartPointer> should be int");
static_assert(
std::is_same_v<int,
mozilla::RemoveSmartPointer<constvolatile nsCOMPtr<int>>>, "RemoveSmartPointer> should be int");
static_assert(std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<int>>, "RemoveRawOrSmartPointer should be int");
static_assert(
std::is_same_v<UniquePtr<int>,
mozilla::RemoveRawOrSmartPointer<UniquePtr<int>>>, "RemoveRawOrSmartPointer> should be UniquePtr");
static_assert(std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<int*>>, "RemoveRawOrSmartPointer should be int");
static_assert(
std::is_same_v<constint, mozilla::RemoveRawOrSmartPointer<constint*>>, "RemoveRawOrSmartPointer should be const int");
static_assert(
std::is_same_v<volatileint,
mozilla::RemoveRawOrSmartPointer<volatileint*>>, "RemoveRawOrSmartPointer should be volatile int");
static_assert(
std::is_same_v<constvolatileint,
mozilla::RemoveRawOrSmartPointer<constvolatileint*>>, "RemoveRawOrSmartPointer should be const " "volatile int");
static_assert(
std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<RefPtr<int>>>, "RemoveRawOrSmartPointer> should be int");
static_assert(
std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<const RefPtr<int>>>, "RemoveRawOrSmartPointer> should be int");
static_assert(
std::is_same_v<int,
mozilla::RemoveRawOrSmartPointer<volatile RefPtr<int>>>, "RemoveRawOrSmartPointer> should be int");
static_assert(
std::is_same_v< int, mozilla::RemoveRawOrSmartPointer<constvolatile RefPtr<int>>>, "RemoveRawOrSmartPointer> should be " "int");
static_assert(
std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<nsCOMPtr<int>>>, "RemoveRawOrSmartPointer> should be int");
static_assert(
std::is_same_v<int,
mozilla::RemoveRawOrSmartPointer<const nsCOMPtr<int>>>, "RemoveRawOrSmartPointer> should be int");
static_assert(
std::is_same_v<int,
mozilla::RemoveRawOrSmartPointer<volatile nsCOMPtr<int>>>, "RemoveRawOrSmartPointer> should be int");
static_assert(
std::is_same_v< int, mozilla::RemoveRawOrSmartPointer<constvolatile nsCOMPtr<int>>>, "RemoveRawOrSmartPointer> should be " "int");
}
class ThreadUtilsRefCountedFinal final { public:
ThreadUtilsRefCountedFinal() : m_refCount(0) {}
~ThreadUtilsRefCountedFinal() = default; // 'AddRef' and 'Release' methods with different return types, to verify // that the return type doesn't influence storage selection. long AddRef(void) { return ++m_refCount; } void Release(void) { --m_refCount; }
private: long m_refCount;
};
class ThreadUtilsRefCountedBase { public:
ThreadUtilsRefCountedBase() : m_refCount(0) {} virtual ~ThreadUtilsRefCountedBase() = default; // 'AddRef' and 'Release' methods with different return types, to verify // that the return type doesn't influence storage selection. virtualvoid AddRef(void) { ++m_refCount; } virtual MozExternalRefCountType Release(void) { return --m_refCount; }
private:
MozExternalRefCountType m_refCount;
};
class ThreadUtilsRefCountedDerived : public ThreadUtilsRefCountedBase {};
static_assert(!IsParameterStorageClass<int>::value, "'int' should not be recognized as Storage Class");
static_assert(
IsParameterStorageClass<StoreCopyPassByConstLRef<int>>::value, "StoreCopyPassByConstLRef should be recognized as Storage Class");
static_assert(
IsParameterStorageClass<StoreCopyPassByRRef<int>>::value, "StoreCopyPassByRRef should be recognized as Storage Class");
static_assert(
IsParameterStorageClass<StoreRefPassByLRef<int>>::value, "StoreRefPassByLRef should be recognized as Storage Class");
static_assert(
IsParameterStorageClass<StoreConstRefPassByConstLRef<int>>::value, "StoreConstRefPassByConstLRef should be recognized as Storage " "Class");
static_assert(
IsParameterStorageClass<StoreRefPtrPassByPtr<int>>::value, "StoreRefPtrPassByPtr should be recognized as Storage Class");
static_assert(IsParameterStorageClass<StorePtrPassByPtr<int>>::value, "StorePtrPassByPtr should be recognized as Storage Class");
static_assert(
IsParameterStorageClass<StoreConstPtrPassByConstPtr<int>>::value, "StoreConstPtrPassByConstPtr should be recognized as Storage Class");
RefPtr<ThreadUtilsObject> rpt(new ThreadUtilsObject); int count = 0;
static_assert(std::is_same_v<::detail::ParameterStorage<int>::Type,
StoreCopyPassByConstLRef<int>>, "detail::ParameterStorage::Type should be " "StoreCopyPassByConstLRef");
// Passing a short to make sure forwarding works with an inexact type match. shortint si = 11;
r1 = NewRunnableMethod<int>("TestThreadUtils::ThreadUtilsObject::Test1i", rpt,
&ThreadUtilsObject::Test1i, si);
r1->Run();
EXPECT_EQ(count += 2, rpt->mCount);
EXPECT_EQ(si, rpt->mA0);
// Raw pointer, possible cv-qualified.
static_assert(
std::is_same_v<::detail::ParameterStorage<int*>::Type,
StorePtrPassByPtr<int>>, "detail::ParameterStorage::Type should be StorePtrPassByPtr");
static_assert(std::is_same_v<::detail::ParameterStorage<int* const>::Type,
StorePtrPassByPtr<int>>, "detail::ParameterStorage::Type should be " "StorePtrPassByPtr");
static_assert(std::is_same_v<::detail::ParameterStorage<int* volatile>::Type,
StorePtrPassByPtr<int>>, "detail::ParameterStorage::Type should be " "StorePtrPassByPtr");
static_assert(
std::is_same_v<::detail::ParameterStorage<int* constvolatile>::Type,
StorePtrPassByPtr<int>>, "detail::ParameterStorage::Type should be " "StorePtrPassByPtr");
static_assert(
std::is_same_v<::detail::ParameterStorage<int*>::Type::stored_type, int*>, "detail::ParameterStorage::Type::stored_type should be int*");
static_assert(
std::is_same_v<::detail::ParameterStorage<int*>::Type::passed_type, int*>, "detail::ParameterStorage::Type::passed_type should be int*");
{ int i = 12;
r1 = NewRunnableMethod<int*>("TestThreadUtils::ThreadUtilsObject::Test1pi",
rpt, &ThreadUtilsObject::Test1pi, &i);
r1->Run();
EXPECT_EQ(count += 2, rpt->mCount);
EXPECT_EQ(i, rpt->mA0);
}
// Raw pointer to const.
static_assert(std::is_same_v<::detail::ParameterStorage<constint*>::Type,
StoreConstPtrPassByConstPtr<int>>, "detail::ParameterStorage::Type should be " "StoreConstPtrPassByConstPtr");
static_assert(
std::is_same_v<::detail::ParameterStorage<constint* const>::Type,
StoreConstPtrPassByConstPtr<int>>, "detail::ParameterStorage::Type should be " "StoreConstPtrPassByConstPtr");
static_assert(
std::is_same_v<::detail::ParameterStorage<constint* volatile>::Type,
StoreConstPtrPassByConstPtr<int>>, "detail::ParameterStorage::Type should be " "StoreConstPtrPassByConstPtr");
static_assert(std::is_same_v<
::detail::ParameterStorage<constint* constvolatile>::Type,
StoreConstPtrPassByConstPtr<int>>, "detail::ParameterStorage::Type " "should be StoreConstPtrPassByConstPtr");
static_assert(
std::is_same_v<::detail::ParameterStorage<constint*>::Type::stored_type, constint*>, "detail::ParameterStorage::Type::stored_type should be const " "int*");
static_assert(
std::is_same_v<::detail::ParameterStorage<constint*>::Type::passed_type, constint*>, "detail::ParameterStorage::Type::passed_type should be const " "int*");
{ int i = 1201;
r1 = NewRunnableMethod<constint*>( "TestThreadUtils::ThreadUtilsObject::Test1pci", rpt,
&ThreadUtilsObject::Test1pci, &i);
r1->Run();
EXPECT_EQ(count += 2, rpt->mCount);
EXPECT_EQ(i, rpt->mA0);
}
// nsRefPtr to pointer.
static_assert(
std::is_same_v<::detail::ParameterStorage<
StoreRefPtrPassByPtr<SpyWithISupports>>::Type,
StoreRefPtrPassByPtr<SpyWithISupports>>, "ParameterStorage>::Type should " "be StoreRefPtrPassByPtr");
static_assert(
std::is_same_v<::detail::ParameterStorage<SpyWithISupports*>::Type,
StoreRefPtrPassByPtr<SpyWithISupports>>, "ParameterStorage::Type should be " "StoreRefPtrPassByPtr");
static_assert(
std::is_same_v<StoreRefPtrPassByPtr<SpyWithISupports>::stored_type,
RefPtr<SpyWithISupports>>, "StoreRefPtrPassByPtr::stored_type should be " "RefPtr");
static_assert(
std::is_same_v<StoreRefPtrPassByPtr<SpyWithISupports>::passed_type,
SpyWithISupports*>, "StoreRefPtrPassByPtr::passed_type should be " "SpyWithISupports*"); // (more nsRefPtr tests below)
// nsRefPtr for ref-countable classes that do not derive from ISupports.
static_assert(::detail::HasRefCountMethods<ThreadUtilsRefCountedFinal>, "ThreadUtilsRefCountedFinal has AddRef() and Release()");
static_assert(
std::is_same_v<
::detail::ParameterStorage<ThreadUtilsRefCountedFinal*>::Type,
StoreRefPtrPassByPtr<ThreadUtilsRefCountedFinal>>, "ParameterStorage::Type should be " "StoreRefPtrPassByPtr");
static_assert(::detail::HasRefCountMethods<ThreadUtilsRefCountedBase>, "ThreadUtilsRefCountedBase has AddRef() and Release()");
static_assert(
std::is_same_v<
::detail::ParameterStorage<ThreadUtilsRefCountedBase*>::Type,
StoreRefPtrPassByPtr<ThreadUtilsRefCountedBase>>, "ParameterStorage::Type should be " "StoreRefPtrPassByPtr");
static_assert(::detail::HasRefCountMethods<ThreadUtilsRefCountedDerived>, "ThreadUtilsRefCountedDerived has AddRef() and Release()");
static_assert(
std::is_same_v<
::detail::ParameterStorage<ThreadUtilsRefCountedDerived*>::Type,
StoreRefPtrPassByPtr<ThreadUtilsRefCountedDerived>>, "ParameterStorage::Type should be " "StoreRefPtrPassByPtr");
static_assert(!::detail::HasRefCountMethods<ThreadUtilsNonRefCounted>, "ThreadUtilsNonRefCounted doesn't have AddRef() and Release()");
static_assert(!std::is_same_v<
::detail::ParameterStorage<ThreadUtilsNonRefCounted*>::Type,
StoreRefPtrPassByPtr<ThreadUtilsNonRefCounted>>, "ParameterStorage::Type should NOT " "be StoreRefPtrPassByPtr");
// Lvalue reference.
static_assert(
std::is_same_v<::detail::ParameterStorage<int&>::Type,
StoreRefPassByLRef<int>>, "ParameterStorage::Type should be StoreRefPassByLRef");
static_assert(
std::is_same_v<::detail::ParameterStorage<int&>::Type::stored_type,
StoreRefPassByLRef<int>::stored_type>, "ParameterStorage::Type::stored_type should be " "StoreRefPassByLRef::stored_type");
static_assert(
std::is_same_v<::detail::ParameterStorage<int&>::Type::stored_type, int&>, "ParameterStorage::Type::stored_type should be int&");
static_assert(
std::is_same_v<::detail::ParameterStorage<int&>::Type::passed_type, int&>, "ParameterStorage::Type::passed_type should be int&");
{ int i = 13;
r1 = NewRunnableMethod<int&>("TestThreadUtils::ThreadUtilsObject::Test1ri",
rpt, &ThreadUtilsObject::Test1ri, i);
r1->Run();
EXPECT_EQ(count += 2, rpt->mCount);
EXPECT_EQ(i, rpt->mA0);
}
// Rvalue reference -- Actually storing a copy and then moving it.
static_assert(
std::is_same_v<::detail::ParameterStorage<int&&>::Type,
StoreCopyPassByRRef<int>>, "ParameterStorage::Type should be StoreCopyPassByRRef");
static_assert(
std::is_same_v<::detail::ParameterStorage<int&&>::Type::stored_type,
StoreCopyPassByRRef<int>::stored_type>, "ParameterStorage::Type::stored_type should be " "StoreCopyPassByRRef::stored_type");
static_assert(
std::is_same_v<::detail::ParameterStorage<int&&>::Type::stored_type, int>, "ParameterStorage::Type::stored_type should be int");
static_assert(
std::is_same_v<::detail::ParameterStorage<int&&>::Type::passed_type, int&&>, "ParameterStorage::Type::passed_type should be int&&");
{ int i = 14;
r1 = NewRunnableMethod<int&&>( "TestThreadUtils::ThreadUtilsObject::Test1rri", rpt,
&ThreadUtilsObject::Test1rri, std::move(i));
}
r1->Run();
EXPECT_EQ(count += 2, rpt->mCount);
EXPECT_EQ(14, rpt->mA0);
// Null unique pointer, by semi-implicit store&move with "T&&" syntax.
static_assert(std::is_same_v<
::detail::ParameterStorage<mozilla::UniquePtr<int>&&>::Type,
StoreCopyPassByRRef<mozilla::UniquePtr<int>>>, "ParameterStorage&&>::Type should be " "StoreCopyPassByRRef>");
static_assert(
std::is_same_v<::detail::ParameterStorage<
mozilla::UniquePtr<int>&&>::Type::stored_type,
StoreCopyPassByRRef<mozilla::UniquePtr<int>>::stored_type>, "ParameterStorage&&>::Type::stored_type should be " "StoreCopyPassByRRef>::stored_type");
static_assert(
std::is_same_v<::detail::ParameterStorage<
mozilla::UniquePtr<int>&&>::Type::stored_type,
mozilla::UniquePtr<int>>, "ParameterStorage&&>::Type::stored_type should be " "UniquePtr");
static_assert(
std::is_same_v<::detail::ParameterStorage<
mozilla::UniquePtr<int>&&>::Type::passed_type,
mozilla::UniquePtr<int>&&>, "ParameterStorage&&>::Type::passed_type should be " "UniquePtr&&");
{
mozilla::UniquePtr<int> upi;
r1 = NewRunnableMethod<mozilla::UniquePtr<int>&&>( "TestThreadUtils::ThreadUtilsObject::Test1upi", rpt,
&ThreadUtilsObject::Test1upi, std::move(upi));
}
r1->Run();
EXPECT_EQ(count += 2, rpt->mCount);
EXPECT_EQ(-1, rpt->mA0);
rpt->mA0 = 0;
// Null unique pointer, by explicit store&move with "StoreCopyPassByRRef<T>" // syntax.
static_assert(
std::is_same_v<::detail::ParameterStorage<StoreCopyPassByRRef<
mozilla::UniquePtr<int>>>::Type::stored_type,
StoreCopyPassByRRef<mozilla::UniquePtr<int>>::stored_type>, "ParameterStorage>>::Type::stored_" "type should be StoreCopyPassByRRef>::stored_type");
static_assert(
std::is_same_v<::detail::ParameterStorage<StoreCopyPassByRRef<
mozilla::UniquePtr<int>>>::Type::stored_type,
StoreCopyPassByRRef<mozilla::UniquePtr<int>>::stored_type>, "ParameterStorage>>::Type::stored_" "type should be StoreCopyPassByRRef>::stored_type");
static_assert(
std::is_same_v<::detail::ParameterStorage<StoreCopyPassByRRef<
mozilla::UniquePtr<int>>>::Type::stored_type,
mozilla::UniquePtr<int>>, "ParameterStorage>>::Type::stored_" "type should be UniquePtr");
static_assert(
std::is_same_v<::detail::ParameterStorage<StoreCopyPassByRRef<
mozilla::UniquePtr<int>>>::Type::passed_type,
mozilla::UniquePtr<int>&&>, "ParameterStorage>>::Type::passed_" "type should be UniquePtr&&");
{
mozilla::UniquePtr<int> upi;
r1 = NewRunnableMethod<StoreCopyPassByRRef<mozilla::UniquePtr<int>>>( "TestThreadUtils::ThreadUtilsObject::Test1upi", rpt,
&ThreadUtilsObject::Test1upi, std::move(upi));
}
r1->Run();
EXPECT_EQ(count += 2, rpt->mCount);
EXPECT_EQ(-1, rpt->mA0);
// Unique pointer as lvalue to lref.
{
mozilla::UniquePtr<int> upi;
r1 = NewRunnableMethod<mozilla::UniquePtr<int>&>( "TestThreadUtils::ThreadUtilsObject::Test1rupi", rpt,
&ThreadUtilsObject::Test1rupi, upi); // Passed as lref, so Run() must be called while local upi is still alive!
r1->Run();
}
EXPECT_EQ(count += 2, rpt->mCount);
EXPECT_EQ(-1, rpt->mA0);
// Verify copy/move assumptions.
Spy::ClearAll(); if (gDebug) {
printf("%d - Test: Store copy from lvalue, pass by const lvalue ref\n",
__LINE__);
}
{ // Block around nsCOMPtr lifetime.
nsCOMPtr<nsIRunnable> r5;
{ // Block around Spy lifetime. if (gDebug) {
printf("%d - Spy s(20)\n", __LINE__);
}
Spy s(20);
EXPECT_EQ(1, gConstructions);
EXPECT_EQ(1, gAlive); if (gDebug) {
printf( "%d - r5 = " "NewRunnableMethod>(&TestByConstLRef," " s)\n",
__LINE__);
}
r5 = NewRunnableMethod<StoreCopyPassByConstLRef<Spy>>( "TestThreadUtils::ThreadUtilsObject::TestByConstLRef", rpt,
&ThreadUtilsObject::TestByConstLRef, s);
EXPECT_EQ(2, gAlive);
EXPECT_LE(1, gCopyConstructions); // At least 1 copy-construction.
Spy::ClearActions(); if (gDebug) {
printf("%d - End block with Spy s(20)\n", __LINE__);
}
}
EXPECT_EQ(1, gDestructions);
EXPECT_EQ(1, gAlive);
Spy::ClearActions(); if (gDebug) {
printf("%d - Run()\n", __LINE__);
}
r5->Run();
EXPECT_EQ(0, gCopyConstructions); // No copies in call.
EXPECT_EQ(20, rpt->mSpy.mID);
EXPECT_EQ(0, gDestructions);
EXPECT_EQ(1, gAlive);
Spy::ClearActions(); if (gDebug) {
printf("%d - End block with r\n", __LINE__);
}
} if (gDebug) {
printf("%d - After end block with r\n", __LINE__);
}
EXPECT_EQ(1, gDestructions);
EXPECT_EQ(0, gAlive);
Spy::ClearAll(); if (gDebug) {
printf("%d - Test: Store copy from prvalue, pass by const lvalue ref\n",
__LINE__);
}
{ if (gDebug) {
printf( "%d - r6 = " "NewRunnableMethod>(&TestByConstLRef, " "Spy(21))\n",
__LINE__);
}
nsCOMPtr<nsIRunnable> r6 = NewRunnableMethod<StoreCopyPassByConstLRef<Spy>>( "TestThreadUtils::ThreadUtilsObject::TestByConstLRef", rpt,
&ThreadUtilsObject::TestByConstLRef, Spy(21));
EXPECT_EQ(1, gAlive);
EXPECT_EQ(1, gConstructions);
EXPECT_LE(1, gMoveConstructions);
Spy::ClearActions(); if (gDebug) {
printf("%d - Run()\n", __LINE__);
}
r6->Run();
EXPECT_EQ(0, gCopyConstructions); // No copies in call.
EXPECT_EQ(21, rpt->mSpy.mID);
EXPECT_EQ(0, gDestructions);
EXPECT_EQ(1, gAlive);
Spy::ClearActions(); if (gDebug) {
printf("%d - End block with r\n", __LINE__);
}
} if (gDebug) {
printf("%d - After end block with r\n", __LINE__);
}
EXPECT_EQ(1, gDestructions);
EXPECT_EQ(0, gAlive);
Spy::ClearAll(); if (gDebug) {
printf("%d - Test: Store copy from lvalue, pass by rvalue ref\n", __LINE__);
}
{ // Block around nsCOMPtr lifetime.
nsCOMPtr<nsIRunnable> r7;
{ // Block around Spy lifetime. if (gDebug) {
printf("%d - Spy s(30)\n", __LINE__);
}
Spy s(30);
EXPECT_EQ(1, gConstructions);
EXPECT_EQ(1, gAlive); if (gDebug) {
printf( "%d - r7 = " "NewRunnableMethod>(&TestByRRef, s)\n",
__LINE__);
}
r7 = NewRunnableMethod<StoreCopyPassByRRef<Spy>>( "TestThreadUtils::ThreadUtilsObject::TestByRRef", rpt,
&ThreadUtilsObject::TestByRRef, s);
EXPECT_EQ(2, gAlive);
EXPECT_LE(1, gCopyConstructions); // At least 1 copy-construction.
Spy::ClearActions(); if (gDebug) {
printf("%d - End block with Spy s(30)\n", __LINE__);
}
}
EXPECT_EQ(1, gDestructions);
EXPECT_EQ(1, gAlive);
Spy::ClearActions(); if (gDebug) {
printf("%d - Run()\n", __LINE__);
}
r7->Run();
EXPECT_LE(1, gMoves); // Move in call.
EXPECT_EQ(30, rpt->mSpy.mID);
EXPECT_EQ(0, gDestructions);
EXPECT_EQ(0, gAlive); // Spy inside Test is not counted.
EXPECT_EQ(1, gZombies); // Our local spy should now be a zombie.
Spy::ClearActions(); if (gDebug) {
printf("%d - End block with r\n", __LINE__);
}
} if (gDebug) {
printf("%d - After end block with r\n", __LINE__);
}
EXPECT_EQ(1, gDestructions);
EXPECT_EQ(0, gAlive);
Spy::ClearAll(); if (gDebug) {
printf("%d - Test: Store copy from prvalue, pass by rvalue ref\n",
__LINE__);
}
{ if (gDebug) {
printf( "%d - r8 = NewRunnableMethod>(&TestByRRef, " "Spy(31))\n",
__LINE__);
}
nsCOMPtr<nsIRunnable> r8 = NewRunnableMethod<StoreCopyPassByRRef<Spy>>( "TestThreadUtils::ThreadUtilsObject::TestByRRef", rpt,
&ThreadUtilsObject::TestByRRef, Spy(31));
EXPECT_EQ(1, gAlive);
EXPECT_EQ(1, gConstructions);
EXPECT_LE(1, gMoveConstructions);
Spy::ClearActions(); if (gDebug) {
printf("%d - Run()\n", __LINE__);
}
r8->Run();
EXPECT_LE(1, gMoves); // Move in call.
EXPECT_EQ(31, rpt->mSpy.mID);
EXPECT_EQ(0, gDestructions);
EXPECT_EQ(0, gAlive); // Spy inside Test is not counted.
EXPECT_EQ(1, gZombies); // Our local spy should now be a zombie.
Spy::ClearActions(); if (gDebug) {
printf("%d - End block with r\n", __LINE__);
}
} if (gDebug) {
printf("%d - After end block with r\n", __LINE__);
}
EXPECT_EQ(1, gDestructions);
EXPECT_EQ(0, gAlive);
Spy::ClearAll(); if (gDebug) {
printf("%d - Test: Store lvalue ref, pass lvalue ref\n", __LINE__);
}
{ if (gDebug) {
printf("%d - Spy s(40)\n", __LINE__);
}
Spy s(40);
EXPECT_EQ(1, gConstructions);
EXPECT_EQ(1, gAlive);
Spy::ClearActions(); if (gDebug) {
printf("%d - r9 = NewRunnableMethod(&TestByLRef, s)\n", __LINE__);
}
nsCOMPtr<nsIRunnable> r9 = NewRunnableMethod<Spy&>( "TestThreadUtils::ThreadUtilsObject::TestByLRef", rpt,
&ThreadUtilsObject::TestByLRef, s);
EXPECT_EQ(0, gAllConstructions);
EXPECT_EQ(0, gDestructions);
EXPECT_EQ(1, gAlive);
Spy::ClearActions(); if (gDebug) {
printf("%d - Run()\n", __LINE__);
}
r9->Run();
EXPECT_LE(1, gAssignments); // Assignment from reference in call.
EXPECT_EQ(40, rpt->mSpy.mID);
EXPECT_EQ(&s, rpt->mSpyPtr);
EXPECT_EQ(0, gDestructions);
EXPECT_EQ(1, gAlive); // Spy inside Test is not counted.
Spy::ClearActions(); if (gDebug) {
printf("%d - End block with r\n", __LINE__);
}
} if (gDebug) {
printf("%d - After end block with r\n", __LINE__);
}
EXPECT_EQ(1, gDestructions);
EXPECT_EQ(0, gAlive);
Spy::ClearAll(); if (gDebug) {
printf("%d - Test: Store nsRefPtr, pass by pointer\n", __LINE__);
}
{ // Block around nsCOMPtr lifetime.
nsCOMPtr<nsIRunnable> r10;
SpyWithISupports* ptr = 0;
{ // Block around RefPtr<Spy> lifetime. if (gDebug) {
printf("%d - RefPtr s(new SpyWithISupports(45))\n",
__LINE__);
}
RefPtr<SpyWithISupports> s(new SpyWithISupports(45));
ptr = s.get();
--> --------------------
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.