diff options
Diffstat (limited to 'xpcom/threads')
-rw-r--r-- | xpcom/threads/MozPromise.h | 200 | ||||
-rw-r--r-- | xpcom/threads/Mutex.h | 4 | ||||
-rw-r--r-- | xpcom/threads/nsThreadManager.cpp | 6 | ||||
-rw-r--r-- | xpcom/threads/nsThreadUtils.h | 301 |
4 files changed, 201 insertions, 310 deletions
diff --git a/xpcom/threads/MozPromise.h b/xpcom/threads/MozPromise.h index f17e085c2f..af4ac657fd 100644 --- a/xpcom/threads/MozPromise.h +++ b/xpcom/threads/MozPromise.h @@ -82,24 +82,22 @@ struct MethodTrait : MethodTraitsHelper<std::remove_reference_t<T>> {}; } // namespace detail -template <typename MethodType> -using TakesArgument = - std::integral_constant<bool, detail::MethodTrait<MethodType>::ArgSize != 0>; +template <typename T> +using MethodReturnType = typename detail::MethodTrait<T>::ReturnType; -template <typename MethodType, typename TargetType> -using ReturnTypeIs = - std::is_convertible<typename detail::MethodTrait<MethodType>::ReturnType, - TargetType>; +template <typename MethodType> +constexpr bool TakesAnyArguments = + detail::MethodTrait<MethodType>::ArgSize != 0; template <typename ResolveValueT, typename RejectValueT, bool IsExclusive> class MozPromise; -template <typename Return> -struct IsMozPromise : std::false_type {}; +template <typename T> +constexpr bool IsMozPromise = false; template <typename ResolveValueT, typename RejectValueT, bool IsExclusive> -struct IsMozPromise<MozPromise<ResolveValueT, RejectValueT, IsExclusive>> - : std::true_type {}; +constexpr bool + IsMozPromise<MozPromise<ResolveValueT, RejectValueT, IsExclusive>> = true; /* * A promise manages an asynchronous request that may or may not be able to be @@ -176,8 +174,8 @@ class MozPromise : public MozPromiseBase { } public: - typedef ResolveValueT ResolveValueType; - typedef RejectValueT RejectValueType; + using ResolveValueType = ResolveValueT; + using RejectValueType = RejectValueT; class ResolveOrRejectValue { public: template <typename ResolveValueType_> @@ -288,12 +286,10 @@ class MozPromise : public MozPromiseBase { return p; } - typedef MozPromise<CopyableTArray<ResolveValueType>, RejectValueType, - IsExclusive> - AllPromiseType; - - typedef MozPromise<CopyableTArray<ResolveOrRejectValue>, bool, IsExclusive> - AllSettledPromiseType; + using AllPromiseType = MozPromise<CopyableTArray<ResolveValueType>, + RejectValueType, IsExclusive>; + using AllSettledPromiseType = + MozPromise<CopyableTArray<ResolveOrRejectValue>, bool, IsExclusive>; private: class AllPromiseHolder : public MozPromiseRefcountable { @@ -350,17 +346,17 @@ class MozPromise : public MozPromiseBase { // Trying to pass ResolveOrRejectValue by value fails static analysis checks, // so we need to use either a const& or an rvalue reference, depending on // whether IsExclusive is true or not. - typedef std::conditional_t<IsExclusive, ResolveOrRejectValue&&, - const ResolveOrRejectValue&> - ResolveOrRejectValueParam; + using ResolveOrRejectValueParam = + std::conditional_t<IsExclusive, ResolveOrRejectValue&&, + const ResolveOrRejectValue&>; - typedef std::conditional_t<IsExclusive, ResolveValueType&&, - const ResolveValueType&> - ResolveValueTypeParam; + using ResolveValueTypeParam = + std::conditional_t<IsExclusive, ResolveValueType&&, + const ResolveValueType&>; - typedef std::conditional_t<IsExclusive, RejectValueType&&, - const RejectValueType&> - RejectValueTypeParam; + using RejectValueTypeParam = + std::conditional_t<IsExclusive, RejectValueType&&, + const RejectValueType&>; class AllSettledPromiseHolder : public MozPromiseRefcountable { public: @@ -648,15 +644,15 @@ class MozPromise : public MozPromiseBase { * make the resolve/reject value argument "optional". */ template <typename ThisType, typename MethodType, typename ValueType> - static std::enable_if_t<TakesArgument<MethodType>::value, - typename detail::MethodTrait<MethodType>::ReturnType> + static std::enable_if_t<TakesAnyArguments<MethodType>, + MethodReturnType<MethodType>> InvokeMethod(ThisType* aThisVal, MethodType aMethod, ValueType&& aValue) { return (aThisVal->*aMethod)(std::forward<ValueType>(aValue)); } template <typename ThisType, typename MethodType, typename ValueType> - static std::enable_if_t<!TakesArgument<MethodType>::value, - typename detail::MethodTrait<MethodType>::ReturnType> + static std::enable_if_t<!TakesAnyArguments<MethodType>, + MethodReturnType<MethodType>> InvokeMethod(ThisType* aThisVal, MethodType aMethod, ValueType&& aValue) { return (aThisVal->*aMethod)(); } @@ -697,18 +693,14 @@ class MozPromise : public MozPromiseBase { : public ThenValueBase { friend class ThenCommand<ThenValue>; - using R1 = typename RemoveSmartPointer< - typename detail::MethodTrait<ResolveMethodType>::ReturnType>::Type; - using R2 = typename RemoveSmartPointer< - typename detail::MethodTrait<RejectMethodType>::ReturnType>::Type; - using SupportChaining = - std::integral_constant<bool, IsMozPromise<R1>::value && - std::is_same_v<R1, R2>>; + using R1 = RemoveSmartPointer<MethodReturnType<ResolveMethodType>>; + using R2 = RemoveSmartPointer<MethodReturnType<RejectMethodType>>; + constexpr static bool SupportChaining = + IsMozPromise<R1> && std::is_same_v<R1, R2>; // Fall back to MozPromise when promise chaining is not supported to make // code compile. - using PromiseType = - std::conditional_t<SupportChaining::value, R1, MozPromise>; + using PromiseType = std::conditional_t<SupportChaining, R1, MozPromise>; public: ThenValue(nsISerialEventTarget* aResponseTarget, ThisType* aThisVal, @@ -736,13 +728,13 @@ class MozPromise : public MozPromiseBase { void DoResolveOrRejectInternal(ResolveOrRejectValue& aValue) override { if (aValue.IsResolve()) { - InvokeCallbackMethod<SupportChaining::value>( - mThisVal.get(), mResolveMethod, MaybeMove(aValue.ResolveValue()), - std::move(mCompletionPromise)); + InvokeCallbackMethod<SupportChaining>(mThisVal.get(), mResolveMethod, + MaybeMove(aValue.ResolveValue()), + std::move(mCompletionPromise)); } else { - InvokeCallbackMethod<SupportChaining::value>( - mThisVal.get(), mRejectMethod, MaybeMove(aValue.RejectValue()), - std::move(mCompletionPromise)); + InvokeCallbackMethod<SupportChaining>(mThisVal.get(), mRejectMethod, + MaybeMove(aValue.RejectValue()), + std::move(mCompletionPromise)); } // Null out mThisVal after invoking the callback so that any references @@ -764,15 +756,12 @@ class MozPromise : public MozPromiseBase { class ThenValue<ThisType*, ResolveRejectMethodType> : public ThenValueBase { friend class ThenCommand<ThenValue>; - using R1 = typename RemoveSmartPointer<typename detail::MethodTrait< - ResolveRejectMethodType>::ReturnType>::Type; - using SupportChaining = - std::integral_constant<bool, IsMozPromise<R1>::value>; + using R1 = RemoveSmartPointer<MethodReturnType<ResolveRejectMethodType>>; + constexpr static bool SupportChaining = IsMozPromise<R1>; // Fall back to MozPromise when promise chaining is not supported to make // code compile. - using PromiseType = - std::conditional_t<SupportChaining::value, R1, MozPromise>; + using PromiseType = std::conditional_t<SupportChaining, R1, MozPromise>; public: ThenValue(nsISerialEventTarget* aResponseTarget, ThisType* aThisVal, @@ -798,7 +787,7 @@ class MozPromise : public MozPromiseBase { } void DoResolveOrRejectInternal(ResolveOrRejectValue& aValue) override { - InvokeCallbackMethod<SupportChaining::value>( + InvokeCallbackMethod<SupportChaining>( mThisVal.get(), mResolveRejectMethod, MaybeMove(aValue), std::move(mCompletionPromise)); @@ -822,18 +811,14 @@ class MozPromise : public MozPromiseBase { class ThenValue<ResolveFunction, RejectFunction> : public ThenValueBase { friend class ThenCommand<ThenValue>; - using R1 = typename RemoveSmartPointer< - typename detail::MethodTrait<ResolveFunction>::ReturnType>::Type; - using R2 = typename RemoveSmartPointer< - typename detail::MethodTrait<RejectFunction>::ReturnType>::Type; - using SupportChaining = - std::integral_constant<bool, IsMozPromise<R1>::value && - std::is_same_v<R1, R2>>; + using R1 = RemoveSmartPointer<MethodReturnType<ResolveFunction>>; + using R2 = RemoveSmartPointer<MethodReturnType<RejectFunction>>; + constexpr static bool SupportChaining = + IsMozPromise<R1> && std::is_same_v<R1, R2>; // Fall back to MozPromise when promise chaining is not supported to make // code compile. - using PromiseType = - std::conditional_t<SupportChaining::value, R1, MozPromise>; + using PromiseType = std::conditional_t<SupportChaining, R1, MozPromise>; public: ThenValue(nsISerialEventTarget* aResponseTarget, @@ -867,11 +852,11 @@ class MozPromise : public MozPromiseBase { // easily. We could fix this if need be, though it's quite easy to work // around by just capturing something. if (aValue.IsResolve()) { - InvokeCallbackMethod<SupportChaining::value>( + InvokeCallbackMethod<SupportChaining>( mResolveFunction.ptr(), &ResolveFunction::operator(), MaybeMove(aValue.ResolveValue()), std::move(mCompletionPromise)); } else { - InvokeCallbackMethod<SupportChaining::value>( + InvokeCallbackMethod<SupportChaining>( mRejectFunction.ptr(), &RejectFunction::operator(), MaybeMove(aValue.RejectValue()), std::move(mCompletionPromise)); } @@ -896,15 +881,12 @@ class MozPromise : public MozPromiseBase { class ThenValue<ResolveRejectFunction> : public ThenValueBase { friend class ThenCommand<ThenValue>; - using R1 = typename RemoveSmartPointer< - typename detail::MethodTrait<ResolveRejectFunction>::ReturnType>::Type; - using SupportChaining = - std::integral_constant<bool, IsMozPromise<R1>::value>; + using R1 = RemoveSmartPointer<MethodReturnType<ResolveRejectFunction>>; + constexpr static bool SupportChaining = IsMozPromise<R1>; // Fall back to MozPromise when promise chaining is not supported to make // code compile. - using PromiseType = - std::conditional_t<SupportChaining::value, R1, MozPromise>; + using PromiseType = std::conditional_t<SupportChaining, R1, MozPromise>; public: ThenValue(nsISerialEventTarget* aResponseTarget, @@ -935,7 +917,7 @@ class MozPromise : public MozPromiseBase { // 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 // around by just capturing something. - InvokeCallbackMethod<SupportChaining::value>( + InvokeCallbackMethod<SupportChaining>( mResolveRejectFunction.ptr(), &ResolveRejectFunction::operator(), MaybeMove(aValue), std::move(mCompletionPromise)); @@ -998,7 +980,7 @@ class MozPromise : public MozPromiseBase { MozPromise* aReceiver) : mCallSite(aCallSite), mThenValue(aThenValue), mReceiver(aReceiver) {} - ThenCommand(ThenCommand&& aOther) = default; + ThenCommand(ThenCommand&& aOther) noexcept = default; public: ~ThenCommand() { @@ -1013,7 +995,7 @@ class MozPromise : public MozPromiseBase { // p->Then(thread2, ...); operator RefPtr<PromiseType>() { static_assert( - ThenValueType::SupportChaining::value, + ThenValueType::SupportChaining, "The resolve/reject callback needs to return a RefPtr<MozPromise> " "in order to do promise chaining."); @@ -1336,12 +1318,18 @@ class MozPromise<ResolveValueT, RejectValueT, IsExclusive>::Private }; // 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 // cases. -typedef MozPromise<bool, nsresult, /* IsExclusive = */ false> - GenericNonExclusivePromise; +// +// Vaguely deprecated, as above. +using GenericNonExclusivePromise = + MozPromise<bool, nsresult, /* IsExclusive = */ false>; /* * Class to encapsulate a promise for a particular role. Use this as the member @@ -1352,8 +1340,9 @@ class MozPromiseHolderBase { public: MozPromiseHolderBase() = default; - MozPromiseHolderBase(MozPromiseHolderBase&& aOther) = default; - MozPromiseHolderBase& operator=(MozPromiseHolderBase&& aOther) = default; + MozPromiseHolderBase(MozPromiseHolderBase&& aOther) noexcept = default; + MozPromiseHolderBase& operator=(MozPromiseHolderBase&& aOther) noexcept = + default; ~MozPromiseHolderBase() { MOZ_ASSERT(!mPromise); } @@ -1511,8 +1500,8 @@ class MozPromiseRequestHolder { // will never be called. void Disconnect() { MOZ_ASSERT(Exists()); - mRequest->Disconnect(); - mRequest = nullptr; + RefPtr request = std::move(mRequest); + request->Disconnect(); } void DisconnectIfExists() { @@ -1700,30 +1689,26 @@ class ProxyFunctionRunnable : public CancelableRunnable { UniquePtr<FunctionStorage> mFunction; }; -// Note: The following struct and function are not for public consumption (yet?) -// as we would prefer all calls to pass on-the-spot lambdas (or at least moved -// function objects). They could be moved outside of detail if really needed. +template <typename T> +constexpr static bool IsRefPtrMozPromise = false; +template <typename T, typename U, bool B> +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 {}; +} // namespace detail -// 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. +// Invoke a function object (e.g., lambda) asynchronously. +// 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>"); + Function&& aFunction) -> decltype(aFunction()) { + static_assert(!std::is_lvalue_reference_v<Function>, + "Function object must not be passed by lvalue-ref (to avoid " + "unplanned copies); Consider move()ing the object."); + + static_assert(detail::IsRefPtrMozPromise<decltype(aFunction())>, + "Function object must return RefPtr<MozPromise>"); MOZ_ASSERT(aTarget); - typedef typename RemoveSmartPointer<decltype(aFunction())>::Type PromiseType; + typedef RemoveSmartPointer<decltype(aFunction())> PromiseType; typedef detail::ProxyFunctionRunnable<Function, PromiseType> ProxyRunnableType; @@ -1733,21 +1718,6 @@ static auto InvokeAsync(nsISerialEventTarget* aTarget, const char* aCallerName, return p; } -} // namespace detail - -// Invoke a function object (e.g., lambda) asynchronously. -// Return a promise that the function should eventually resolve or reject. -template <typename Function> -static auto InvokeAsync(nsISerialEventTarget* aTarget, const char* aCallerName, - Function&& aFunction) -> decltype(aFunction()) { - static_assert(!std::is_lvalue_reference_v<Function>, - "Function object must not be passed by lvalue-ref (to avoid " - "unplanned copies); Consider move()ing the object."); - return detail::InvokeAsync(aTarget, aCallerName, - detail::AllowInvokeAsyncFunctionLVRef(), - std::forward<Function>(aFunction)); -} - # undef PROMISE_LOG # undef PROMISE_ASSERT # undef PROMISE_DEBUG diff --git a/xpcom/threads/Mutex.h b/xpcom/threads/Mutex.h index 5116f1d7c3..8edb6ee773 100644 --- a/xpcom/threads/Mutex.h +++ b/xpcom/threads/Mutex.h @@ -227,7 +227,7 @@ class MOZ_RAII MOZ_SCOPED_CAPABILITY BaseAutoLock { public: /** * Constructor - * The constructor aquires the given lock. The destructor + * The constructor acquires the given lock. The destructor * releases the lock. * * @param aLock A valid mozilla::Mutex* returned by @@ -343,7 +343,7 @@ class MOZ_RAII MOZ_SCOPED_CAPABILITY ReleasableBaseAutoLock { public: /** * Constructor - * The constructor aquires the given lock. The destructor + * The constructor acquires the given lock. The destructor * releases the lock. * * @param aLock A valid mozilla::Mutex& returned by diff --git a/xpcom/threads/nsThreadManager.cpp b/xpcom/threads/nsThreadManager.cpp index 805be6ee64..3ea324a6c6 100644 --- a/xpcom/threads/nsThreadManager.cpp +++ b/xpcom/threads/nsThreadManager.cpp @@ -672,11 +672,11 @@ void AutoNestedEventLoopAnnotation::AnnotateXPCOMSpinEventLoopStack( if (aStack.Length() > 0) { nsCString prefixedStack(XRE_GetProcessTypeString()); prefixedStack += ": "_ns + aStack; - CrashReporter::AnnotateCrashReport( + CrashReporter::RecordAnnotationNSCString( CrashReporter::Annotation::XPCOMSpinEventLoopStack, prefixedStack); } else { - CrashReporter::AnnotateCrashReport( - CrashReporter::Annotation::XPCOMSpinEventLoopStack, ""_ns); + CrashReporter::UnrecordAnnotation( + CrashReporter::Annotation::XPCOMSpinEventLoopStack); } } diff --git a/xpcom/threads/nsThreadUtils.h b/xpcom/threads/nsThreadUtils.h index 72041da295..755ec21c95 100644 --- a/xpcom/threads/nsThreadUtils.h +++ b/xpcom/threads/nsThreadUtils.h @@ -562,71 +562,40 @@ using RunnableFunctionImpl = 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> -struct IsRefcountedSmartPointer - : detail::IsRefcountedSmartPointerHelper<std::remove_cv_t<T>> {}; - -namespace detail { - -template <typename T, typename CVRemoved> struct RemoveSmartPointerHelper { - typedef T Type; + using Type = T; }; -template <typename T, typename Pointee> -struct RemoveSmartPointerHelper<T, RefPtr<Pointee>> { - typedef Pointee Type; +template <typename T> +struct RemoveSmartPointerHelper<RefPtr<T>> { + using Type = T; }; -template <typename T, typename Pointee> -struct RemoveSmartPointerHelper<T, nsCOMPtr<Pointee>> { - typedef Pointee Type; +template <typename T> +struct RemoveSmartPointerHelper<nsCOMPtr<T>> { + using Type = T; }; -} // namespace detail - template <typename T> -struct RemoveSmartPointer - : 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; + using Type = typename RemoveSmartPointerHelper<T>::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; +template <typename T> +struct RemoveRawOrSmartPointerHelper<T*> { + using Type = T; }; } // namespace detail template <typename T> -struct RemoveRawOrSmartPointer - : detail::RemoveRawOrSmartPointerHelper<T, std::remove_cv_t<T>> {}; +using RemoveSmartPointer = + typename detail::RemoveSmartPointerHelper<std::remove_cv_t<T>>::Type; + +template <typename T> +using RemoveRawOrSmartPointer = + typename detail::RemoveRawOrSmartPointerHelper<std::remove_cv_t<T>>::Type; } // namespace mozilla @@ -797,23 +766,22 @@ struct nsRunnableMethodTraits; template <typename PtrType, class C, typename R, bool Owning, mozilla::RunnableKind Kind, typename... As> struct nsRunnableMethodTraits<PtrType, R (C::*)(As...), Owning, Kind> { - typedef typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type class_type; + using class_type = mozilla::RemoveRawOrSmartPointer<PtrType>; static_assert(std::is_base_of<C, class_type>::value, "Stored class must inherit from method's class"); - typedef R return_type; - typedef nsRunnableMethod<C, R, Owning, Kind> base_type; + using return_type = R; + using base_type = nsRunnableMethod<C, R, Owning, Kind>; static const bool can_cancel = Kind == mozilla::RunnableKind::Cancelable; }; template <typename PtrType, class C, typename R, bool Owning, mozilla::RunnableKind Kind, typename... As> struct nsRunnableMethodTraits<PtrType, R (C::*)(As...) const, Owning, Kind> { - typedef const typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type - class_type; + using class_type = const mozilla::RemoveRawOrSmartPointer<PtrType>; static_assert(std::is_base_of<C, class_type>::value, "Stored class must inherit from method's class"); - typedef R return_type; - typedef nsRunnableMethod<C, R, Owning, Kind> base_type; + using return_type = R; + using base_type = nsRunnableMethod<C, R, Owning, Kind>; static const bool can_cancel = Kind == mozilla::RunnableKind::Cancelable; }; @@ -822,22 +790,22 @@ template <typename PtrType, class C, typename R, bool Owning, mozilla::RunnableKind Kind, typename... As> struct nsRunnableMethodTraits<PtrType, R (__stdcall C::*)(As...), Owning, Kind> { - typedef typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type class_type; + using class_type = mozilla::RemoveRawOrSmartPointer<PtrType>; static_assert(std::is_base_of<C, class_type>::value, "Stored class must inherit from method's class"); - typedef R return_type; - typedef nsRunnableMethod<C, R, Owning, Kind> base_type; + using return_type = R; + using base_type = nsRunnableMethod<C, R, Owning, Kind>; static const bool can_cancel = Kind == mozilla::RunnableKind::Cancelable; }; template <typename PtrType, class C, typename R, bool Owning, mozilla::RunnableKind Kind> struct nsRunnableMethodTraits<PtrType, R (NS_STDCALL C::*)(), Owning, Kind> { - typedef typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type class_type; + using class_type = mozilla::RemoveRawOrSmartPointer<PtrType>; static_assert(std::is_base_of<C, class_type>::value, "Stored class must inherit from method's class"); - typedef R return_type; - typedef nsRunnableMethod<C, R, Owning, Kind> base_type; + using return_type = R; + using base_type = nsRunnableMethod<C, R, Owning, Kind>; static const bool can_cancel = Kind == mozilla::RunnableKind::Cancelable; }; @@ -845,12 +813,11 @@ template <typename PtrType, class C, typename R, bool Owning, mozilla::RunnableKind Kind, typename... As> struct nsRunnableMethodTraits<PtrType, R (__stdcall C::*)(As...) const, Owning, Kind> { - typedef const typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type - class_type; + using class_type = const mozilla::RemoveRawOrSmartPointer<PtrType>; static_assert(std::is_base_of<C, class_type>::value, "Stored class must inherit from method's class"); - typedef R return_type; - typedef nsRunnableMethod<C, R, Owning, Kind> base_type; + using return_type = R; + using base_type = nsRunnableMethod<C, R, Owning, Kind>; static const bool can_cancel = Kind == mozilla::RunnableKind::Cancelable; }; @@ -858,12 +825,11 @@ template <typename PtrType, class C, typename R, bool Owning, mozilla::RunnableKind Kind> struct nsRunnableMethodTraits<PtrType, R (NS_STDCALL C::*)() const, Owning, Kind> { - typedef const typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type - class_type; + using class_type = const mozilla::RemoveRawOrSmartPointer<PtrType>; static_assert(std::is_base_of<C, class_type>::value, "Stored class must inherit from method's class"); - typedef R return_type; - typedef nsRunnableMethod<C, R, Owning, Kind> base_type; + using return_type = R; + using base_type = nsRunnableMethod<C, R, Owning, Kind>; static const bool can_cancel = Kind == mozilla::RunnableKind::Cancelable; }; # endif @@ -881,19 +847,6 @@ struct IsParameterStorageClass : public std::false_type {}; // 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> struct StoreCopyPassByConstLRef { using stored_type = std::decay_t<T>; typedef const stored_type& passed_type; @@ -907,19 +860,6 @@ struct IsParameterStorageClass<StoreCopyPassByConstLRef<S>> : 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> struct StoreCopyPassByRRef { using stored_type = std::decay_t<T>; typedef stored_type&& passed_type; @@ -996,32 +936,6 @@ template <typename S> struct IsParameterStorageClass<StoreConstPtrPassByConstPtr<S>> : 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 { template <typename> @@ -1035,94 +949,101 @@ template <class> static auto HasRefCountMethodsTest(long) -> std::false_type; template <class T> -struct HasRefCountMethods : decltype(HasRefCountMethodsTest<T>(0)) {}; - -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; +constexpr static bool HasRefCountMethods = + decltype(HasRefCountMethodsTest<T>(0))::value; + +// Choose storage&passing strategy based on preferred storage type: +// - If IsParameterStorageClass<T>::value is true, use as-is. +// - RC* -> StoreRefPtrPassByPtr<RC> :Store RefPtr<RC>, pass RC* +// ^^ RC quacks like a ref-counted type (i.e., has AddRef and Release methods) +// - const T* -> StoreConstPtrPassByConstPtr<T> :Store const T*, pass const T* +// - T* -> StorePtrPassByPtr<T> :Store T*, pass T*. +// - const T& -> StoreConstRefPassByConstLRef<T>:Store const T&, pass const T&. +// - T& -> StoreRefPassByLRef<T> :Store T&, pass T&. +// - T&& -> StoreCopyPassByRRef<T> :Store T, pass std::move(T). +// - RefPtr<T>, nsCOMPtr<T> +// -> StoreRefPtrPassByPtr<T> :Store RefPtr<T>, pass T* +// - Other T -> StoreCopyPassByConstLRef<T> :Store T, pass const T&. +// +// For anything less common, please use a lambda function rather than devising +// new parameter-storage classes. (In fact, consider doing that anyway.) + +template <typename T> +struct OtherParameterStorage; + +// The `IsParameterStorageClass` and `RC*` cases must be handled separately (see +// `ParameterStorageHelper`, below) until we can use C++20 concepts. + +template <typename T> +struct OtherParameterStorage<const T*> { + using Type = StoreConstPtrPassByConstPtr<T>; }; -template <typename TWithoutPointer> -struct PointerStorageClass - : std::conditional< - HasRefCountMethods<TWithoutPointer>::value, - StoreRefPtrPassByPtr<TWithoutPointer>, - typename NonnsISupportsPointerStorageClass<TWithoutPointer>::Type> { - using Type = typename PointerStorageClass::conditional::type; +template <typename T> +struct OtherParameterStorage<T*> { + using Type = StorePtrPassByPtr<T>; }; -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 OtherParameterStorage<const T&> { + using Type = StoreConstRefPassByConstLRef<T>; }; 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; +struct OtherParameterStorage<T&> { + using Type = StoreRefPassByLRef<T>; }; 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; +struct OtherParameterStorage<RefPtr<T>> { + using Type = StoreRefPtrPassByPtr<T>; }; 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; +struct OtherParameterStorage<nsCOMPtr<T>> { + using Type = StoreRefPtrPassByPtr<T>; }; 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; +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; }; -// Choose storage&passing strategy based on preferred storage type: -// - If IsParameterStorageClass<T>::value is true, use as-is. -// - RC* -> StoreRefPtrPassByPtr<RC> :Store RefPtr<RC>, pass RC* -// ^^ RC quacks like a ref-counted type (i.e., has AddRef and Release methods) -// - const T* -> StoreConstPtrPassByConstPtr<T> :Store const T*, pass const T* -// - T* -> StorePtrPassByPtr<T> :Store T*, pass T*. -// - const T& -> StoreConstRefPassByConstLRef<T>:Store const T&, pass const T&. -// - T& -> StoreRefPassByLRef<T> :Store T&, pass T&. -// - T&& -> StoreCopyPassByRRef<T> :Store T, pass std::move(T). -// - RefPtr<T>, nsCOMPtr<T> -// -> StoreRefPtrPassByPtr<T> :Store RefPtr<T>, pass T* -// - Other T -> StoreCopyPassByConstLRef<T> :Store T, pass const T&. -// Other available explicit options: -// - StoreCopyPassByValue<T> :Store T, pass T. -// - 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> -struct ParameterStorage - : std::conditional<IsParameterStorageClass<T>::value, T, - typename NonParameterStorageClass<T>::Type> { - using Type = typename ParameterStorage::conditional::type; +struct ParameterStorage { + using Type = typename ParameterStorageHelper<T>::Type; }; template <class T> |