Backed out 6 changesets (bug 1880192) for causing build bustages on MozPromise.h. CLOSED TREE

Backed out changeset b73f06a9fdb1 (bug 1880192)
Backed out changeset ee04f994bad8 (bug 1880192)
Backed out changeset 8c7a686c8691 (bug 1880192)
Backed out changeset 15e93c260557 (bug 1880192)
Backed out changeset b5f62ac62087 (bug 1880192)
Backed out changeset ff2d8eae2a68 (bug 1880192)
This commit is contained in:
Iulian Moraru 2024-02-27 20:41:39 +02:00
parent 8cc44430a4
commit 0783fb05a1
9 changed files with 602 additions and 289 deletions

View file

@ -318,7 +318,7 @@ struct AudioChunk {
* A list of audio samples consisting of a sequence of slices of SharedBuffers. * A list of audio samples consisting of a sequence of slices of SharedBuffers.
* The audio rate is determined by the track, not stored in this class. * The audio rate is determined by the track, not stored in this class.
*/ */
class AudioSegment final : public MediaSegmentBase<AudioSegment, AudioChunk> { class AudioSegment : public MediaSegmentBase<AudioSegment, AudioChunk> {
// The channel count that MaxChannelCount() returned last time it was called. // The channel count that MaxChannelCount() returned last time it was called.
uint32_t mMemoizedMaxChannelCount = 0; uint32_t mMemoizedMaxChannelCount = 0;

View file

@ -109,8 +109,8 @@ class VideoFrameConverter {
// for processing so it can be immediately sent. // for processing so it can be immediately sent.
mLastFrameQueuedForProcessing.mTime = time; mLastFrameQueuedForProcessing.mTime = time;
MOZ_ALWAYS_SUCCEEDS( MOZ_ALWAYS_SUCCEEDS(mTaskQueue->Dispatch(
mTaskQueue->Dispatch(NewRunnableMethod<FrameToProcess>( NewRunnableMethod<StoreCopyPassByLRef<FrameToProcess>>(
"VideoFrameConverter::ProcessVideoFrame", this, "VideoFrameConverter::ProcessVideoFrame", this,
&VideoFrameConverter::ProcessVideoFrame, &VideoFrameConverter::ProcessVideoFrame,
mLastFrameQueuedForProcessing))); mLastFrameQueuedForProcessing)));
@ -138,8 +138,8 @@ class VideoFrameConverter {
mLastFrameQueuedForProcessing.mForceBlack = true; mLastFrameQueuedForProcessing.mForceBlack = true;
mLastFrameQueuedForProcessing.mImage = nullptr; mLastFrameQueuedForProcessing.mImage = nullptr;
MOZ_ALWAYS_SUCCEEDS( MOZ_ALWAYS_SUCCEEDS(mTaskQueue->Dispatch(
mTaskQueue->Dispatch(NewRunnableMethod<FrameToProcess>( NewRunnableMethod<StoreCopyPassByLRef<FrameToProcess>>(
"VideoFrameConverter::ProcessVideoFrame", this, "VideoFrameConverter::ProcessVideoFrame", this,
&VideoFrameConverter::ProcessVideoFrame, &VideoFrameConverter::ProcessVideoFrame,
mLastFrameQueuedForProcessing))); mLastFrameQueuedForProcessing)));
@ -293,10 +293,11 @@ class VideoFrameConverter {
return; return;
} }
MOZ_ALWAYS_SUCCEEDS(mTaskQueue->Dispatch(NewRunnableMethod<FrameToProcess>( MOZ_ALWAYS_SUCCEEDS(mTaskQueue->Dispatch(
"VideoFrameConverter::ProcessVideoFrame", this, NewRunnableMethod<StoreCopyPassByLRef<FrameToProcess>>(
&VideoFrameConverter::ProcessVideoFrame, "VideoFrameConverter::ProcessVideoFrame", this,
mLastFrameQueuedForProcessing))); &VideoFrameConverter::ProcessVideoFrame,
mLastFrameQueuedForProcessing)));
} }
void ProcessVideoFrame(const FrameToProcess& aFrame) { void ProcessVideoFrame(const FrameToProcess& aFrame) {

View file

@ -437,13 +437,12 @@ uint32_t SpeechRecognition::ProcessAudioSegment(AudioSegment* aSegment,
// we need to call the nsISpeechRecognitionService::ProcessAudioSegment // we need to call the nsISpeechRecognitionService::ProcessAudioSegment
// in a separate thread so that any eventual encoding or pre-processing // in a separate thread so that any eventual encoding or pre-processing
// of the audio does not block the main thread // of the audio does not block the main thread
nsresult rv = mEncodeTaskQueue->Dispatch(NS_NewRunnableFunction( nsresult rv = mEncodeTaskQueue->Dispatch(
"nsISpeechRecognitionService::ProcessAudioSegment", NewRunnableMethod<StoreCopyPassByPtr<AudioSegment>, TrackRate>(
[=, service = mRecognitionService, "nsISpeechRecognitionService::ProcessAudioSegment",
segment = std::move(*aSegment)]() mutable { mRecognitionService,
service->ProcessAudioSegment(&segment, aTrackRate); &nsISpeechRecognitionService::ProcessAudioSegment,
})); std::move(*aSegment), aTrackRate));
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv)); MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
Unused << rv; Unused << rv;
return samples; return samples;

View file

@ -394,7 +394,8 @@ void APZCTreeManager::SetAllowedTouchBehavior(
uint64_t aInputBlockId, const nsTArray<TouchBehaviorFlags>& aValues) { uint64_t aInputBlockId, const nsTArray<TouchBehaviorFlags>& aValues) {
if (!APZThreadUtils::IsControllerThread()) { if (!APZThreadUtils::IsControllerThread()) {
APZThreadUtils::RunOnControllerThread( APZThreadUtils::RunOnControllerThread(
NewRunnableMethod<uint64_t, nsTArray<TouchBehaviorFlags>>( NewRunnableMethod<uint64_t,
StoreCopyPassByLRef<nsTArray<TouchBehaviorFlags>>>(
"layers::APZCTreeManager::SetAllowedTouchBehavior", this, "layers::APZCTreeManager::SetAllowedTouchBehavior", this,
&APZCTreeManager::SetAllowedTouchBehavior, aInputBlockId, &APZCTreeManager::SetAllowedTouchBehavior, aInputBlockId,
aValues.Clone())); aValues.Clone()));

View file

@ -364,13 +364,13 @@ nsresult nsWifiMonitor::DoScan() {
} }
return NS_DispatchToMainThread( return NS_DispatchToMainThread(
NewRunnableMethod<nsTArray<RefPtr<nsIWifiAccessPoint>>, bool>( NewRunnableMethod<const nsTArray<RefPtr<nsIWifiAccessPoint>>&&, bool>(
"CallWifiListeners", this, &nsWifiMonitor::CallWifiListeners, "CallWifiListeners", this, &nsWifiMonitor::CallWifiListeners,
mLastAccessPoints.Clone(), accessPointsChanged)); mLastAccessPoints.Clone(), accessPointsChanged));
} }
nsresult nsWifiMonitor::CallWifiListeners( nsresult nsWifiMonitor::CallWifiListeners(
const nsTArray<RefPtr<nsIWifiAccessPoint>>& aAccessPoints, nsTArray<RefPtr<nsIWifiAccessPoint>>&& aAccessPoints,
bool aAccessPointsChanged) { bool aAccessPointsChanged) {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
LOG(("Sending wifi access points to the listeners")); LOG(("Sending wifi access points to the listeners"));

View file

@ -69,7 +69,7 @@ class nsWifiMonitor final : public nsIWifiMonitor, public nsIObserver {
nsresult DoScan(); nsresult DoScan();
nsresult CallWifiListeners( nsresult CallWifiListeners(
const nsTArray<RefPtr<nsIWifiAccessPoint>>& aAccessPoints, nsTArray<RefPtr<nsIWifiAccessPoint>>&& aAccessPoints,
bool aAccessPointsChanged); bool aAccessPointsChanged);
nsresult PassErrorToWifiListeners(nsresult rv); nsresult PassErrorToWifiListeners(nsresult rv);

View file

@ -885,88 +885,122 @@ TEST(ThreadUtils, IdleTaskRunner)
TEST(ThreadUtils, TypeTraits) TEST(ThreadUtils, TypeTraits)
{ {
static_assert(std::is_same_v<int, mozilla::RemoveSmartPointer<int>>, static_assert(!mozilla::IsRefcountedSmartPointer<int>::value,
"RemoveSmartPointer<int> should be int"); "IsRefcountedSmartPointer<int> should be false");
static_assert(std::is_same_v<int*, mozilla::RemoveSmartPointer<int*>>, static_assert(mozilla::IsRefcountedSmartPointer<RefPtr<int>>::value,
"RemoveSmartPointer<int*> should be int*"); "IsRefcountedSmartPointer<RefPtr<...>> should be true");
static_assert(std::is_same_v<UniquePtr<int>, static_assert(mozilla::IsRefcountedSmartPointer<const RefPtr<int>>::value,
mozilla::RemoveSmartPointer<UniquePtr<int>>>, "IsRefcountedSmartPointer<const RefPtr<...>> should be true");
"RemoveSmartPointer<UniquePtr<int>> should be UniquePtr<int>");
static_assert(std::is_same_v<int, mozilla::RemoveSmartPointer<RefPtr<int>>>,
"RemoveSmartPointer<RefPtr<int>> should be int");
static_assert( static_assert(
std::is_same_v<int, mozilla::RemoveSmartPointer<const RefPtr<int>>>, mozilla::IsRefcountedSmartPointer<volatile RefPtr<int>>::value,
"RemoveSmartPointer<const RefPtr<int>> should be int"); "IsRefcountedSmartPointer<volatile RefPtr<...>> should be true");
static_assert( static_assert(
std::is_same_v<int, mozilla::RemoveSmartPointer<volatile RefPtr<int>>>, mozilla::IsRefcountedSmartPointer<const volatile RefPtr<int>>::value,
"RemoveSmartPointer<volatile RefPtr<int>> should be int"); "IsRefcountedSmartPointer<const volatile RefPtr<...>> should be true");
static_assert(mozilla::IsRefcountedSmartPointer<nsCOMPtr<int>>::value,
"IsRefcountedSmartPointer<nsCOMPtr<...>> should be true");
static_assert(mozilla::IsRefcountedSmartPointer<const nsCOMPtr<int>>::value,
"IsRefcountedSmartPointer<const nsCOMPtr<...>> should be true");
static_assert( static_assert(
std::is_same_v<int, mozilla::IsRefcountedSmartPointer<volatile nsCOMPtr<int>>::value,
mozilla::RemoveSmartPointer<const volatile RefPtr<int>>>, "IsRefcountedSmartPointer<volatile nsCOMPtr<...>> should be true");
"RemoveSmartPointer<const volatile RefPtr<int>> should be int");
static_assert(std::is_same_v<int, mozilla::RemoveSmartPointer<nsCOMPtr<int>>>,
"RemoveSmartPointer<nsCOMPtr<int>> should be int");
static_assert( static_assert(
std::is_same_v<int, mozilla::RemoveSmartPointer<const nsCOMPtr<int>>>, mozilla::IsRefcountedSmartPointer<const volatile nsCOMPtr<int>>::value,
"RemoveSmartPointer<const nsCOMPtr<int>> should be int"); "IsRefcountedSmartPointer<const volatile nsCOMPtr<...>> should be true");
static_assert(
std::is_same_v<int, mozilla::RemoveSmartPointer<volatile nsCOMPtr<int>>>,
"RemoveSmartPointer<volatile nsCOMPtr<int>> should be int");
static_assert(
std::is_same_v<int,
mozilla::RemoveSmartPointer<const volatile nsCOMPtr<int>>>,
"RemoveSmartPointer<const volatile nsCOMPtr<int>> should be int");
static_assert(std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<int>>, static_assert(std::is_same_v<int, mozilla::RemoveSmartPointer<int>::Type>,
"RemoveRawOrSmartPointer<int> should be int"); "RemoveSmartPointer<int>::Type should be int");
static_assert(std::is_same_v<int*, mozilla::RemoveSmartPointer<int*>::Type>,
"RemoveSmartPointer<int*>::Type should be int*");
static_assert( static_assert(
std::is_same_v<UniquePtr<int>, std::is_same_v<UniquePtr<int>,
mozilla::RemoveRawOrSmartPointer<UniquePtr<int>>>, mozilla::RemoveSmartPointer<UniquePtr<int>>::Type>,
"RemoveRawOrSmartPointer<UniquePtr<int>> should be UniquePtr<int>"); "RemoveSmartPointer<UniquePtr<int>>::Type should be UniquePtr<int>");
static_assert(std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<int*>>,
"RemoveRawOrSmartPointer<int*> should be int");
static_assert( static_assert(
std::is_same_v<const int, mozilla::RemoveRawOrSmartPointer<const int*>>, std::is_same_v<int, mozilla::RemoveSmartPointer<RefPtr<int>>::Type>,
"RemoveRawOrSmartPointer<const int*> should be const int"); "RemoveSmartPointer<RefPtr<int>>::Type should be int");
static_assert(
std::is_same_v<int, mozilla::RemoveSmartPointer<const RefPtr<int>>::Type>,
"RemoveSmartPointer<const RefPtr<int>>::Type should be int");
static_assert(
std::is_same_v<int,
mozilla::RemoveSmartPointer<volatile RefPtr<int>>::Type>,
"RemoveSmartPointer<volatile RefPtr<int>>::Type should be int");
static_assert(
std::is_same_v<
int, mozilla::RemoveSmartPointer<const volatile RefPtr<int>>::Type>,
"RemoveSmartPointer<const volatile RefPtr<int>>::Type should be int");
static_assert(
std::is_same_v<int, mozilla::RemoveSmartPointer<nsCOMPtr<int>>::Type>,
"RemoveSmartPointer<nsCOMPtr<int>>::Type should be int");
static_assert(
std::is_same_v<int,
mozilla::RemoveSmartPointer<const nsCOMPtr<int>>::Type>,
"RemoveSmartPointer<const nsCOMPtr<int>>::Type should be int");
static_assert(
std::is_same_v<int,
mozilla::RemoveSmartPointer<volatile nsCOMPtr<int>>::Type>,
"RemoveSmartPointer<volatile nsCOMPtr<int>>::Type should be int");
static_assert(
std::is_same_v<
int, mozilla::RemoveSmartPointer<const volatile nsCOMPtr<int>>::Type>,
"RemoveSmartPointer<const volatile nsCOMPtr<int>>::Type should be int");
static_assert(
std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<int>::Type>,
"RemoveRawOrSmartPointer<int>::Type should be int");
static_assert(
std::is_same_v<UniquePtr<int>,
mozilla::RemoveRawOrSmartPointer<UniquePtr<int>>::Type>,
"RemoveRawOrSmartPointer<UniquePtr<int>>::Type should be UniquePtr<int>");
static_assert(
std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<int*>::Type>,
"RemoveRawOrSmartPointer<int*>::Type should be int");
static_assert(
std::is_same_v<const int,
mozilla::RemoveRawOrSmartPointer<const int*>::Type>,
"RemoveRawOrSmartPointer<const int*>::Type should be const int");
static_assert( static_assert(
std::is_same_v<volatile int, std::is_same_v<volatile int,
mozilla::RemoveRawOrSmartPointer<volatile int*>>, mozilla::RemoveRawOrSmartPointer<volatile int*>::Type>,
"RemoveRawOrSmartPointer<volatile int*> should be volatile int"); "RemoveRawOrSmartPointer<volatile int*>::Type should be volatile int");
static_assert( static_assert(
std::is_same_v<const volatile int, std::is_same_v<const volatile int, mozilla::RemoveRawOrSmartPointer<
mozilla::RemoveRawOrSmartPointer<const volatile int*>>, const volatile int*>::Type>,
"RemoveRawOrSmartPointer<const volatile int*> should be const " "RemoveRawOrSmartPointer<const volatile int*>::Type should be const "
"volatile int"); "volatile int");
static_assert( static_assert(
std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<RefPtr<int>>>, std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<RefPtr<int>>::Type>,
"RemoveRawOrSmartPointer<RefPtr<int>> should be int"); "RemoveRawOrSmartPointer<RefPtr<int>>::Type should be int");
static_assert(
std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<const RefPtr<int>>>,
"RemoveRawOrSmartPointer<const RefPtr<int>> should be int");
static_assert( static_assert(
std::is_same_v<int, std::is_same_v<int,
mozilla::RemoveRawOrSmartPointer<volatile RefPtr<int>>>, mozilla::RemoveRawOrSmartPointer<const RefPtr<int>>::Type>,
"RemoveRawOrSmartPointer<volatile RefPtr<int>> should be int"); "RemoveRawOrSmartPointer<const RefPtr<int>>::Type should be int");
static_assert( static_assert(
std::is_same_v< std::is_same_v<
int, mozilla::RemoveRawOrSmartPointer<const volatile RefPtr<int>>>, int, mozilla::RemoveRawOrSmartPointer<volatile RefPtr<int>>::Type>,
"RemoveRawOrSmartPointer<const volatile RefPtr<int>> should be " "RemoveRawOrSmartPointer<volatile RefPtr<int>>::Type should be int");
static_assert(
std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<
const volatile RefPtr<int>>::Type>,
"RemoveRawOrSmartPointer<const volatile RefPtr<int>>::Type should be "
"int"); "int");
static_assert(
std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<nsCOMPtr<int>>>,
"RemoveRawOrSmartPointer<nsCOMPtr<int>> should be int");
static_assert( static_assert(
std::is_same_v<int, std::is_same_v<int,
mozilla::RemoveRawOrSmartPointer<const nsCOMPtr<int>>>, mozilla::RemoveRawOrSmartPointer<nsCOMPtr<int>>::Type>,
"RemoveRawOrSmartPointer<const nsCOMPtr<int>> should be int"); "RemoveRawOrSmartPointer<nsCOMPtr<int>>::Type should be int");
static_assert(
std::is_same_v<int,
mozilla::RemoveRawOrSmartPointer<volatile nsCOMPtr<int>>>,
"RemoveRawOrSmartPointer<volatile nsCOMPtr<int>> should be int");
static_assert( static_assert(
std::is_same_v< std::is_same_v<
int, mozilla::RemoveRawOrSmartPointer<const volatile nsCOMPtr<int>>>, int, mozilla::RemoveRawOrSmartPointer<const nsCOMPtr<int>>::Type>,
"RemoveRawOrSmartPointer<const volatile nsCOMPtr<int>> should be " "RemoveRawOrSmartPointer<const nsCOMPtr<int>>::Type should be int");
static_assert(
std::is_same_v<
int, mozilla::RemoveRawOrSmartPointer<volatile nsCOMPtr<int>>::Type>,
"RemoveRawOrSmartPointer<volatile nsCOMPtr<int>>::Type should be int");
static_assert(
std::is_same_v<int, mozilla::RemoveRawOrSmartPointer<
const volatile nsCOMPtr<int>>::Type>,
"RemoveRawOrSmartPointer<const volatile nsCOMPtr<int>>::Type should be "
"int"); "int");
} }
@ -1254,9 +1288,15 @@ TEST(ThreadUtils, main)
static_assert(!IsParameterStorageClass<int>::value, static_assert(!IsParameterStorageClass<int>::value,
"'int' should not be recognized as Storage Class"); "'int' should not be recognized as Storage Class");
static_assert(
IsParameterStorageClass<StoreCopyPassByValue<int>>::value,
"StoreCopyPassByValue<int> should be recognized as Storage Class");
static_assert( static_assert(
IsParameterStorageClass<StoreCopyPassByConstLRef<int>>::value, IsParameterStorageClass<StoreCopyPassByConstLRef<int>>::value,
"StoreCopyPassByConstLRef<int> should be recognized as Storage Class"); "StoreCopyPassByConstLRef<int> should be recognized as Storage Class");
static_assert(
IsParameterStorageClass<StoreCopyPassByLRef<int>>::value,
"StoreCopyPassByLRef<int> should be recognized as Storage Class");
static_assert( static_assert(
IsParameterStorageClass<StoreCopyPassByRRef<int>>::value, IsParameterStorageClass<StoreCopyPassByRRef<int>>::value,
"StoreCopyPassByRRef<int> should be recognized as Storage Class"); "StoreCopyPassByRRef<int> should be recognized as Storage Class");
@ -1275,6 +1315,12 @@ TEST(ThreadUtils, main)
static_assert( static_assert(
IsParameterStorageClass<StoreConstPtrPassByConstPtr<int>>::value, IsParameterStorageClass<StoreConstPtrPassByConstPtr<int>>::value,
"StoreConstPtrPassByConstPtr<int> should be recognized as Storage Class"); "StoreConstPtrPassByConstPtr<int> should be recognized as Storage Class");
static_assert(
IsParameterStorageClass<StoreCopyPassByConstPtr<int>>::value,
"StoreCopyPassByConstPtr<int> should be recognized as Storage Class");
static_assert(
IsParameterStorageClass<StoreCopyPassByPtr<int>>::value,
"StoreCopyPassByPtr<int> should be recognized as Storage Class");
RefPtr<ThreadUtilsObject> rpt(new ThreadUtilsObject); RefPtr<ThreadUtilsObject> rpt(new ThreadUtilsObject);
int count = 0; int count = 0;
@ -1313,6 +1359,11 @@ TEST(ThreadUtils, main)
StoreCopyPassByConstLRef<int>>, StoreCopyPassByConstLRef<int>>,
"detail::ParameterStorage<int>::Type should be " "detail::ParameterStorage<int>::Type should be "
"StoreCopyPassByConstLRef<int>"); "StoreCopyPassByConstLRef<int>");
static_assert(std::is_same_v<
::detail::ParameterStorage<StoreCopyPassByValue<int>>::Type,
StoreCopyPassByValue<int>>,
"detail::ParameterStorage<StoreCopyPassByValue<int>>::Type "
"should be StoreCopyPassByValue<int>");
r1 = NewRunnableMethod<int>("TestThreadUtils::ThreadUtilsObject::Test1i", rpt, r1 = NewRunnableMethod<int>("TestThreadUtils::ThreadUtilsObject::Test1i", rpt,
&ThreadUtilsObject::Test1i, 12); &ThreadUtilsObject::Test1i, 12);
@ -1429,6 +1480,37 @@ TEST(ThreadUtils, main)
EXPECT_EQ(i, rpt->mA0); EXPECT_EQ(i, rpt->mA0);
} }
// Raw pointer to copy.
static_assert(std::is_same_v<StoreCopyPassByPtr<int>::stored_type, int>,
"StoreCopyPassByPtr<int>::stored_type should be int");
static_assert(std::is_same_v<StoreCopyPassByPtr<int>::passed_type, int*>,
"StoreCopyPassByPtr<int>::passed_type should be int*");
{
int i = 1202;
r1 = NewRunnableMethod<StoreCopyPassByPtr<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 copy.
static_assert(std::is_same_v<StoreCopyPassByConstPtr<int>::stored_type, int>,
"StoreCopyPassByConstPtr<int>::stored_type should be int");
static_assert(
std::is_same_v<StoreCopyPassByConstPtr<int>::passed_type, const int*>,
"StoreCopyPassByConstPtr<int>::passed_type should be const int*");
{
int i = 1203;
r1 = NewRunnableMethod<StoreCopyPassByConstPtr<int>>(
"TestThreadUtils::ThreadUtilsObject::Test1pci", rpt,
&ThreadUtilsObject::Test1pci, i);
r1->Run();
EXPECT_EQ(count += 2, rpt->mCount);
EXPECT_EQ(i, rpt->mA0);
}
// nsRefPtr to pointer. // nsRefPtr to pointer.
static_assert( static_assert(
std::is_same_v<::detail::ParameterStorage< std::is_same_v<::detail::ParameterStorage<
@ -1454,7 +1536,7 @@ TEST(ThreadUtils, main)
// (more nsRefPtr tests below) // (more nsRefPtr tests below)
// nsRefPtr for ref-countable classes that do not derive from ISupports. // nsRefPtr for ref-countable classes that do not derive from ISupports.
static_assert(::detail::HasRefCountMethods<ThreadUtilsRefCountedFinal>, static_assert(::detail::HasRefCountMethods<ThreadUtilsRefCountedFinal>::value,
"ThreadUtilsRefCountedFinal has AddRef() and Release()"); "ThreadUtilsRefCountedFinal has AddRef() and Release()");
static_assert( static_assert(
std::is_same_v< std::is_same_v<
@ -1462,7 +1544,7 @@ TEST(ThreadUtils, main)
StoreRefPtrPassByPtr<ThreadUtilsRefCountedFinal>>, StoreRefPtrPassByPtr<ThreadUtilsRefCountedFinal>>,
"ParameterStorage<ThreadUtilsRefCountedFinal*>::Type should be " "ParameterStorage<ThreadUtilsRefCountedFinal*>::Type should be "
"StoreRefPtrPassByPtr<ThreadUtilsRefCountedFinal>"); "StoreRefPtrPassByPtr<ThreadUtilsRefCountedFinal>");
static_assert(::detail::HasRefCountMethods<ThreadUtilsRefCountedBase>, static_assert(::detail::HasRefCountMethods<ThreadUtilsRefCountedBase>::value,
"ThreadUtilsRefCountedBase has AddRef() and Release()"); "ThreadUtilsRefCountedBase has AddRef() and Release()");
static_assert( static_assert(
std::is_same_v< std::is_same_v<
@ -1470,8 +1552,9 @@ TEST(ThreadUtils, main)
StoreRefPtrPassByPtr<ThreadUtilsRefCountedBase>>, StoreRefPtrPassByPtr<ThreadUtilsRefCountedBase>>,
"ParameterStorage<ThreadUtilsRefCountedBase*>::Type should be " "ParameterStorage<ThreadUtilsRefCountedBase*>::Type should be "
"StoreRefPtrPassByPtr<ThreadUtilsRefCountedBase>"); "StoreRefPtrPassByPtr<ThreadUtilsRefCountedBase>");
static_assert(::detail::HasRefCountMethods<ThreadUtilsRefCountedDerived>, static_assert(
"ThreadUtilsRefCountedDerived has AddRef() and Release()"); ::detail::HasRefCountMethods<ThreadUtilsRefCountedDerived>::value,
"ThreadUtilsRefCountedDerived has AddRef() and Release()");
static_assert( static_assert(
std::is_same_v< std::is_same_v<
::detail::ParameterStorage<ThreadUtilsRefCountedDerived*>::Type, ::detail::ParameterStorage<ThreadUtilsRefCountedDerived*>::Type,
@ -1479,7 +1562,7 @@ TEST(ThreadUtils, main)
"ParameterStorage<ThreadUtilsRefCountedDerived*>::Type should be " "ParameterStorage<ThreadUtilsRefCountedDerived*>::Type should be "
"StoreRefPtrPassByPtr<ThreadUtilsRefCountedDerived>"); "StoreRefPtrPassByPtr<ThreadUtilsRefCountedDerived>");
static_assert(!::detail::HasRefCountMethods<ThreadUtilsNonRefCounted>, static_assert(!::detail::HasRefCountMethods<ThreadUtilsNonRefCounted>::value,
"ThreadUtilsNonRefCounted doesn't have AddRef() and Release()"); "ThreadUtilsNonRefCounted doesn't have AddRef() and Release()");
static_assert(!std::is_same_v< static_assert(!std::is_same_v<
::detail::ParameterStorage<ThreadUtilsNonRefCounted*>::Type, ::detail::ParameterStorage<ThreadUtilsNonRefCounted*>::Type,
@ -1653,6 +1736,126 @@ TEST(ThreadUtils, main)
// Verify copy/move assumptions. // Verify copy/move assumptions.
Spy::ClearAll();
if (gDebug) {
printf("%d - Test: Store copy from lvalue, pass by value\n", __LINE__);
}
{ // Block around nsCOMPtr lifetime.
nsCOMPtr<nsIRunnable> r2;
{ // Block around Spy lifetime.
if (gDebug) {
printf("%d - Spy s(10)\n", __LINE__);
}
Spy s(10);
EXPECT_EQ(1, gConstructions);
EXPECT_EQ(1, gAlive);
if (gDebug) {
printf(
"%d - r2 = "
"NewRunnableMethod<StoreCopyPassByValue<Spy>>(&TestByValue, s)\n",
__LINE__);
}
r2 = NewRunnableMethod<StoreCopyPassByValue<Spy>>(
"TestThreadUtils::ThreadUtilsObject::TestByValue", rpt,
&ThreadUtilsObject::TestByValue, 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(10)\n", __LINE__);
}
}
EXPECT_EQ(1, gDestructions);
EXPECT_EQ(1, gAlive);
Spy::ClearActions();
if (gDebug) {
printf("%d - Run()\n", __LINE__);
}
r2->Run();
EXPECT_LE(1, gCopyConstructions); // Another copy-construction in call.
EXPECT_EQ(10, rpt->mSpy.mID);
EXPECT_LE(1, 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 value\n", __LINE__);
}
{
if (gDebug) {
printf(
"%d - r3 = "
"NewRunnableMethod<StoreCopyPassByValue<Spy>>(&TestByValue, "
"Spy(11))\n",
__LINE__);
}
nsCOMPtr<nsIRunnable> r3 = NewRunnableMethod<StoreCopyPassByValue<Spy>>(
"TestThreadUtils::ThreadUtilsObject::TestByValue", rpt,
&ThreadUtilsObject::TestByValue, Spy(11));
EXPECT_EQ(1, gAlive);
EXPECT_EQ(1, gConstructions);
EXPECT_LE(1, gMoveConstructions);
Spy::ClearActions();
if (gDebug) {
printf("%d - Run()\n", __LINE__);
}
r3->Run();
EXPECT_LE(1, gCopyConstructions); // Another copy-construction in call.
EXPECT_EQ(11, rpt->mSpy.mID);
EXPECT_LE(1, 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();
{ // Store copy from xvalue, pass by value.
nsCOMPtr<nsIRunnable> r4;
{
Spy s(12);
EXPECT_EQ(1, gConstructions);
EXPECT_EQ(1, gAlive);
Spy::ClearActions();
r4 = NewRunnableMethod<StoreCopyPassByValue<Spy>>(
"TestThreadUtils::ThreadUtilsObject::TestByValue", rpt,
&ThreadUtilsObject::TestByValue, std::move(s));
EXPECT_LE(1, gMoveConstructions);
EXPECT_EQ(1, gAlive);
EXPECT_EQ(1, gZombies);
Spy::ClearActions();
}
EXPECT_EQ(1, gDestructions);
EXPECT_EQ(1, gAlive);
EXPECT_EQ(0, gZombies);
Spy::ClearActions();
r4->Run();
EXPECT_LE(1, gCopyConstructions); // Another copy-construction in call.
EXPECT_EQ(12, rpt->mSpy.mID);
EXPECT_LE(1, gDestructions);
EXPECT_EQ(1, gAlive);
Spy::ClearActions();
}
EXPECT_EQ(1, gDestructions);
EXPECT_EQ(0, gAlive);
// Won't test xvalues anymore, prvalues are enough to verify all rvalues.
Spy::ClearAll(); Spy::ClearAll();
if (gDebug) { if (gDebug) {
printf("%d - Test: Store copy from lvalue, pass by const lvalue ref\n", printf("%d - Test: Store copy from lvalue, pass by const lvalue ref\n",

View file

@ -82,22 +82,24 @@ struct MethodTrait : MethodTraitsHelper<std::remove_reference_t<T>> {};
} // namespace detail } // namespace detail
template <typename T>
using MethodReturnType = typename detail::MethodTrait<T>::ReturnType;
template <typename MethodType> template <typename MethodType>
constexpr bool TakesAnyArguments = using TakesArgument =
detail::MethodTrait<MethodType>::ArgSize != 0; std::integral_constant<bool, detail::MethodTrait<MethodType>::ArgSize != 0>;
template <typename MethodType, typename TargetType>
using ReturnTypeIs =
std::is_convertible<typename detail::MethodTrait<MethodType>::ReturnType,
TargetType>;
template <typename ResolveValueT, typename RejectValueT, bool IsExclusive> template <typename ResolveValueT, typename RejectValueT, bool IsExclusive>
class MozPromise; class MozPromise;
template <typename T> template <typename Return>
constexpr bool IsMozPromise = false; struct IsMozPromise : std::false_type {};
template <typename ResolveValueT, typename RejectValueT, bool IsExclusive> template <typename ResolveValueT, typename RejectValueT, bool IsExclusive>
constexpr bool struct IsMozPromise<MozPromise<ResolveValueT, RejectValueT, IsExclusive>>
IsMozPromise<MozPromise<ResolveValueT, RejectValueT, IsExclusive>> = true; : std::true_type {};
/* /*
* A promise manages an asynchronous request that may or may not be able to be * A promise manages an asynchronous request that may or may not be able to be
@ -174,8 +176,8 @@ class MozPromise : public MozPromiseBase {
} }
public: public:
using ResolveValueType = ResolveValueT; typedef ResolveValueT ResolveValueType;
using RejectValueType = RejectValueT; typedef RejectValueT RejectValueType;
class ResolveOrRejectValue { class ResolveOrRejectValue {
public: public:
template <typename ResolveValueType_> template <typename ResolveValueType_>
@ -286,10 +288,12 @@ class MozPromise : public MozPromiseBase {
return p; return p;
} }
using AllPromiseType = MozPromise<CopyableTArray<ResolveValueType>, typedef MozPromise<CopyableTArray<ResolveValueType>, RejectValueType,
RejectValueType, IsExclusive>; IsExclusive>
using AllSettledPromiseType = AllPromiseType;
MozPromise<CopyableTArray<ResolveOrRejectValue>, bool, IsExclusive>;
typedef MozPromise<CopyableTArray<ResolveOrRejectValue>, bool, IsExclusive>
AllSettledPromiseType;
private: private:
class AllPromiseHolder : public MozPromiseRefcountable { class AllPromiseHolder : public MozPromiseRefcountable {
@ -346,17 +350,17 @@ class MozPromise : public MozPromiseBase {
// Trying to pass ResolveOrRejectValue by value fails static analysis checks, // Trying to pass ResolveOrRejectValue by value fails static analysis checks,
// so we need to use either a const& or an rvalue reference, depending on // so we need to use either a const& or an rvalue reference, depending on
// whether IsExclusive is true or not. // whether IsExclusive is true or not.
using ResolveOrRejectValueParam = typedef std::conditional_t<IsExclusive, ResolveOrRejectValue&&,
std::conditional_t<IsExclusive, ResolveOrRejectValue&&, const ResolveOrRejectValue&>
const ResolveOrRejectValue&>; ResolveOrRejectValueParam;
using ResolveValueTypeParam = typedef std::conditional_t<IsExclusive, ResolveValueType&&,
std::conditional_t<IsExclusive, ResolveValueType&&, const ResolveValueType&>
const ResolveValueType&>; ResolveValueTypeParam;
using RejectValueTypeParam = typedef std::conditional_t<IsExclusive, RejectValueType&&,
std::conditional_t<IsExclusive, RejectValueType&&, const RejectValueType&>
const RejectValueType&>; RejectValueTypeParam;
class AllSettledPromiseHolder : public MozPromiseRefcountable { class AllSettledPromiseHolder : public MozPromiseRefcountable {
public: public:
@ -644,15 +648,15 @@ class MozPromise : public MozPromiseBase {
* make the resolve/reject value argument "optional". * make the resolve/reject value argument "optional".
*/ */
template <typename ThisType, typename MethodType, typename ValueType> template <typename ThisType, typename MethodType, typename ValueType>
static std::enable_if_t<TakesAnyArguments<MethodType>, static std::enable_if_t<TakesArgument<MethodType>::value,
MethodReturnType<MethodType>> typename detail::MethodTrait<MethodType>::ReturnType>
InvokeMethod(ThisType* aThisVal, MethodType aMethod, ValueType&& aValue) { InvokeMethod(ThisType* aThisVal, MethodType aMethod, ValueType&& aValue) {
return (aThisVal->*aMethod)(std::forward<ValueType>(aValue)); return (aThisVal->*aMethod)(std::forward<ValueType>(aValue));
} }
template <typename ThisType, typename MethodType, typename ValueType> template <typename ThisType, typename MethodType, typename ValueType>
static std::enable_if_t<!TakesAnyArguments<MethodType>, static std::enable_if_t<!TakesArgument<MethodType>::value,
MethodReturnType<MethodType>> typename detail::MethodTrait<MethodType>::ReturnType>
InvokeMethod(ThisType* aThisVal, MethodType aMethod, ValueType&& aValue) { InvokeMethod(ThisType* aThisVal, MethodType aMethod, ValueType&& aValue) {
return (aThisVal->*aMethod)(); return (aThisVal->*aMethod)();
} }
@ -693,14 +697,18 @@ class MozPromise : public MozPromiseBase {
: public ThenValueBase { : public ThenValueBase {
friend class ThenCommand<ThenValue>; friend class ThenCommand<ThenValue>;
using R1 = RemoveSmartPointer<MethodReturnType<ResolveMethodType>>; using R1 = typename RemoveSmartPointer<
using R2 = RemoveSmartPointer<MethodReturnType<RejectMethodType>>; typename detail::MethodTrait<ResolveMethodType>::ReturnType>::Type;
constexpr static bool SupportChaining = using R2 = typename RemoveSmartPointer<
IsMozPromise<R1> && std::is_same_v<R1, R2>; typename detail::MethodTrait<RejectMethodType>::ReturnType>::Type;
using SupportChaining =
std::integral_constant<bool, IsMozPromise<R1>::value &&
std::is_same_v<R1, R2>>;
// Fall back to MozPromise when promise chaining is not supported to make // Fall back to MozPromise when promise chaining is not supported to make
// code compile. // code compile.
using PromiseType = std::conditional_t<SupportChaining, R1, MozPromise>; using PromiseType =
std::conditional_t<SupportChaining::value, R1, MozPromise>;
public: public:
ThenValue(nsISerialEventTarget* aResponseTarget, ThisType* aThisVal, ThenValue(nsISerialEventTarget* aResponseTarget, ThisType* aThisVal,
@ -728,13 +736,13 @@ class MozPromise : public MozPromiseBase {
void DoResolveOrRejectInternal(ResolveOrRejectValue& aValue) override { void DoResolveOrRejectInternal(ResolveOrRejectValue& aValue) override {
if (aValue.IsResolve()) { if (aValue.IsResolve()) {
InvokeCallbackMethod<SupportChaining>(mThisVal.get(), mResolveMethod, InvokeCallbackMethod<SupportChaining::value>(
MaybeMove(aValue.ResolveValue()), mThisVal.get(), mResolveMethod, MaybeMove(aValue.ResolveValue()),
std::move(mCompletionPromise)); std::move(mCompletionPromise));
} else { } else {
InvokeCallbackMethod<SupportChaining>(mThisVal.get(), mRejectMethod, InvokeCallbackMethod<SupportChaining::value>(
MaybeMove(aValue.RejectValue()), mThisVal.get(), mRejectMethod, MaybeMove(aValue.RejectValue()),
std::move(mCompletionPromise)); std::move(mCompletionPromise));
} }
// Null out mThisVal after invoking the callback so that any references // Null out mThisVal after invoking the callback so that any references
@ -756,12 +764,15 @@ class MozPromise : public MozPromiseBase {
class ThenValue<ThisType*, ResolveRejectMethodType> : public ThenValueBase { class ThenValue<ThisType*, ResolveRejectMethodType> : public ThenValueBase {
friend class ThenCommand<ThenValue>; friend class ThenCommand<ThenValue>;
using R1 = RemoveSmartPointer<MethodReturnType<ResolveRejectMethodType>>; using R1 = typename RemoveSmartPointer<typename detail::MethodTrait<
constexpr static bool SupportChaining = IsMozPromise<R1>; ResolveRejectMethodType>::ReturnType>::Type;
using SupportChaining =
std::integral_constant<bool, IsMozPromise<R1>::value>;
// Fall back to MozPromise when promise chaining is not supported to make // Fall back to MozPromise when promise chaining is not supported to make
// code compile. // code compile.
using PromiseType = std::conditional_t<SupportChaining, R1, MozPromise>; using PromiseType =
std::conditional_t<SupportChaining::value, R1, MozPromise>;
public: public:
ThenValue(nsISerialEventTarget* aResponseTarget, ThisType* aThisVal, ThenValue(nsISerialEventTarget* aResponseTarget, ThisType* aThisVal,
@ -787,7 +798,7 @@ class MozPromise : public MozPromiseBase {
} }
void DoResolveOrRejectInternal(ResolveOrRejectValue& aValue) override { void DoResolveOrRejectInternal(ResolveOrRejectValue& aValue) override {
InvokeCallbackMethod<SupportChaining>( InvokeCallbackMethod<SupportChaining::value>(
mThisVal.get(), mResolveRejectMethod, MaybeMove(aValue), mThisVal.get(), mResolveRejectMethod, MaybeMove(aValue),
std::move(mCompletionPromise)); std::move(mCompletionPromise));
@ -811,14 +822,18 @@ class MozPromise : public MozPromiseBase {
class ThenValue<ResolveFunction, RejectFunction> : public ThenValueBase { class ThenValue<ResolveFunction, RejectFunction> : public ThenValueBase {
friend class ThenCommand<ThenValue>; friend class ThenCommand<ThenValue>;
using R1 = RemoveSmartPointer<MethodReturnType<ResolveFunction>>; using R1 = typename RemoveSmartPointer<
using R2 = RemoveSmartPointer<MethodReturnType<RejectFunction>>; typename detail::MethodTrait<ResolveFunction>::ReturnType>::Type;
constexpr static bool SupportChaining = using R2 = typename RemoveSmartPointer<
IsMozPromise<R1> && std::is_same_v<R1, R2>; typename detail::MethodTrait<RejectFunction>::ReturnType>::Type;
using SupportChaining =
std::integral_constant<bool, IsMozPromise<R1>::value &&
std::is_same_v<R1, R2>>;
// Fall back to MozPromise when promise chaining is not supported to make // Fall back to MozPromise when promise chaining is not supported to make
// code compile. // code compile.
using PromiseType = std::conditional_t<SupportChaining, R1, MozPromise>; using PromiseType =
std::conditional_t<SupportChaining::value, R1, MozPromise>;
public: public:
ThenValue(nsISerialEventTarget* aResponseTarget, ThenValue(nsISerialEventTarget* aResponseTarget,
@ -852,11 +867,11 @@ class MozPromise : public MozPromiseBase {
// easily. We could fix this if need be, though it's quite easy to work // easily. We could fix this if need be, though it's quite easy to work
// around by just capturing something. // around by just capturing something.
if (aValue.IsResolve()) { if (aValue.IsResolve()) {
InvokeCallbackMethod<SupportChaining>( InvokeCallbackMethod<SupportChaining::value>(
mResolveFunction.ptr(), &ResolveFunction::operator(), mResolveFunction.ptr(), &ResolveFunction::operator(),
MaybeMove(aValue.ResolveValue()), std::move(mCompletionPromise)); MaybeMove(aValue.ResolveValue()), std::move(mCompletionPromise));
} else { } else {
InvokeCallbackMethod<SupportChaining>( InvokeCallbackMethod<SupportChaining::value>(
mRejectFunction.ptr(), &RejectFunction::operator(), mRejectFunction.ptr(), &RejectFunction::operator(),
MaybeMove(aValue.RejectValue()), std::move(mCompletionPromise)); MaybeMove(aValue.RejectValue()), std::move(mCompletionPromise));
} }
@ -881,12 +896,15 @@ class MozPromise : public MozPromiseBase {
class ThenValue<ResolveRejectFunction> : public ThenValueBase { class ThenValue<ResolveRejectFunction> : public ThenValueBase {
friend class ThenCommand<ThenValue>; friend class ThenCommand<ThenValue>;
using R1 = RemoveSmartPointer<MethodReturnType<ResolveRejectFunction>>; using R1 = typename RemoveSmartPointer<
constexpr static bool SupportChaining = IsMozPromise<R1>; typename detail::MethodTrait<ResolveRejectFunction>::ReturnType>::Type;
using SupportChaining =
std::integral_constant<bool, IsMozPromise<R1>::value>;
// Fall back to MozPromise when promise chaining is not supported to make // Fall back to MozPromise when promise chaining is not supported to make
// code compile. // code compile.
using PromiseType = std::conditional_t<SupportChaining, R1, MozPromise>; using PromiseType =
std::conditional_t<SupportChaining::value, R1, MozPromise>;
public: public:
ThenValue(nsISerialEventTarget* aResponseTarget, ThenValue(nsISerialEventTarget* aResponseTarget,
@ -917,7 +935,7 @@ class MozPromise : public MozPromiseBase {
// classes with ::operator()), since it allows us to share code more // classes with ::operator()), since it allows us to share code more
// easily. We could fix this if need be, though it's quite easy to work // easily. We could fix this if need be, though it's quite easy to work
// around by just capturing something. // around by just capturing something.
InvokeCallbackMethod<SupportChaining>( InvokeCallbackMethod<SupportChaining::value>(
mResolveRejectFunction.ptr(), &ResolveRejectFunction::operator(), mResolveRejectFunction.ptr(), &ResolveRejectFunction::operator(),
MaybeMove(aValue), std::move(mCompletionPromise)); MaybeMove(aValue), std::move(mCompletionPromise));
@ -980,7 +998,7 @@ class MozPromise : public MozPromiseBase {
MozPromise* aReceiver) MozPromise* aReceiver)
: mCallSite(aCallSite), mThenValue(aThenValue), mReceiver(aReceiver) {} : mCallSite(aCallSite), mThenValue(aThenValue), mReceiver(aReceiver) {}
ThenCommand(ThenCommand&& aOther) noexcept = default; ThenCommand(ThenCommand&& aOther) = default;
public: public:
~ThenCommand() { ~ThenCommand() {
@ -995,7 +1013,7 @@ class MozPromise : public MozPromiseBase {
// p->Then(thread2, ...); // p->Then(thread2, ...);
operator RefPtr<PromiseType>() { operator RefPtr<PromiseType>() {
static_assert( static_assert(
ThenValueType::SupportChaining, ThenValueType::SupportChaining::value,
"The resolve/reject callback needs to return a RefPtr<MozPromise> " "The resolve/reject callback needs to return a RefPtr<MozPromise> "
"in order to do promise chaining."); "in order to do promise chaining.");
@ -1318,18 +1336,12 @@ class MozPromise<ResolveValueT, RejectValueT, IsExclusive>::Private
}; };
// A generic promise type that does the trick for simple use cases. // A generic promise type that does the trick for simple use cases.
// typedef MozPromise<bool, nsresult, /* IsExclusive = */ true> GenericPromise;
// Vaguely deprecated: prefer explicitly naming the resolve- and reject-type.
// Additionally, prefer `mozilla::Ok` as the resolve-type if the boolean's value
// is irrelevant.
using GenericPromise = MozPromise<bool, nsresult, /* IsExclusive = */ true>;
// A generic, non-exclusive promise type that does the trick for simple use // A generic, non-exclusive promise type that does the trick for simple use
// cases. // cases.
// typedef MozPromise<bool, nsresult, /* IsExclusive = */ false>
// Vaguely deprecated, as above. GenericNonExclusivePromise;
using GenericNonExclusivePromise =
MozPromise<bool, nsresult, /* IsExclusive = */ false>;
/* /*
* Class to encapsulate a promise for a particular role. Use this as the member * Class to encapsulate a promise for a particular role. Use this as the member
@ -1340,9 +1352,8 @@ class MozPromiseHolderBase {
public: public:
MozPromiseHolderBase() = default; MozPromiseHolderBase() = default;
MozPromiseHolderBase(MozPromiseHolderBase&& aOther) noexcept = default; MozPromiseHolderBase(MozPromiseHolderBase&& aOther) = default;
MozPromiseHolderBase& operator=(MozPromiseHolderBase&& aOther) noexcept = MozPromiseHolderBase& operator=(MozPromiseHolderBase&& aOther) = default;
default;
~MozPromiseHolderBase() { MOZ_ASSERT(!mPromise); } ~MozPromiseHolderBase() { MOZ_ASSERT(!mPromise); }
@ -1689,10 +1700,38 @@ class ProxyFunctionRunnable : public CancelableRunnable {
UniquePtr<FunctionStorage> mFunction; UniquePtr<FunctionStorage> mFunction;
}; };
template <typename T> // Note: The following struct and function are not for public consumption (yet?)
constexpr static bool IsRefPtrMozPromise = false; // as we would prefer all calls to pass on-the-spot lambdas (or at least moved
template <typename T, typename U, bool B> // function objects). They could be moved outside of detail if really needed.
constexpr static bool IsRefPtrMozPromise<RefPtr<MozPromise<T, U, B>>> = true;
// We prefer getting function objects by non-lvalue-ref (to avoid copying them
// and their captures). This struct is a tag that allows the use of objects
// through lvalue-refs where necessary.
struct AllowInvokeAsyncFunctionLVRef {};
// Invoke a function object (e.g., lambda or std/mozilla::function)
// asynchronously; note that the object will be copied if provided by
// lvalue-ref. Return a promise that the function should eventually resolve or
// reject.
template <typename Function>
static auto InvokeAsync(nsISerialEventTarget* aTarget, const char* aCallerName,
AllowInvokeAsyncFunctionLVRef, Function&& aFunction)
-> decltype(aFunction()) {
static_assert(
IsRefcountedSmartPointer<decltype(aFunction())>::value &&
IsMozPromise<
typename RemoveSmartPointer<decltype(aFunction())>::Type>::value,
"Function object must return RefPtr<MozPromise>");
MOZ_ASSERT(aTarget);
typedef typename RemoveSmartPointer<decltype(aFunction())>::Type PromiseType;
typedef detail::ProxyFunctionRunnable<Function, PromiseType>
ProxyRunnableType;
auto p = MakeRefPtr<typename PromiseType::Private>(aCallerName);
auto r = MakeRefPtr<ProxyRunnableType>(p, std::forward<Function>(aFunction));
aTarget->Dispatch(r.forget());
return p;
}
} // namespace detail } // namespace detail
@ -1704,18 +1743,9 @@ static auto InvokeAsync(nsISerialEventTarget* aTarget, const char* aCallerName,
static_assert(!std::is_lvalue_reference_v<Function>, static_assert(!std::is_lvalue_reference_v<Function>,
"Function object must not be passed by lvalue-ref (to avoid " "Function object must not be passed by lvalue-ref (to avoid "
"unplanned copies); Consider move()ing the object."); "unplanned copies); Consider move()ing the object.");
return detail::InvokeAsync(aTarget, aCallerName,
static_assert(detail::IsRefPtrMozPromise<decltype(aFunction())>, detail::AllowInvokeAsyncFunctionLVRef(),
"Function object must return RefPtr<MozPromise>"); std::forward<Function>(aFunction));
MOZ_ASSERT(aTarget);
typedef RemoveSmartPointer<decltype(aFunction())> PromiseType;
typedef detail::ProxyFunctionRunnable<Function, PromiseType>
ProxyRunnableType;
auto p = MakeRefPtr<typename PromiseType::Private>(aCallerName);
auto r = MakeRefPtr<ProxyRunnableType>(p, std::forward<Function>(aFunction));
aTarget->Dispatch(r.forget());
return p;
} }
# undef PROMISE_LOG # undef PROMISE_LOG

View file

@ -562,40 +562,71 @@ using RunnableFunctionImpl =
namespace detail { namespace detail {
template <typename CVRemoved>
struct IsRefcountedSmartPointerHelper : std::false_type {};
template <typename Pointee>
struct IsRefcountedSmartPointerHelper<RefPtr<Pointee>> : std::true_type {};
template <typename Pointee>
struct IsRefcountedSmartPointerHelper<nsCOMPtr<Pointee>> : std::true_type {};
} // namespace detail
template <typename T> template <typename T>
struct IsRefcountedSmartPointer
: detail::IsRefcountedSmartPointerHelper<std::remove_cv_t<T>> {};
namespace detail {
template <typename T, typename CVRemoved>
struct RemoveSmartPointerHelper { struct RemoveSmartPointerHelper {
using Type = T; typedef T Type;
}; };
template <typename T> template <typename T, typename Pointee>
struct RemoveSmartPointerHelper<RefPtr<T>> { struct RemoveSmartPointerHelper<T, RefPtr<Pointee>> {
using Type = T; typedef Pointee Type;
}; };
template <typename T> template <typename T, typename Pointee>
struct RemoveSmartPointerHelper<nsCOMPtr<T>> { struct RemoveSmartPointerHelper<T, nsCOMPtr<Pointee>> {
using Type = T; typedef Pointee Type;
};
template <typename T>
struct RemoveRawOrSmartPointerHelper {
using Type = typename RemoveSmartPointerHelper<T>::Type;
};
template <typename T>
struct RemoveRawOrSmartPointerHelper<T*> {
using Type = T;
}; };
} // namespace detail } // namespace detail
template <typename T> template <typename T>
using RemoveSmartPointer = struct RemoveSmartPointer
typename detail::RemoveSmartPointerHelper<std::remove_cv_t<T>>::Type; : detail::RemoveSmartPointerHelper<T, std::remove_cv_t<T>> {};
namespace detail {
template <typename T, typename CVRemoved>
struct RemoveRawOrSmartPointerHelper {
typedef T Type;
};
template <typename T, typename Pointee>
struct RemoveRawOrSmartPointerHelper<T, Pointee*> {
typedef Pointee Type;
};
template <typename T, typename Pointee>
struct RemoveRawOrSmartPointerHelper<T, RefPtr<Pointee>> {
typedef Pointee Type;
};
template <typename T, typename Pointee>
struct RemoveRawOrSmartPointerHelper<T, nsCOMPtr<Pointee>> {
typedef Pointee Type;
};
} // namespace detail
template <typename T> template <typename T>
using RemoveRawOrSmartPointer = struct RemoveRawOrSmartPointer
typename detail::RemoveRawOrSmartPointerHelper<std::remove_cv_t<T>>::Type; : detail::RemoveRawOrSmartPointerHelper<T, std::remove_cv_t<T>> {};
} // namespace mozilla } // namespace mozilla
@ -766,22 +797,23 @@ struct nsRunnableMethodTraits;
template <typename PtrType, class C, typename R, bool Owning, template <typename PtrType, class C, typename R, bool Owning,
mozilla::RunnableKind Kind, typename... As> mozilla::RunnableKind Kind, typename... As>
struct nsRunnableMethodTraits<PtrType, R (C::*)(As...), Owning, Kind> { struct nsRunnableMethodTraits<PtrType, R (C::*)(As...), Owning, Kind> {
using class_type = mozilla::RemoveRawOrSmartPointer<PtrType>; typedef typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type class_type;
static_assert(std::is_base_of<C, class_type>::value, static_assert(std::is_base_of<C, class_type>::value,
"Stored class must inherit from method's class"); "Stored class must inherit from method's class");
using return_type = R; typedef R return_type;
using base_type = nsRunnableMethod<C, R, Owning, Kind>; typedef nsRunnableMethod<C, R, Owning, Kind> base_type;
static const bool can_cancel = Kind == mozilla::RunnableKind::Cancelable; static const bool can_cancel = Kind == mozilla::RunnableKind::Cancelable;
}; };
template <typename PtrType, class C, typename R, bool Owning, template <typename PtrType, class C, typename R, bool Owning,
mozilla::RunnableKind Kind, typename... As> mozilla::RunnableKind Kind, typename... As>
struct nsRunnableMethodTraits<PtrType, R (C::*)(As...) const, Owning, Kind> { struct nsRunnableMethodTraits<PtrType, R (C::*)(As...) const, Owning, Kind> {
using class_type = const mozilla::RemoveRawOrSmartPointer<PtrType>; typedef const typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type
class_type;
static_assert(std::is_base_of<C, class_type>::value, static_assert(std::is_base_of<C, class_type>::value,
"Stored class must inherit from method's class"); "Stored class must inherit from method's class");
using return_type = R; typedef R return_type;
using base_type = nsRunnableMethod<C, R, Owning, Kind>; typedef nsRunnableMethod<C, R, Owning, Kind> base_type;
static const bool can_cancel = Kind == mozilla::RunnableKind::Cancelable; static const bool can_cancel = Kind == mozilla::RunnableKind::Cancelable;
}; };
@ -790,22 +822,22 @@ template <typename PtrType, class C, typename R, bool Owning,
mozilla::RunnableKind Kind, typename... As> mozilla::RunnableKind Kind, typename... As>
struct nsRunnableMethodTraits<PtrType, R (__stdcall C::*)(As...), Owning, struct nsRunnableMethodTraits<PtrType, R (__stdcall C::*)(As...), Owning,
Kind> { Kind> {
using class_type = mozilla::RemoveRawOrSmartPointer<PtrType>; typedef typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type class_type;
static_assert(std::is_base_of<C, class_type>::value, static_assert(std::is_base_of<C, class_type>::value,
"Stored class must inherit from method's class"); "Stored class must inherit from method's class");
using return_type = R; typedef R return_type;
using base_type = nsRunnableMethod<C, R, Owning, Kind>; typedef nsRunnableMethod<C, R, Owning, Kind> base_type;
static const bool can_cancel = Kind == mozilla::RunnableKind::Cancelable; static const bool can_cancel = Kind == mozilla::RunnableKind::Cancelable;
}; };
template <typename PtrType, class C, typename R, bool Owning, template <typename PtrType, class C, typename R, bool Owning,
mozilla::RunnableKind Kind> mozilla::RunnableKind Kind>
struct nsRunnableMethodTraits<PtrType, R (NS_STDCALL C::*)(), Owning, Kind> { struct nsRunnableMethodTraits<PtrType, R (NS_STDCALL C::*)(), Owning, Kind> {
using class_type = mozilla::RemoveRawOrSmartPointer<PtrType>; typedef typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type class_type;
static_assert(std::is_base_of<C, class_type>::value, static_assert(std::is_base_of<C, class_type>::value,
"Stored class must inherit from method's class"); "Stored class must inherit from method's class");
using return_type = R; typedef R return_type;
using base_type = nsRunnableMethod<C, R, Owning, Kind>; typedef nsRunnableMethod<C, R, Owning, Kind> base_type;
static const bool can_cancel = Kind == mozilla::RunnableKind::Cancelable; static const bool can_cancel = Kind == mozilla::RunnableKind::Cancelable;
}; };
@ -813,11 +845,12 @@ template <typename PtrType, class C, typename R, bool Owning,
mozilla::RunnableKind Kind, typename... As> mozilla::RunnableKind Kind, typename... As>
struct nsRunnableMethodTraits<PtrType, R (__stdcall C::*)(As...) const, Owning, struct nsRunnableMethodTraits<PtrType, R (__stdcall C::*)(As...) const, Owning,
Kind> { Kind> {
using class_type = const mozilla::RemoveRawOrSmartPointer<PtrType>; typedef const typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type
class_type;
static_assert(std::is_base_of<C, class_type>::value, static_assert(std::is_base_of<C, class_type>::value,
"Stored class must inherit from method's class"); "Stored class must inherit from method's class");
using return_type = R; typedef R return_type;
using base_type = nsRunnableMethod<C, R, Owning, Kind>; typedef nsRunnableMethod<C, R, Owning, Kind> base_type;
static const bool can_cancel = Kind == mozilla::RunnableKind::Cancelable; static const bool can_cancel = Kind == mozilla::RunnableKind::Cancelable;
}; };
@ -825,11 +858,12 @@ template <typename PtrType, class C, typename R, bool Owning,
mozilla::RunnableKind Kind> mozilla::RunnableKind Kind>
struct nsRunnableMethodTraits<PtrType, R (NS_STDCALL C::*)() const, Owning, struct nsRunnableMethodTraits<PtrType, R (NS_STDCALL C::*)() const, Owning,
Kind> { Kind> {
using class_type = const mozilla::RemoveRawOrSmartPointer<PtrType>; typedef const typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type
class_type;
static_assert(std::is_base_of<C, class_type>::value, static_assert(std::is_base_of<C, class_type>::value,
"Stored class must inherit from method's class"); "Stored class must inherit from method's class");
using return_type = R; typedef R return_type;
using base_type = nsRunnableMethod<C, R, Owning, Kind>; typedef nsRunnableMethod<C, R, Owning, Kind> base_type;
static const bool can_cancel = Kind == mozilla::RunnableKind::Cancelable; static const bool can_cancel = Kind == mozilla::RunnableKind::Cancelable;
}; };
# endif # endif
@ -846,6 +880,19 @@ struct IsParameterStorageClass : public std::false_type {};
// StoreXPassByY structs used to inform nsRunnableMethodArguments how to // StoreXPassByY structs used to inform nsRunnableMethodArguments how to
// store arguments, and how to pass them to the target method. // store arguments, and how to pass them to the target method.
template <typename T>
struct StoreCopyPassByValue {
using stored_type = std::decay_t<T>;
typedef stored_type passed_type;
stored_type m;
template <typename A>
MOZ_IMPLICIT StoreCopyPassByValue(A&& a) : m(std::forward<A>(a)) {}
passed_type PassAsParameter() { return m; }
};
template <typename S>
struct IsParameterStorageClass<StoreCopyPassByValue<S>>
: public std::true_type {};
template <typename T> template <typename T>
struct StoreCopyPassByConstLRef { struct StoreCopyPassByConstLRef {
using stored_type = std::decay_t<T>; using stored_type = std::decay_t<T>;
@ -859,6 +906,19 @@ template <typename S>
struct IsParameterStorageClass<StoreCopyPassByConstLRef<S>> struct IsParameterStorageClass<StoreCopyPassByConstLRef<S>>
: public std::true_type {}; : public std::true_type {};
template <typename T>
struct StoreCopyPassByLRef {
using stored_type = std::decay_t<T>;
typedef stored_type& passed_type;
stored_type m;
template <typename A>
MOZ_IMPLICIT StoreCopyPassByLRef(A&& a) : m(std::forward<A>(a)) {}
passed_type PassAsParameter() { return m; }
};
template <typename S>
struct IsParameterStorageClass<StoreCopyPassByLRef<S>> : public std::true_type {
};
template <typename T> template <typename T>
struct StoreCopyPassByRRef { struct StoreCopyPassByRRef {
using stored_type = std::decay_t<T>; using stored_type = std::decay_t<T>;
@ -936,6 +996,32 @@ template <typename S>
struct IsParameterStorageClass<StoreConstPtrPassByConstPtr<S>> struct IsParameterStorageClass<StoreConstPtrPassByConstPtr<S>>
: public std::true_type {}; : public std::true_type {};
template <typename T>
struct StoreCopyPassByConstPtr {
typedef T stored_type;
typedef const T* passed_type;
stored_type m;
template <typename A>
MOZ_IMPLICIT StoreCopyPassByConstPtr(A&& a) : m(std::forward<A>(a)) {}
passed_type PassAsParameter() { return &m; }
};
template <typename S>
struct IsParameterStorageClass<StoreCopyPassByConstPtr<S>>
: public std::true_type {};
template <typename T>
struct StoreCopyPassByPtr {
typedef T stored_type;
typedef T* passed_type;
stored_type m;
template <typename A>
MOZ_IMPLICIT StoreCopyPassByPtr(A&& a) : m(std::forward<A>(a)) {}
passed_type PassAsParameter() { return &m; }
};
template <typename S>
struct IsParameterStorageClass<StoreCopyPassByPtr<S>> : public std::true_type {
};
namespace detail { namespace detail {
template <typename> template <typename>
@ -949,8 +1035,69 @@ template <class>
static auto HasRefCountMethodsTest(long) -> std::false_type; static auto HasRefCountMethodsTest(long) -> std::false_type;
template <class T> template <class T>
constexpr static bool HasRefCountMethods = struct HasRefCountMethods : decltype(HasRefCountMethodsTest<T>(0)) {};
decltype(HasRefCountMethodsTest<T>(0))::value;
template <typename TWithoutPointer>
struct NonnsISupportsPointerStorageClass
: std::conditional<
std::is_const_v<TWithoutPointer>,
StoreConstPtrPassByConstPtr<std::remove_const_t<TWithoutPointer>>,
StorePtrPassByPtr<TWithoutPointer>> {
using Type = typename NonnsISupportsPointerStorageClass::conditional::type;
};
template <typename TWithoutPointer>
struct PointerStorageClass
: std::conditional<
HasRefCountMethods<TWithoutPointer>::value,
StoreRefPtrPassByPtr<TWithoutPointer>,
typename NonnsISupportsPointerStorageClass<TWithoutPointer>::Type> {
using Type = typename PointerStorageClass::conditional::type;
};
template <typename TWithoutRef>
struct LValueReferenceStorageClass
: std::conditional<
std::is_const_v<TWithoutRef>,
StoreConstRefPassByConstLRef<std::remove_const_t<TWithoutRef>>,
StoreRefPassByLRef<TWithoutRef>> {
using Type = typename LValueReferenceStorageClass::conditional::type;
};
template <typename T>
struct SmartPointerStorageClass
: std::conditional<
mozilla::IsRefcountedSmartPointer<T>::value,
StoreRefPtrPassByPtr<typename mozilla::RemoveSmartPointer<T>::Type>,
StoreCopyPassByConstLRef<T>> {
using Type = typename SmartPointerStorageClass::conditional::type;
};
template <typename T>
struct NonLValueReferenceStorageClass
: std::conditional<std::is_rvalue_reference_v<T>,
StoreCopyPassByRRef<std::remove_reference_t<T>>,
typename SmartPointerStorageClass<T>::Type> {
using Type = typename NonLValueReferenceStorageClass::conditional::type;
};
template <typename T>
struct NonPointerStorageClass
: std::conditional<std::is_lvalue_reference_v<T>,
typename LValueReferenceStorageClass<
std::remove_reference_t<T>>::Type,
typename NonLValueReferenceStorageClass<T>::Type> {
using Type = typename NonPointerStorageClass::conditional::type;
};
template <typename T>
struct NonParameterStorageClass
: std::conditional<
std::is_pointer_v<T>,
typename PointerStorageClass<std::remove_pointer_t<T>>::Type,
typename NonPointerStorageClass<T>::Type> {
using Type = typename NonParameterStorageClass::conditional::type;
};
// Choose storage&passing strategy based on preferred storage type: // Choose storage&passing strategy based on preferred storage type:
// - If IsParameterStorageClass<T>::value is true, use as-is. // - If IsParameterStorageClass<T>::value is true, use as-is.
@ -964,86 +1111,18 @@ constexpr static bool HasRefCountMethods =
// - RefPtr<T>, nsCOMPtr<T> // - RefPtr<T>, nsCOMPtr<T>
// -> StoreRefPtrPassByPtr<T> :Store RefPtr<T>, pass T* // -> StoreRefPtrPassByPtr<T> :Store RefPtr<T>, pass T*
// - Other T -> StoreCopyPassByConstLRef<T> :Store T, pass const T&. // - Other T -> StoreCopyPassByConstLRef<T> :Store T, pass const T&.
// // Other available explicit options:
// For anything less common, please use a lambda function rather than devising // - StoreCopyPassByValue<T> :Store T, pass T.
// new parameter-storage classes. (In fact, consider doing that anyway.) // - StoreCopyPassByLRef<T> :Store T, pass T& (of copy!)
// - StoreCopyPassByConstPtr<T> :Store T, pass const T*
// - StoreCopyPassByPtr<T> :Store T, pass T* (of copy!)
// Or create your own class with PassAsParameter() method, optional
// clean-up in destructor, and with associated IsParameterStorageClass<>.
template <typename T> template <typename T>
struct OtherParameterStorage; struct ParameterStorage
: std::conditional<IsParameterStorageClass<T>::value, T,
// The `IsParameterStorageClass` and `RC*` cases must be handled separately (see typename NonParameterStorageClass<T>::Type> {
// `ParameterStorageHelper`, below) until we can use C++20 concepts. using Type = typename ParameterStorage::conditional::type;
template <typename T>
struct OtherParameterStorage<const T*> {
using Type = StoreConstPtrPassByConstPtr<T>;
};
template <typename T>
struct OtherParameterStorage<T*> {
using Type = StorePtrPassByPtr<T>;
};
template <typename T>
struct OtherParameterStorage<const T&> {
using Type = StoreConstRefPassByConstLRef<T>;
};
template <typename T>
struct OtherParameterStorage<T&> {
using Type = StoreRefPassByLRef<T>;
};
template <typename T>
struct OtherParameterStorage<RefPtr<T>> {
using Type = StoreRefPtrPassByPtr<T>;
};
template <typename T>
struct OtherParameterStorage<nsCOMPtr<T>> {
using Type = StoreRefPtrPassByPtr<T>;
};
template <typename T>
struct OtherParameterStorage<T&&> {
using Type = StoreCopyPassByRRef<T>;
};
template <typename T>
struct OtherParameterStorage<const T&&> {
// This is good advice regardless of the types you're handling.
static_assert(!SFINAE1True<T>::value, "please use a lambda function");
};
// default impl.
template <typename T>
struct OtherParameterStorage {
using Type = StoreCopyPassByConstLRef<T>;
};
template <typename T, bool A = IsParameterStorageClass<T>::value,
bool B = std::is_pointer_v<T> &&
HasRefCountMethods<std::remove_pointer_t<T>>>
struct ParameterStorageHelper;
template <typename T, bool B>
struct ParameterStorageHelper<T, true, B> {
using Type = T;
};
template <typename T>
struct ParameterStorageHelper<T, false, true> {
using Type = StoreRefPtrPassByPtr<std::remove_pointer_t<T>>;
};
template <typename T>
struct ParameterStorageHelper<T, false, false> {
using Type = typename OtherParameterStorage<std::remove_cv_t<T>>::Type;
};
template <typename T>
struct ParameterStorage {
using Type = typename ParameterStorageHelper<T>::Type;
}; };
template <class T> template <class T>