mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
Bug 1131445 - variadic NS_NewRunnableMethodWithArgs with storage&passing argument type decorators. r=waldo
--HG-- extra : rebase_source : 3c2104c19bb37624ec32a1ca4c50235e7cefd953
This commit is contained in:
parent
e984800b68
commit
4495d81efb
@ -958,6 +958,42 @@ struct RemoveExtent<T[N]>
|
||||
|
||||
/* 20.9.7.5 Pointer modifications [meta.trans.ptr] */
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename T, typename CVRemoved>
|
||||
struct RemovePointerHelper
|
||||
{
|
||||
typedef T Type;
|
||||
};
|
||||
|
||||
template<typename T, typename Pointee>
|
||||
struct RemovePointerHelper<T, Pointee*>
|
||||
{
|
||||
typedef Pointee Type;
|
||||
};
|
||||
|
||||
} // namespac detail
|
||||
|
||||
/**
|
||||
* Produces the pointed-to type if a pointer is provided, else returns the input
|
||||
* type. Note that this does not dereference pointer-to-member pointers.
|
||||
*
|
||||
* struct S { bool m; void f(); };
|
||||
* mozilla::RemovePointer<int>::Type is int;
|
||||
* mozilla::RemovePointer<int*>::Type is int;
|
||||
* mozilla::RemovePointer<int* const>::Type is int;
|
||||
* mozilla::RemovePointer<int* volatile>::Type is int;
|
||||
* mozilla::RemovePointer<const long*>::Type is const long;
|
||||
* mozilla::RemovePointer<void* const>::Type is void;
|
||||
* mozilla::RemovePointer<void (S::*)()>::Type is void (S::*)();
|
||||
* mozilla::RemovePointer<void (*)()>::Type is void();
|
||||
* mozilla::RemovePointer<bool S::*>::Type is bool S::*.
|
||||
*/
|
||||
template<typename T>
|
||||
struct RemovePointer
|
||||
: detail::RemovePointerHelper<T, typename RemoveCV<T>::Type>
|
||||
{};
|
||||
|
||||
/* 20.9.7.6 Other transformations [meta.trans.other] */
|
||||
|
||||
/**
|
||||
|
@ -23,6 +23,7 @@ using mozilla::IsUnsigned;
|
||||
using mozilla::MakeSigned;
|
||||
using mozilla::MakeUnsigned;
|
||||
using mozilla::RemoveExtent;
|
||||
using mozilla::RemovePointer;
|
||||
|
||||
static_assert(!IsArray<bool>::value,
|
||||
"bool not an array");
|
||||
@ -430,6 +431,28 @@ static_assert(IsSame<RemoveExtent<volatile int[5]>::Type, volatile int>::value,
|
||||
static_assert(IsSame<RemoveExtent<long[][17]>::Type, long[17]>::value,
|
||||
"removing extent from multidimensional array must return element type");
|
||||
|
||||
struct TestRemovePointer { bool m; void f(); };
|
||||
static_assert(IsSame<RemovePointer<int>::Type, int>::value,
|
||||
"removing pointer from int must return int");
|
||||
static_assert(IsSame<RemovePointer<int*>::Type, int>::value,
|
||||
"removing pointer from int* must return int");
|
||||
static_assert(IsSame<RemovePointer<int* const>::Type, int>::value,
|
||||
"removing pointer from int* const must return int");
|
||||
static_assert(IsSame<RemovePointer<int* volatile>::Type, int>::value,
|
||||
"removing pointer from int* volatile must return int");
|
||||
static_assert(IsSame<RemovePointer<const long*>::Type, const long>::value,
|
||||
"removing pointer from const long* must return const long");
|
||||
static_assert(IsSame<RemovePointer<void* const>::Type, void>::value,
|
||||
"removing pointer from void* const must return void");
|
||||
static_assert(IsSame<RemovePointer<void (TestRemovePointer::*)()>::Type,
|
||||
void (TestRemovePointer::*)()>::value,
|
||||
"removing pointer from void (S::*)() must return void (S::*)()");
|
||||
static_assert(IsSame<RemovePointer<void (*)()>::Type, void()>::value,
|
||||
"removing pointer from void (*)() must return void()");
|
||||
static_assert(IsSame<RemovePointer<bool TestRemovePointer::*>::Type,
|
||||
bool TestRemovePointer::*>::value,
|
||||
"removing pointer from bool S::* must return bool S::*");
|
||||
|
||||
/*
|
||||
* Android's broken [u]intptr_t inttype macros are broken because its PRI*PTR
|
||||
* macros are defined as "ld", but sizeof(long) is 8 and sizeof(intptr_t)
|
||||
|
@ -268,67 +268,41 @@ public:
|
||||
typedef typename ReturnTypeEnforcer<ReturnType>::ReturnTypeIsSafe check;
|
||||
};
|
||||
|
||||
template<class ClassType, typename Arg, bool Owning>
|
||||
template<class ClassType, bool Owning>
|
||||
struct nsRunnableMethodReceiver
|
||||
{
|
||||
nsRefPtr<ClassType> mObj;
|
||||
Arg mArg;
|
||||
nsRunnableMethodReceiver(ClassType* aObj, Arg aArg)
|
||||
: mObj(aObj)
|
||||
, mArg(aArg)
|
||||
{
|
||||
}
|
||||
~nsRunnableMethodReceiver() { Revoke(); }
|
||||
void Revoke() { mObj = nullptr; }
|
||||
};
|
||||
|
||||
template<class ClassType, bool Owning>
|
||||
struct nsRunnableMethodReceiver<ClassType, void, Owning>
|
||||
{
|
||||
nsRefPtr<ClassType> mObj;
|
||||
explicit nsRunnableMethodReceiver(ClassType* aObj)
|
||||
: mObj(aObj)
|
||||
{
|
||||
}
|
||||
explicit nsRunnableMethodReceiver(ClassType* aObj) : mObj(aObj) {}
|
||||
~nsRunnableMethodReceiver() { Revoke(); }
|
||||
ClassType* Get() const { return mObj.get(); }
|
||||
void Revoke() { mObj = nullptr; }
|
||||
};
|
||||
|
||||
template<class ClassType>
|
||||
struct nsRunnableMethodReceiver<ClassType, void, false>
|
||||
struct nsRunnableMethodReceiver<ClassType, false>
|
||||
{
|
||||
ClassType* MOZ_NON_OWNING_REF mObj;
|
||||
explicit nsRunnableMethodReceiver(ClassType* aObj) : mObj(aObj) {}
|
||||
ClassType* Get() const { return mObj; }
|
||||
void Revoke() { mObj = nullptr; }
|
||||
};
|
||||
|
||||
template<typename Method, bool Owning> struct nsRunnableMethodTraits;
|
||||
|
||||
template<class C, typename R, typename A, bool Owning>
|
||||
struct nsRunnableMethodTraits<R(C::*)(A), Owning>
|
||||
template<class C, typename R, bool Owning, typename... As>
|
||||
struct nsRunnableMethodTraits<R(C::*)(As...), Owning>
|
||||
{
|
||||
typedef C class_type;
|
||||
typedef R return_type;
|
||||
typedef A arg_type;
|
||||
typedef nsRunnableMethod<C, R, Owning> base_type;
|
||||
};
|
||||
|
||||
template<class C, typename R, bool Owning>
|
||||
struct nsRunnableMethodTraits<R(C::*)(), Owning>
|
||||
{
|
||||
typedef C class_type;
|
||||
typedef R return_type;
|
||||
typedef void arg_type;
|
||||
typedef nsRunnableMethod<C, R, Owning> base_type;
|
||||
};
|
||||
|
||||
#ifdef NS_HAVE_STDCALL
|
||||
template<class C, typename R, typename A, bool Owning>
|
||||
struct nsRunnableMethodTraits<R(__stdcall C::*)(A), Owning>
|
||||
template<class C, typename R, bool Owning, typename... As>
|
||||
struct nsRunnableMethodTraits<R(__stdcall C::*)(As...), Owning>
|
||||
{
|
||||
typedef C class_type;
|
||||
typedef R return_type;
|
||||
typedef A arg_type;
|
||||
typedef nsRunnableMethod<C, R, Owning> base_type;
|
||||
};
|
||||
|
||||
@ -337,57 +311,361 @@ struct nsRunnableMethodTraits<R(NS_STDCALL C::*)(), Owning>
|
||||
{
|
||||
typedef C class_type;
|
||||
typedef R return_type;
|
||||
typedef void arg_type;
|
||||
typedef nsRunnableMethod<C, R, Owning> base_type;
|
||||
};
|
||||
#endif
|
||||
|
||||
template<typename Method, typename Arg, bool Owning>
|
||||
|
||||
// IsParameterStorageClass<T>::value is true if T is a parameter-storage class
|
||||
// that will be recognized by NS_New[NonOwning]RunnableMethodWithArg[s] to
|
||||
// force a specific storage&passing strategy (instead of inferring one,
|
||||
// see ParameterStorage).
|
||||
// When creating a new storage class, add a specialization for it to be
|
||||
// recognized.
|
||||
template<typename T>
|
||||
struct IsParameterStorageClass : public mozilla::FalseType {};
|
||||
|
||||
// StoreXPassByY structs used to inform nsRunnableMethodArguments how to
|
||||
// store arguments, and how to pass them to the target method.
|
||||
|
||||
template<typename T>
|
||||
struct StoreCopyPassByValue
|
||||
{
|
||||
typedef T stored_type;
|
||||
typedef T passed_type;
|
||||
stored_type m;
|
||||
template <typename A>
|
||||
StoreCopyPassByValue(A&& a) : m(mozilla::Forward<A>(a)) {}
|
||||
passed_type PassAsParameter() { return m; }
|
||||
};
|
||||
template<typename S>
|
||||
struct IsParameterStorageClass<StoreCopyPassByValue<S>>
|
||||
: public mozilla::TrueType {};
|
||||
|
||||
template<typename T>
|
||||
struct StoreCopyPassByConstLRef
|
||||
{
|
||||
typedef T stored_type;
|
||||
typedef const T& passed_type;
|
||||
stored_type m;
|
||||
template <typename A>
|
||||
StoreCopyPassByConstLRef(A&& a) : m(mozilla::Forward<A>(a)) {}
|
||||
passed_type PassAsParameter() { return m; }
|
||||
};
|
||||
template<typename S>
|
||||
struct IsParameterStorageClass<StoreCopyPassByConstLRef<S>>
|
||||
: public mozilla::TrueType {};
|
||||
|
||||
template<typename T>
|
||||
struct StoreCopyPassByLRef
|
||||
{
|
||||
typedef T stored_type;
|
||||
typedef T& passed_type;
|
||||
stored_type m;
|
||||
template <typename A>
|
||||
StoreCopyPassByLRef(A&& a) : m(mozilla::Forward<A>(a)) {}
|
||||
passed_type PassAsParameter() { return m; }
|
||||
};
|
||||
template<typename S>
|
||||
struct IsParameterStorageClass<StoreCopyPassByLRef<S>>
|
||||
: public mozilla::TrueType {};
|
||||
|
||||
template<typename T>
|
||||
struct StoreCopyPassByRRef
|
||||
{
|
||||
typedef T stored_type;
|
||||
typedef T&& passed_type;
|
||||
stored_type m;
|
||||
template <typename A>
|
||||
StoreCopyPassByRRef(A&& a) : m(mozilla::Forward<A>(a)) {}
|
||||
passed_type PassAsParameter() { return mozilla::Move(m); }
|
||||
};
|
||||
template<typename S>
|
||||
struct IsParameterStorageClass<StoreCopyPassByRRef<S>>
|
||||
: public mozilla::TrueType {};
|
||||
|
||||
template<typename T>
|
||||
struct StoreRefPassByLRef
|
||||
{
|
||||
typedef T& stored_type;
|
||||
typedef T& passed_type;
|
||||
stored_type m;
|
||||
template <typename A>
|
||||
StoreRefPassByLRef(A& a) : m(a) {}
|
||||
passed_type PassAsParameter() { return m; }
|
||||
};
|
||||
template<typename S>
|
||||
struct IsParameterStorageClass<StoreRefPassByLRef<S>>
|
||||
: public mozilla::TrueType {};
|
||||
|
||||
template<typename T>
|
||||
struct StoreConstRefPassByConstLRef
|
||||
{
|
||||
typedef const T& stored_type;
|
||||
typedef const T& passed_type;
|
||||
stored_type m;
|
||||
template <typename A>
|
||||
StoreConstRefPassByConstLRef(const A& a) : m(a) {}
|
||||
passed_type PassAsParameter() { return m; }
|
||||
};
|
||||
template<typename S>
|
||||
struct IsParameterStorageClass<StoreConstRefPassByConstLRef<S>>
|
||||
: public mozilla::TrueType {};
|
||||
|
||||
template<typename T>
|
||||
struct StorensRefPtrPassByPtr
|
||||
{
|
||||
typedef nsRefPtr<T> stored_type;
|
||||
typedef T* passed_type;
|
||||
stored_type m;
|
||||
template <typename A>
|
||||
StorensRefPtrPassByPtr(A a) : m(a) {}
|
||||
passed_type PassAsParameter() { return m.get(); }
|
||||
};
|
||||
template<typename S>
|
||||
struct IsParameterStorageClass<StorensRefPtrPassByPtr<S>>
|
||||
: public mozilla::TrueType {};
|
||||
|
||||
template<typename T>
|
||||
struct StorePtrPassByPtr
|
||||
{
|
||||
typedef T* stored_type;
|
||||
typedef T* passed_type;
|
||||
stored_type m;
|
||||
template <typename A>
|
||||
StorePtrPassByPtr(A a) : m(a) {}
|
||||
passed_type PassAsParameter() { return m; }
|
||||
};
|
||||
template<typename S>
|
||||
struct IsParameterStorageClass<StorePtrPassByPtr<S>>
|
||||
: public mozilla::TrueType {};
|
||||
|
||||
template<typename T>
|
||||
struct StoreConstPtrPassByConstPtr
|
||||
{
|
||||
typedef const T* stored_type;
|
||||
typedef const T* passed_type;
|
||||
stored_type m;
|
||||
template <typename A>
|
||||
StoreConstPtrPassByConstPtr(A a) : m(a) {}
|
||||
passed_type PassAsParameter() { return m; }
|
||||
};
|
||||
template<typename S>
|
||||
struct IsParameterStorageClass<StoreConstPtrPassByConstPtr<S>>
|
||||
: public mozilla::TrueType {};
|
||||
|
||||
template<typename T>
|
||||
struct StoreCopyPassByConstPtr
|
||||
{
|
||||
typedef T stored_type;
|
||||
typedef const T* passed_type;
|
||||
stored_type m;
|
||||
template <typename A>
|
||||
StoreCopyPassByConstPtr(A&& a) : m(mozilla::Forward<A>(a)) {}
|
||||
passed_type PassAsParameter() { return &m; }
|
||||
};
|
||||
template<typename S>
|
||||
struct IsParameterStorageClass<StoreCopyPassByConstPtr<S>>
|
||||
: public mozilla::TrueType {};
|
||||
|
||||
template<typename T>
|
||||
struct StoreCopyPassByPtr
|
||||
{
|
||||
typedef T stored_type;
|
||||
typedef T* passed_type;
|
||||
stored_type m;
|
||||
template <typename A>
|
||||
StoreCopyPassByPtr(A&& a) : m(mozilla::Forward<A>(a)) {}
|
||||
passed_type PassAsParameter() { return &m; }
|
||||
};
|
||||
template<typename S>
|
||||
struct IsParameterStorageClass<StoreCopyPassByPtr<S>>
|
||||
: public mozilla::TrueType {};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename TWithoutPointer>
|
||||
struct NonnsISupportsPointerStorageClass
|
||||
: mozilla::Conditional<mozilla::IsConst<TWithoutPointer>::value,
|
||||
StoreConstPtrPassByConstPtr<
|
||||
typename mozilla::RemoveConst<TWithoutPointer>::Type>,
|
||||
StorePtrPassByPtr<TWithoutPointer>>
|
||||
{};
|
||||
|
||||
template<typename TWithoutPointer>
|
||||
struct PointerStorageClass
|
||||
: mozilla::Conditional<mozilla::IsBaseOf<nsISupports, TWithoutPointer>::value,
|
||||
StorensRefPtrPassByPtr<TWithoutPointer>,
|
||||
typename NonnsISupportsPointerStorageClass<
|
||||
TWithoutPointer
|
||||
>::Type>
|
||||
{};
|
||||
|
||||
template<typename TWithoutRef>
|
||||
struct LValueReferenceStorageClass
|
||||
: mozilla::Conditional<mozilla::IsConst<TWithoutRef>::value,
|
||||
StoreConstRefPassByConstLRef<
|
||||
typename mozilla::RemoveConst<TWithoutRef>::Type>,
|
||||
StoreRefPassByLRef<TWithoutRef>>
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
struct NonLValueReferenceStorageClass
|
||||
: mozilla::Conditional<mozilla::IsRvalueReference<T>::value,
|
||||
StoreCopyPassByRRef<
|
||||
typename mozilla::RemoveReference<T>::Type>,
|
||||
StoreCopyPassByValue<T>>
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
struct NonPointerStorageClass
|
||||
: mozilla::Conditional<mozilla::IsLvalueReference<T>::value,
|
||||
typename LValueReferenceStorageClass<
|
||||
typename mozilla::RemoveReference<T>::Type
|
||||
>::Type,
|
||||
typename NonLValueReferenceStorageClass<T>::Type>
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
struct NonParameterStorageClass
|
||||
: mozilla::Conditional<mozilla::IsPointer<T>::value,
|
||||
typename PointerStorageClass<
|
||||
typename mozilla::RemovePointer<T>::Type
|
||||
>::Type,
|
||||
typename NonPointerStorageClass<T>::Type>
|
||||
{};
|
||||
|
||||
// Choose storage&passing strategy based on preferred storage type:
|
||||
// - If IsParameterStorageClass<T>::value is true, use as-is.
|
||||
// - nsISupports* -> StorensRefPtrPassByPtr<T> : Store nsRefPtr<T>, pass T*
|
||||
// - 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 Move(T).
|
||||
// - Other T -> StoreCopyPassByValue<T> : Store T, pass T.
|
||||
// Other available explicit options:
|
||||
// - StoreCopyPassByConstLRef<T> : Store T, pass const 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
|
||||
: mozilla::Conditional<IsParameterStorageClass<T>::value,
|
||||
T,
|
||||
typename NonParameterStorageClass<T>::Type>
|
||||
{};
|
||||
|
||||
} /* namespace detail */
|
||||
|
||||
// struct used to store arguments and later apply them to a method.
|
||||
template <typename... Ts> struct nsRunnableMethodArguments;
|
||||
|
||||
// Specializations for 0-4 arguments, add more as required.
|
||||
// TODO Use tuple instead; And/or use lambdas.
|
||||
template <>
|
||||
struct nsRunnableMethodArguments<>
|
||||
{
|
||||
template<class C, typename M> void apply(C* o, M m)
|
||||
{
|
||||
((*o).*m)();
|
||||
}
|
||||
};
|
||||
template <typename T0>
|
||||
struct nsRunnableMethodArguments<T0>
|
||||
{
|
||||
typename ::detail::ParameterStorage<T0>::Type m0;
|
||||
template<typename A0>
|
||||
nsRunnableMethodArguments(A0&& a0)
|
||||
: m0(mozilla::Forward<A0>(a0))
|
||||
{}
|
||||
template<class C, typename M> void apply(C* o, M m)
|
||||
{
|
||||
((*o).*m)(m0.PassAsParameter());
|
||||
}
|
||||
};
|
||||
template <typename T0, typename T1>
|
||||
struct nsRunnableMethodArguments<T0, T1>
|
||||
{
|
||||
typename ::detail::ParameterStorage<T0>::Type m0;
|
||||
typename ::detail::ParameterStorage<T1>::Type m1;
|
||||
template<typename A0, typename A1>
|
||||
nsRunnableMethodArguments(A0&& a0, A1&& a1)
|
||||
: m0(mozilla::Forward<A0>(a0))
|
||||
, m1(mozilla::Forward<A1>(a1))
|
||||
{}
|
||||
template<class C, typename M> void apply(C* o, M m)
|
||||
{
|
||||
((*o).*m)(m0.PassAsParameter(), m1.PassAsParameter());
|
||||
}
|
||||
};
|
||||
template <typename T0, typename T1, typename T2>
|
||||
struct nsRunnableMethodArguments<T0, T1, T2>
|
||||
{
|
||||
typename ::detail::ParameterStorage<T0>::Type m0;
|
||||
typename ::detail::ParameterStorage<T1>::Type m1;
|
||||
typename ::detail::ParameterStorage<T2>::Type m2;
|
||||
template<typename A0, typename A1, typename A2>
|
||||
nsRunnableMethodArguments(A0&& a0, A1&& a1, A2&& a2)
|
||||
: m0(mozilla::Forward<A0>(a0))
|
||||
, m1(mozilla::Forward<A1>(a1))
|
||||
, m2(mozilla::Forward<A2>(a2))
|
||||
{}
|
||||
template<class C, typename M> void apply(C* o, M m)
|
||||
{
|
||||
((*o).*m)(m0.PassAsParameter(), m1.PassAsParameter(), m2.PassAsParameter());
|
||||
}
|
||||
};
|
||||
template <typename T0, typename T1, typename T2, typename T3>
|
||||
struct nsRunnableMethodArguments<T0, T1, T2, T3>
|
||||
{
|
||||
typename ::detail::ParameterStorage<T0>::Type m0;
|
||||
typename ::detail::ParameterStorage<T1>::Type m1;
|
||||
typename ::detail::ParameterStorage<T2>::Type m2;
|
||||
typename ::detail::ParameterStorage<T3>::Type m3;
|
||||
template<typename A0, typename A1, typename A2, typename A3>
|
||||
nsRunnableMethodArguments(A0&& a0, A1&& a1, A2&& a2, A3&& a3)
|
||||
: m0(mozilla::Forward<A0>(a0))
|
||||
, m1(mozilla::Forward<A1>(a1))
|
||||
, m2(mozilla::Forward<A2>(a2))
|
||||
, m3(mozilla::Forward<A3>(a3))
|
||||
{}
|
||||
template<class C, typename M> void apply(C* o, M m)
|
||||
{
|
||||
((*o).*m)(m0.PassAsParameter(), m1.PassAsParameter(),
|
||||
m2.PassAsParameter(), m3.PassAsParameter());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Method, bool Owning, typename... Storages>
|
||||
class nsRunnableMethodImpl
|
||||
: public nsRunnableMethodTraits<Method, Owning>::base_type
|
||||
{
|
||||
typedef typename nsRunnableMethodTraits<Method, Owning>::class_type ClassType;
|
||||
nsRunnableMethodReceiver<ClassType, Arg, Owning> mReceiver;
|
||||
typedef typename nsRunnableMethodTraits<Method, Owning>::class_type
|
||||
ClassType;
|
||||
nsRunnableMethodReceiver<ClassType, Owning> mReceiver;
|
||||
Method mMethod;
|
||||
nsRunnableMethodArguments<Storages...> mArgs;
|
||||
public:
|
||||
nsRunnableMethodImpl(ClassType* aObj, Method aMethod, Arg aArg)
|
||||
: mReceiver(aObj, aArg)
|
||||
, mMethod(aMethod)
|
||||
{
|
||||
}
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
if (MOZ_LIKELY(mReceiver.mObj)) {
|
||||
((*mReceiver.mObj).*mMethod)(mReceiver.mArg);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
void Revoke() { mReceiver.Revoke(); }
|
||||
};
|
||||
|
||||
template<typename Method, bool Owning>
|
||||
class nsRunnableMethodImpl<Method, void, Owning>
|
||||
: public nsRunnableMethodTraits<Method, Owning>::base_type
|
||||
{
|
||||
typedef typename nsRunnableMethodTraits<Method, Owning>::class_type ClassType;
|
||||
nsRunnableMethodReceiver<ClassType, void, Owning> mReceiver;
|
||||
Method mMethod;
|
||||
|
||||
public:
|
||||
nsRunnableMethodImpl(ClassType* aObj, Method aMethod)
|
||||
virtual ~nsRunnableMethodImpl() { Revoke(); };
|
||||
template<typename... Args>
|
||||
explicit nsRunnableMethodImpl(ClassType* aObj, Method aMethod,
|
||||
Args&&... aArgs)
|
||||
: mReceiver(aObj)
|
||||
, mMethod(aMethod)
|
||||
, mArgs(mozilla::Forward<Args>(aArgs)...)
|
||||
{
|
||||
static_assert(sizeof...(Storages) == sizeof...(Args), "Storages and Args should have equal sizes");
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
if (MOZ_LIKELY(mReceiver.mObj)) {
|
||||
((*mReceiver.mObj).*mMethod)();
|
||||
if (MOZ_LIKELY(mReceiver.Get())) {
|
||||
mArgs.apply(mReceiver.Get(), mMethod);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void Revoke() { mReceiver.Revoke(); }
|
||||
};
|
||||
|
||||
@ -405,33 +683,51 @@ template<typename PtrType, typename Method>
|
||||
typename nsRunnableMethodTraits<Method, true>::base_type*
|
||||
NS_NewRunnableMethod(PtrType aPtr, Method aMethod)
|
||||
{
|
||||
return new nsRunnableMethodImpl<Method, void, true>(aPtr, aMethod);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct dependent_type
|
||||
{
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
|
||||
// Similar to NS_NewRunnableMethod. Call like so:
|
||||
// Type myArg;
|
||||
// nsCOMPtr<nsIRunnable> event =
|
||||
// NS_NewRunnableMethodWithArg<Type>(myObject, &MyClass::HandleEvent, myArg);
|
||||
template<typename Arg, typename Method, typename PtrType>
|
||||
typename nsRunnableMethodTraits<Method, true>::base_type*
|
||||
NS_NewRunnableMethodWithArg(PtrType&& aPtr, Method aMethod,
|
||||
typename dependent_type<Arg>::type aArg)
|
||||
{
|
||||
return new nsRunnableMethodImpl<Method, Arg, true>(aPtr, aMethod, aArg);
|
||||
return new nsRunnableMethodImpl<Method, true>(aPtr, aMethod);
|
||||
}
|
||||
|
||||
template<typename PtrType, typename Method>
|
||||
typename nsRunnableMethodTraits<Method, false>::base_type*
|
||||
NS_NewNonOwningRunnableMethod(PtrType&& aPtr, Method aMethod)
|
||||
{
|
||||
return new nsRunnableMethodImpl<Method, void, false>(aPtr, aMethod);
|
||||
return new nsRunnableMethodImpl<Method, false>(aPtr, aMethod);
|
||||
}
|
||||
|
||||
// Similar to NS_NewRunnableMethod. Call like so:
|
||||
// nsCOMPtr<nsIRunnable> event =
|
||||
// NS_NewRunnableMethodWithArg<Type>(myObject, &MyClass::HandleEvent, myArg);
|
||||
// 'Type' is the stored type for the argument, see ParameterStorage for details.
|
||||
template<typename Storage, typename Method, typename PtrType, typename Arg>
|
||||
typename nsRunnableMethodTraits<Method, true>::base_type*
|
||||
NS_NewRunnableMethodWithArg(PtrType&& aPtr, Method aMethod, Arg&& aArg)
|
||||
{
|
||||
return new nsRunnableMethodImpl<Method, true, Storage>(
|
||||
aPtr, aMethod, mozilla::Forward<Arg>(aArg));
|
||||
}
|
||||
|
||||
// Similar to NS_NewRunnableMethod. Call like so:
|
||||
// nsCOMPtr<nsIRunnable> event =
|
||||
// NS_NewRunnableMethodWithArg<Types,...>(myObject, &MyClass::HandleEvent, myArg1,...);
|
||||
// 'Types' are the stored type for each argument, see ParameterStorage for details.
|
||||
template<typename... Storages, typename Method, typename PtrType, typename... Args>
|
||||
typename nsRunnableMethodTraits<Method, true>::base_type*
|
||||
NS_NewRunnableMethodWithArgs(PtrType&& aPtr, Method aMethod, Args&&... aArgs)
|
||||
{
|
||||
static_assert(sizeof...(Storages) == sizeof...(Args),
|
||||
"<Storages...> size should be equal to number of arguments");
|
||||
return new nsRunnableMethodImpl<Method, true, Storages...>(
|
||||
aPtr, aMethod, mozilla::Forward<Args>(aArgs)...);
|
||||
}
|
||||
|
||||
template<typename... Storages, typename Method, typename PtrType, typename... Args>
|
||||
typename nsRunnableMethodTraits<Method, true>::base_type*
|
||||
NS_NewNonOwningRunnableMethodWithArgs(PtrType&& aPtr, Method aMethod,
|
||||
Args&&... aArgs)
|
||||
{
|
||||
static_assert(sizeof...(Storages) == sizeof...(Args),
|
||||
"<Storages...> size should be equal to number of arguments");
|
||||
return new nsRunnableMethodImpl<Method, false, Storages...>(
|
||||
aPtr, aMethod, mozilla::Forward<Args>(aArgs)...);
|
||||
}
|
||||
|
||||
#endif // XPCOM_GLUE_AVOID_NSPR
|
||||
|
880
xpcom/glue/tests/gtest/TestThreadUtils.cpp
Normal file
880
xpcom/glue/tests/gtest/TestThreadUtils.cpp
Normal file
@ -0,0 +1,880 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "nsThreadUtils.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
// {9e70a320-be02-11d1-8031-006008159b5a}
|
||||
#define NS_IFOO_IID \
|
||||
{0x9e70a320, 0xbe02, 0x11d1, \
|
||||
{0x80, 0x31, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x5a}}
|
||||
|
||||
namespace TestThreadUtils {
|
||||
|
||||
static bool gDebug = false;
|
||||
static int gAlive, gZombies;
|
||||
static int gAllConstructions, gConstructions, gCopyConstructions,
|
||||
gMoveConstructions, gDestructions, gAssignments, gMoves;
|
||||
struct Spy
|
||||
{
|
||||
static void ClearActions()
|
||||
{
|
||||
gAllConstructions = gConstructions = gCopyConstructions
|
||||
= gMoveConstructions = gDestructions = gAssignments = gMoves = 0;
|
||||
}
|
||||
static void ClearAll()
|
||||
{
|
||||
ClearActions();
|
||||
gAlive = 0;
|
||||
}
|
||||
|
||||
explicit Spy(int aID) : mID(aID)
|
||||
{
|
||||
++gAlive; ++gAllConstructions; ++gConstructions;
|
||||
if (gDebug) { printf("Spy[%d@%p]()\n", mID, this); }
|
||||
}
|
||||
Spy(const Spy& o) : mID(o.mID)
|
||||
{
|
||||
++gAlive; ++gAllConstructions; ++gCopyConstructions;
|
||||
if (gDebug) { printf("Spy[%d@%p](&[%d@%p])\n", mID, this, o.mID, &o); }
|
||||
}
|
||||
Spy(Spy&& o) : mID(o.mID)
|
||||
{
|
||||
o.mID = -o.mID;
|
||||
++gZombies; ++gAllConstructions; ++gMoveConstructions;
|
||||
if (gDebug) { printf("Spy[%d@%p](&&[%d->%d@%p])\n", mID, this, -o.mID, o.mID, &o); }
|
||||
}
|
||||
~Spy()
|
||||
{
|
||||
if (mID >= 0) { --gAlive; } else { --gZombies; } ++gDestructions;
|
||||
if (gDebug) { printf("~Spy[%d@%p]()\n", mID, this); }
|
||||
mID = 0;
|
||||
}
|
||||
Spy& operator=(const Spy& o)
|
||||
{
|
||||
++gAssignments;
|
||||
if (gDebug) { printf("Spy[%d->%d@%p] = &[%d@%p]\n", mID, o.mID, this, o.mID, &o); }
|
||||
mID = o.mID;
|
||||
return *this;
|
||||
};
|
||||
Spy& operator=(Spy&& o)
|
||||
{
|
||||
--gAlive; ++gZombies;
|
||||
++gMoves;
|
||||
if (gDebug) { printf("Spy[%d->%d@%p] = &&[%d->%d@%p]\n", mID, o.mID, this, o.mID, -o.mID, &o); }
|
||||
mID = o.mID; o.mID = -o.mID;
|
||||
return *this;
|
||||
};
|
||||
|
||||
int mID; // ID given at construction, or negation if was moved from; 0 when destroyed.
|
||||
};
|
||||
|
||||
struct ISpyWithISupports : public nsISupports
|
||||
{
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IFOO_IID)
|
||||
NS_IMETHOD_(nsrefcnt) RefCnt() = 0;
|
||||
NS_IMETHOD_(int32_t) ID() = 0;
|
||||
};
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(ISpyWithISupports, NS_IFOO_IID)
|
||||
struct SpyWithISupports : public ISpyWithISupports, public Spy
|
||||
{
|
||||
private:
|
||||
virtual ~SpyWithISupports() = default;
|
||||
public:
|
||||
explicit SpyWithISupports(int aID) : Spy(aID) {};
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_IMETHOD_(nsrefcnt) RefCnt() MOZ_OVERRIDE { return mRefCnt; }
|
||||
NS_IMETHOD_(int32_t) ID() MOZ_OVERRIDE { return mID; }
|
||||
};
|
||||
NS_IMPL_ISUPPORTS(SpyWithISupports, ISpyWithISupports)
|
||||
|
||||
|
||||
class IThreadUtilsObject : public nsISupports
|
||||
{
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IFOO_IID)
|
||||
|
||||
NS_IMETHOD_(nsrefcnt) RefCnt() = 0;
|
||||
NS_IMETHOD_(int32_t) ID() = 0;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(IThreadUtilsObject, NS_IFOO_IID)
|
||||
|
||||
struct ThreadUtilsObject : public IThreadUtilsObject
|
||||
{
|
||||
// nsISupports implementation
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// IThreadUtilsObject implementation
|
||||
NS_IMETHOD_(nsrefcnt) RefCnt() MOZ_OVERRIDE { return mRefCnt; }
|
||||
NS_IMETHOD_(int32_t) ID() MOZ_OVERRIDE { return 0; }
|
||||
|
||||
int mCount; // Number of calls + arguments processed.
|
||||
int mA0, mA1, mA2, mA3;
|
||||
Spy mSpy; const Spy* mSpyPtr;
|
||||
ThreadUtilsObject()
|
||||
: mCount(0)
|
||||
, mA0(0), mA1(0), mA2(0), mA3(0)
|
||||
, mSpy(1), mSpyPtr(nullptr)
|
||||
{}
|
||||
private:
|
||||
virtual ~ThreadUtilsObject() = default;
|
||||
public:
|
||||
void Test0() { mCount += 1; }
|
||||
void Test1i(int a0) { mCount += 2; mA0 = a0; }
|
||||
void Test2i(int a0, int a1) { mCount += 3; mA0 = a0; mA1 = a1; }
|
||||
void Test3i(int a0, int a1, int a2)
|
||||
{
|
||||
mCount += 4; mA0 = a0; mA1 = a1; mA2 = a2;
|
||||
}
|
||||
void Test4i(int a0, int a1, int a2, int a3)
|
||||
{
|
||||
mCount += 5; mA0 = a0; mA1 = a1; mA2 = a2; mA3 = a3;
|
||||
}
|
||||
void Test1pi(int* ap)
|
||||
{
|
||||
mCount += 2; mA0 = ap ? *ap : -1;
|
||||
}
|
||||
void Test1pci(const int* ap)
|
||||
{
|
||||
mCount += 2; mA0 = ap ? *ap : -1;
|
||||
}
|
||||
void Test1ri(int& ar)
|
||||
{
|
||||
mCount += 2; mA0 = ar;
|
||||
}
|
||||
void Test1rri(int&& arr)
|
||||
{
|
||||
mCount += 2; mA0 = arr;
|
||||
}
|
||||
void Test1upi(mozilla::UniquePtr<int> aup)
|
||||
{
|
||||
mCount += 2; mA0 = aup ? *aup : -1;
|
||||
}
|
||||
void Test1rupi(mozilla::UniquePtr<int>& aup)
|
||||
{
|
||||
mCount += 2; mA0 = aup ? *aup : -1;
|
||||
}
|
||||
void Test1rrupi(mozilla::UniquePtr<int>&& aup)
|
||||
{
|
||||
mCount += 2; mA0 = aup ? *aup : -1;
|
||||
}
|
||||
|
||||
void Test1s(Spy) { mCount += 2; }
|
||||
void Test1ps(Spy*) { mCount += 2; }
|
||||
void Test1rs(Spy&) { mCount += 2; }
|
||||
void Test1rrs(Spy&&) { mCount += 2; }
|
||||
void Test1ups(mozilla::UniquePtr<Spy>) { mCount += 2; }
|
||||
void Test1rups(mozilla::UniquePtr<Spy>&) { mCount += 2; }
|
||||
void Test1rrups(mozilla::UniquePtr<Spy>&&) { mCount += 2; }
|
||||
|
||||
// Possible parameter passing styles:
|
||||
void TestByValue(Spy s)
|
||||
{
|
||||
if (gDebug) { printf("TestByValue(Spy[%d@%p])\n", s.mID, &s); }
|
||||
mSpy = s;
|
||||
};
|
||||
void TestByConstLRef(const Spy& s)
|
||||
{
|
||||
if (gDebug) { printf("TestByConstLRef(Spy[%d@%p]&)\n", s.mID, &s); }
|
||||
mSpy = s;
|
||||
};
|
||||
void TestByRRef(Spy&& s)
|
||||
{
|
||||
if (gDebug) { printf("TestByRRef(Spy[%d@%p]&&)\n", s.mID, &s); }
|
||||
mSpy = mozilla::Move(s);
|
||||
};
|
||||
void TestByLRef(Spy& s)
|
||||
{
|
||||
if (gDebug) { printf("TestByLRef(Spy[%d@%p]&)\n", s.mID, &s); }
|
||||
mSpy = s;
|
||||
mSpyPtr = &s;
|
||||
};
|
||||
void TestByPointer(Spy* p)
|
||||
{
|
||||
if (p) {
|
||||
if (gDebug) { printf("TestByPointer(&Spy[%d@%p])\n", p->mID, p); }
|
||||
mSpy = *p;
|
||||
} else {
|
||||
if (gDebug) { printf("TestByPointer(nullptr)\n"); }
|
||||
}
|
||||
mSpyPtr = p;
|
||||
};
|
||||
void TestByPointerToConst(const Spy* p)
|
||||
{
|
||||
if (p) {
|
||||
if (gDebug) { printf("TestByPointerToConst(&Spy[%d@%p])\n", p->mID, p); }
|
||||
mSpy = *p;
|
||||
} else {
|
||||
if (gDebug) { printf("TestByPointerToConst(nullptr)\n"); }
|
||||
}
|
||||
mSpyPtr = p;
|
||||
};
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(ThreadUtilsObject, IThreadUtilsObject)
|
||||
|
||||
} // namespace TestThreadUtils;
|
||||
|
||||
TEST(ThreadUtils, main)
|
||||
{
|
||||
#ifndef XPCOM_GLUE_AVOID_NSPR
|
||||
using namespace TestThreadUtils;
|
||||
|
||||
static_assert(!IsParameterStorageClass<int>::value,
|
||||
"'int' should not be recognized as Storage Class");
|
||||
static_assert(IsParameterStorageClass<StoreCopyPassByValue<int>>::value,
|
||||
"StoreCopyPassByValue<int> should be recognized as Storage Class");
|
||||
static_assert(IsParameterStorageClass<StoreCopyPassByConstLRef<int>>::value,
|
||||
"StoreCopyPassByConstLRef<int> should be recognized as Storage Class");
|
||||
static_assert(IsParameterStorageClass<StoreCopyPassByLRef<int>>::value,
|
||||
"StoreCopyPassByLRef<int> should be recognized as Storage Class");
|
||||
static_assert(IsParameterStorageClass<StoreCopyPassByRRef<int>>::value,
|
||||
"StoreCopyPassByRRef<int> should be recognized as Storage Class");
|
||||
static_assert(IsParameterStorageClass<StoreRefPassByLRef<int>>::value,
|
||||
"StoreRefPassByLRef<int> should be recognized as Storage Class");
|
||||
static_assert(IsParameterStorageClass<StoreConstRefPassByConstLRef<int>>::value,
|
||||
"StoreConstRefPassByConstLRef<int> should be recognized as Storage Class");
|
||||
static_assert(IsParameterStorageClass<StorensRefPtrPassByPtr<int>>::value,
|
||||
"StorensRefPtrPassByPtr<int> should be recognized as Storage Class");
|
||||
static_assert(IsParameterStorageClass<StorePtrPassByPtr<int>>::value,
|
||||
"StorePtrPassByPtr<int> should be recognized as Storage Class");
|
||||
static_assert(IsParameterStorageClass<StoreConstPtrPassByConstPtr<int>>::value,
|
||||
"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");
|
||||
|
||||
nsRefPtr<ThreadUtilsObject> rpt(new ThreadUtilsObject);
|
||||
int count = 0;
|
||||
|
||||
// Test legacy functions.
|
||||
|
||||
nsCOMPtr<nsIRunnable> r =
|
||||
NS_NewRunnableMethod(rpt, &ThreadUtilsObject::Test0);
|
||||
r->Run();
|
||||
EXPECT_EQ(count += 1, rpt->mCount);
|
||||
|
||||
r = NS_NewRunnableMethodWithArg<int>(rpt, &ThreadUtilsObject::Test1i, 11);
|
||||
r->Run();
|
||||
EXPECT_EQ(count += 2, rpt->mCount);
|
||||
EXPECT_EQ(11, rpt->mA0);
|
||||
|
||||
// Test variadic function with simple POD arguments.
|
||||
|
||||
r = NS_NewRunnableMethodWithArgs(rpt, &ThreadUtilsObject::Test0);
|
||||
r->Run();
|
||||
EXPECT_EQ(count += 1, rpt->mCount);
|
||||
|
||||
static_assert(
|
||||
mozilla::IsSame< ::detail::ParameterStorage<int>::Type,
|
||||
StoreCopyPassByValue<int>>::value,
|
||||
"ns::detail::ParameterStorage<int>::Type should be StoreCopyPassByValue<int>");
|
||||
static_assert(
|
||||
mozilla::IsSame< ::detail::ParameterStorage<StoreCopyPassByValue<int>>::Type,
|
||||
StoreCopyPassByValue<int>>::value,
|
||||
"ns::detail::ParameterStorage<StoreCopyPassByValue<int>>::Type should be StoreCopyPassByValue<int>");
|
||||
|
||||
r = NS_NewRunnableMethodWithArgs<int>(rpt, &ThreadUtilsObject::Test1i, 12);
|
||||
r->Run();
|
||||
EXPECT_EQ(count += 2, rpt->mCount);
|
||||
EXPECT_EQ(12, rpt->mA0);
|
||||
|
||||
r = NS_NewRunnableMethodWithArgs<int, int>(
|
||||
rpt, &ThreadUtilsObject::Test2i, 21, 22);
|
||||
r->Run();
|
||||
EXPECT_EQ(count += 3, rpt->mCount);
|
||||
EXPECT_EQ(21, rpt->mA0);
|
||||
EXPECT_EQ(22, rpt->mA1);
|
||||
|
||||
r = NS_NewRunnableMethodWithArgs<int, int, int>(
|
||||
rpt, &ThreadUtilsObject::Test3i, 31, 32, 33);
|
||||
r->Run();
|
||||
EXPECT_EQ(count += 4, rpt->mCount);
|
||||
EXPECT_EQ(31, rpt->mA0);
|
||||
EXPECT_EQ(32, rpt->mA1);
|
||||
EXPECT_EQ(33, rpt->mA2);
|
||||
|
||||
r = NS_NewRunnableMethodWithArgs<int, int, int, int>(
|
||||
rpt, &ThreadUtilsObject::Test4i, 41, 42, 43, 44);
|
||||
r->Run();
|
||||
EXPECT_EQ(count += 5, rpt->mCount);
|
||||
EXPECT_EQ(41, rpt->mA0);
|
||||
EXPECT_EQ(42, rpt->mA1);
|
||||
EXPECT_EQ(43, rpt->mA2);
|
||||
EXPECT_EQ(44, rpt->mA3);
|
||||
|
||||
// More interesting types of arguments.
|
||||
|
||||
// Passing a short to make sure forwarding works with an inexact type match.
|
||||
short int si = 11;
|
||||
r = NS_NewRunnableMethodWithArgs<int>(rpt, &ThreadUtilsObject::Test1i, si);
|
||||
r->Run();
|
||||
EXPECT_EQ(count += 2, rpt->mCount);
|
||||
EXPECT_EQ(si, rpt->mA0);
|
||||
|
||||
// Raw pointer, possible cv-qualified.
|
||||
static_assert(mozilla::IsSame< ::detail::ParameterStorage<int*>::Type,
|
||||
StorePtrPassByPtr<int>>::value,
|
||||
"ns::detail::ParameterStorage<int*>::Type should be StorePtrPassByPtr<int>");
|
||||
static_assert(mozilla::IsSame< ::detail::ParameterStorage<int* const>::Type,
|
||||
StorePtrPassByPtr<int>>::value,
|
||||
"ns::detail::ParameterStorage<int* const>::Type should be StorePtrPassByPtr<int>");
|
||||
static_assert(mozilla::IsSame< ::detail::ParameterStorage<int* volatile>::Type,
|
||||
StorePtrPassByPtr<int>>::value,
|
||||
"ns::detail::ParameterStorage<int* volatile>::Type should be StorePtrPassByPtr<int>");
|
||||
static_assert(mozilla::IsSame< ::detail::ParameterStorage<int* const volatile>::Type,
|
||||
StorePtrPassByPtr<int>>::value,
|
||||
"ns::detail::ParameterStorage<int* const volatile>::Type should be StorePtrPassByPtr<int>");
|
||||
static_assert(mozilla::IsSame< ::detail::ParameterStorage<int*>::Type::stored_type,
|
||||
int*>::value,
|
||||
"ns::detail::ParameterStorage<int*>::Type::stored_type should be int*");
|
||||
static_assert(mozilla::IsSame< ::detail::ParameterStorage<int*>::Type::passed_type,
|
||||
int*>::value,
|
||||
"ns::detail::ParameterStorage<int*>::Type::passed_type should be int*");
|
||||
{
|
||||
int i = 12;
|
||||
r = NS_NewRunnableMethodWithArgs<int*>(rpt, &ThreadUtilsObject::Test1pi, &i);
|
||||
r->Run();
|
||||
EXPECT_EQ(count += 2, rpt->mCount);
|
||||
EXPECT_EQ(i, rpt->mA0);
|
||||
}
|
||||
|
||||
// Raw pointer to const.
|
||||
static_assert(mozilla::IsSame< ::detail::ParameterStorage<const int*>::Type,
|
||||
StoreConstPtrPassByConstPtr<int>>::value,
|
||||
"ns::detail::ParameterStorage<const int*>::Type should be StoreConstPtrPassByConstPtr<int>");
|
||||
static_assert(mozilla::IsSame< ::detail::ParameterStorage<const int* const>::Type,
|
||||
StoreConstPtrPassByConstPtr<int>>::value,
|
||||
"ns::detail::ParameterStorage<const int* const>::Type should be StoreConstPtrPassByConstPtr<int>");
|
||||
static_assert(mozilla::IsSame< ::detail::ParameterStorage<const int* volatile>::Type,
|
||||
StoreConstPtrPassByConstPtr<int>>::value,
|
||||
"ns::detail::ParameterStorage<const int* volatile>::Type should be StoreConstPtrPassByConstPtr<int>");
|
||||
static_assert(mozilla::IsSame< ::detail::ParameterStorage<const int* const volatile>::Type,
|
||||
StoreConstPtrPassByConstPtr<int>>::value,
|
||||
"ns::detail::ParameterStorage<const int* const volatile>::Type should be StoreConstPtrPassByConstPtr<int>");
|
||||
static_assert(mozilla::IsSame< ::detail::ParameterStorage<const int*>::Type::stored_type,
|
||||
const int*>::value,
|
||||
"ns::detail::ParameterStorage<const int*>::Type::stored_type should be const int*");
|
||||
static_assert(mozilla::IsSame< ::detail::ParameterStorage<const int*>::Type::passed_type,
|
||||
const int*>::value,
|
||||
"ns::detail::ParameterStorage<const int*>::Type::passed_type should be const int*");
|
||||
{
|
||||
int i = 1201;
|
||||
r = NS_NewRunnableMethodWithArgs<const int*>(rpt, &ThreadUtilsObject::Test1pci, &i);
|
||||
r->Run();
|
||||
EXPECT_EQ(count += 2, rpt->mCount);
|
||||
EXPECT_EQ(i, rpt->mA0);
|
||||
}
|
||||
|
||||
// Raw pointer to copy.
|
||||
static_assert(mozilla::IsSame<StoreCopyPassByPtr<int>::stored_type,
|
||||
int>::value,
|
||||
"StoreCopyPassByPtr<int>::stored_type should be int");
|
||||
static_assert(mozilla::IsSame<StoreCopyPassByPtr<int>::passed_type,
|
||||
int*>::value,
|
||||
"StoreCopyPassByPtr<int>::passed_type should be int*");
|
||||
{
|
||||
int i = 1202;
|
||||
r = NS_NewRunnableMethodWithArgs<StoreCopyPassByPtr<int>>(
|
||||
rpt, &ThreadUtilsObject::Test1pi, i);
|
||||
r->Run();
|
||||
EXPECT_EQ(count += 2, rpt->mCount);
|
||||
EXPECT_EQ(i, rpt->mA0);
|
||||
}
|
||||
|
||||
// Raw pointer to const copy.
|
||||
static_assert(mozilla::IsSame<StoreCopyPassByConstPtr<int>::stored_type,
|
||||
int>::value,
|
||||
"StoreCopyPassByConstPtr<int>::stored_type should be int");
|
||||
static_assert(mozilla::IsSame<StoreCopyPassByConstPtr<int>::passed_type,
|
||||
const int*>::value,
|
||||
"StoreCopyPassByConstPtr<int>::passed_type should be const int*");
|
||||
{
|
||||
int i = 1203;
|
||||
r = NS_NewRunnableMethodWithArgs<StoreCopyPassByConstPtr<int>>(
|
||||
rpt, &ThreadUtilsObject::Test1pci, i);
|
||||
r->Run();
|
||||
EXPECT_EQ(count += 2, rpt->mCount);
|
||||
EXPECT_EQ(i, rpt->mA0);
|
||||
}
|
||||
|
||||
// nsRefPtr to pointer.
|
||||
static_assert(mozilla::IsSame< ::detail::ParameterStorage<StorensRefPtrPassByPtr<SpyWithISupports>>::Type,
|
||||
StorensRefPtrPassByPtr<SpyWithISupports>>::value,
|
||||
"ns::detail::ParameterStorage<StorensRefPtrPassByPtr<SpyWithISupports>>::Type should be StorensRefPtrPassByPtr<SpyWithISupports>");
|
||||
static_assert(mozilla::IsSame< ::detail::ParameterStorage<SpyWithISupports*>::Type,
|
||||
StorensRefPtrPassByPtr<SpyWithISupports>>::value,
|
||||
"ns::detail::ParameterStorage<SpyWithISupports*>::Type should be StorensRefPtrPassByPtr<SpyWithISupports>");
|
||||
static_assert(mozilla::IsSame<StorensRefPtrPassByPtr<SpyWithISupports>::stored_type,
|
||||
nsRefPtr<SpyWithISupports>>::value,
|
||||
"StorensRefPtrPassByPtr<SpyWithISupports>::stored_type should be nsRefPtr<SpyWithISupports>");
|
||||
static_assert(mozilla::IsSame<StorensRefPtrPassByPtr<SpyWithISupports>::passed_type,
|
||||
SpyWithISupports*>::value,
|
||||
"StorensRefPtrPassByPtr<SpyWithISupports>::passed_type should be SpyWithISupports*");
|
||||
// (more nsRefPtr tests below)
|
||||
|
||||
// Lvalue reference.
|
||||
static_assert(mozilla::IsSame< ::detail::ParameterStorage<int&>::Type,
|
||||
StoreRefPassByLRef<int>>::value,
|
||||
"ns::detail::ParameterStorage<int&>::Type should be StoreRefPassByLRef<int>");
|
||||
static_assert(mozilla::IsSame< ::detail::ParameterStorage<int&>::Type::stored_type,
|
||||
StoreRefPassByLRef<int>::stored_type>::value,
|
||||
"ns::detail::ParameterStorage<int&>::Type::stored_type should be StoreRefPassByLRef<int>::stored_type");
|
||||
static_assert(mozilla::IsSame< ::detail::ParameterStorage<int&>::Type::stored_type,
|
||||
int&>::value,
|
||||
"ns::detail::ParameterStorage<int&>::Type::stored_type should be int&");
|
||||
static_assert(mozilla::IsSame< ::detail::ParameterStorage<int&>::Type::passed_type,
|
||||
int&>::value,
|
||||
"ns::detail::ParameterStorage<int&>::Type::passed_type should be int&");
|
||||
{
|
||||
int i = 13;
|
||||
r = NS_NewRunnableMethodWithArgs<int&>(rpt, &ThreadUtilsObject::Test1ri, i);
|
||||
r->Run();
|
||||
EXPECT_EQ(count += 2, rpt->mCount);
|
||||
EXPECT_EQ(i, rpt->mA0);
|
||||
}
|
||||
|
||||
// Rvalue reference -- Actually storing a copy and then moving it.
|
||||
static_assert(mozilla::IsSame< ::detail::ParameterStorage<int&&>::Type,
|
||||
StoreCopyPassByRRef<int>>::value,
|
||||
"ns::detail::ParameterStorage<int&&>::Type should be StoreCopyPassByRRef<int>");
|
||||
static_assert(mozilla::IsSame< ::detail::ParameterStorage<int&&>::Type::stored_type,
|
||||
StoreCopyPassByRRef<int>::stored_type>::value,
|
||||
"ns::detail::ParameterStorage<int&&>::Type::stored_type should be StoreCopyPassByRRef<int>::stored_type");
|
||||
static_assert(mozilla::IsSame< ::detail::ParameterStorage<int&&>::Type::stored_type,
|
||||
int>::value,
|
||||
"ns::detail::ParameterStorage<int&&>::Type::stored_type should be int");
|
||||
static_assert(mozilla::IsSame< ::detail::ParameterStorage<int&&>::Type::passed_type,
|
||||
int&&>::value,
|
||||
"ns::detail::ParameterStorage<int&&>::Type::passed_type should be int&&");
|
||||
{
|
||||
int i = 14;
|
||||
r = NS_NewRunnableMethodWithArgs<int&&>(
|
||||
rpt, &ThreadUtilsObject::Test1rri, mozilla::Move(i));
|
||||
}
|
||||
r->Run();
|
||||
EXPECT_EQ(count += 2, rpt->mCount);
|
||||
EXPECT_EQ(14, rpt->mA0);
|
||||
|
||||
// Null unique pointer, by semi-implicit store&move with "T&&" syntax.
|
||||
static_assert(mozilla::IsSame< ::detail::ParameterStorage<mozilla::UniquePtr<int>&&>::Type,
|
||||
StoreCopyPassByRRef<mozilla::UniquePtr<int>>>::value,
|
||||
"ns::detail::ParameterStorage<UniquePtr<int>&&>::Type should be StoreCopyPassByRRef<UniquePtr<int>>");
|
||||
static_assert(mozilla::IsSame< ::detail::ParameterStorage<mozilla::UniquePtr<int>&&>::Type::stored_type,
|
||||
StoreCopyPassByRRef<mozilla::UniquePtr<int>>::stored_type>::value,
|
||||
"ns::detail::ParameterStorage<UniquePtr<int>&&>::Type::stored_type should be StoreCopyPassByRRef<UniquePtr<int>>::stored_type");
|
||||
static_assert(mozilla::IsSame< ::detail::ParameterStorage<mozilla::UniquePtr<int>&&>::Type::stored_type,
|
||||
mozilla::UniquePtr<int>>::value,
|
||||
"ns::detail::ParameterStorage<UniquePtr<int>&&>::Type::stored_type should be UniquePtr<int>");
|
||||
static_assert(mozilla::IsSame< ::detail::ParameterStorage<mozilla::UniquePtr<int>&&>::Type::passed_type,
|
||||
mozilla::UniquePtr<int>&&>::value,
|
||||
"ns::detail::ParameterStorage<UniquePtr<int>&&>::Type::passed_type should be UniquePtr<int>&&");
|
||||
{
|
||||
mozilla::UniquePtr<int> upi;
|
||||
r = NS_NewRunnableMethodWithArgs<mozilla::UniquePtr<int>&&>(
|
||||
rpt, &ThreadUtilsObject::Test1upi, mozilla::Move(upi));
|
||||
}
|
||||
r->Run();
|
||||
EXPECT_EQ(count += 2, rpt->mCount);
|
||||
EXPECT_EQ(-1, rpt->mA0);
|
||||
rpt->mA0 = 0;
|
||||
|
||||
// Null unique pointer, by explicit store&move with "StoreCopyPassByRRef<T>" syntax.
|
||||
static_assert(mozilla::IsSame< ::detail::ParameterStorage<StoreCopyPassByRRef<mozilla::UniquePtr<int>>>::Type::stored_type,
|
||||
StoreCopyPassByRRef<mozilla::UniquePtr<int>>::stored_type>::value,
|
||||
"ns::detail::ParameterStorage<StoreCopyPassByRRef<UniquePtr<int>>>::Type::stored_type should be StoreCopyPassByRRef<UniquePtr<int>>::stored_type");
|
||||
static_assert(mozilla::IsSame< ::detail::ParameterStorage<StoreCopyPassByRRef<mozilla::UniquePtr<int>>>::Type::stored_type,
|
||||
StoreCopyPassByRRef<mozilla::UniquePtr<int>>::stored_type>::value,
|
||||
"ns::detail::ParameterStorage<StoreCopyPassByRRef<UniquePtr<int>>>::Type::stored_type should be StoreCopyPassByRRef<UniquePtr<int>>::stored_type");
|
||||
static_assert(mozilla::IsSame< ::detail::ParameterStorage<StoreCopyPassByRRef<mozilla::UniquePtr<int>>>::Type::stored_type,
|
||||
mozilla::UniquePtr<int>>::value,
|
||||
"ns::detail::ParameterStorage<StoreCopyPassByRRef<UniquePtr<int>>>::Type::stored_type should be UniquePtr<int>");
|
||||
static_assert(mozilla::IsSame< ::detail::ParameterStorage<StoreCopyPassByRRef<mozilla::UniquePtr<int>>>::Type::passed_type,
|
||||
mozilla::UniquePtr<int>&&>::value,
|
||||
"ns::detail::ParameterStorage<StoreCopyPassByRRef<UniquePtr<int>>>::Type::passed_type should be UniquePtr<int>&&");
|
||||
{
|
||||
mozilla::UniquePtr<int> upi;
|
||||
r = NS_NewRunnableMethodWithArgs
|
||||
<StoreCopyPassByRRef<mozilla::UniquePtr<int>>>(
|
||||
rpt, &ThreadUtilsObject::Test1upi, mozilla::Move(upi));
|
||||
}
|
||||
r->Run();
|
||||
EXPECT_EQ(count += 2, rpt->mCount);
|
||||
EXPECT_EQ(-1, rpt->mA0);
|
||||
|
||||
// Unique pointer as xvalue.
|
||||
{
|
||||
mozilla::UniquePtr<int> upi = mozilla::MakeUnique<int>(1);
|
||||
r = NS_NewRunnableMethodWithArgs<mozilla::UniquePtr<int>&&>(
|
||||
rpt, &ThreadUtilsObject::Test1upi, mozilla::Move(upi));
|
||||
}
|
||||
r->Run();
|
||||
EXPECT_EQ(count += 2, rpt->mCount);
|
||||
EXPECT_EQ(1, rpt->mA0);
|
||||
|
||||
{
|
||||
mozilla::UniquePtr<int> upi = mozilla::MakeUnique<int>(1);
|
||||
r = NS_NewRunnableMethodWithArgs
|
||||
<StoreCopyPassByRRef<mozilla::UniquePtr<int>>>
|
||||
(rpt, &ThreadUtilsObject::Test1upi, mozilla::Move(upi));
|
||||
}
|
||||
r->Run();
|
||||
EXPECT_EQ(count += 2, rpt->mCount);
|
||||
EXPECT_EQ(1, rpt->mA0);
|
||||
|
||||
// Unique pointer as prvalue.
|
||||
r = NS_NewRunnableMethodWithArgs<mozilla::UniquePtr<int>&&>(
|
||||
rpt, &ThreadUtilsObject::Test1upi, mozilla::MakeUnique<int>(2));
|
||||
r->Run();
|
||||
EXPECT_EQ(count += 2, rpt->mCount);
|
||||
EXPECT_EQ(2, rpt->mA0);
|
||||
|
||||
// Unique pointer as lvalue to lref.
|
||||
{
|
||||
mozilla::UniquePtr<int> upi;
|
||||
r = NS_NewRunnableMethodWithArgs<mozilla::UniquePtr<int>&>(
|
||||
rpt, &ThreadUtilsObject::Test1rupi, upi);
|
||||
// Passed as lref, so Run() must be called while local upi is still alive!
|
||||
r->Run();
|
||||
}
|
||||
EXPECT_EQ(count += 2, rpt->mCount);
|
||||
EXPECT_EQ(-1, rpt->mA0);
|
||||
|
||||
// Verify copy/move assumptions.
|
||||
|
||||
Spy::ClearAll();
|
||||
if (gDebug) { printf("%d - Test: Store copy from lvalue, pass by value\n", __LINE__); }
|
||||
{ // Block around nsCOMPtr lifetime.
|
||||
nsCOMPtr<nsIRunnable> r;
|
||||
{ // 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 - r = NS_NewRunnableMethodWithArgs<StoreCopyPassByValue<Spy>>(&TestByValue, s)\n", __LINE__); }
|
||||
r = NS_NewRunnableMethodWithArgs<StoreCopyPassByValue<Spy>>(
|
||||
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__); }
|
||||
r->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 - r = NS_NewRunnableMethodWithArgs<StoreCopyPassByValue<Spy>>(&TestByValue, Spy(11))\n", __LINE__); }
|
||||
nsCOMPtr<nsIRunnable> r =
|
||||
NS_NewRunnableMethodWithArgs<StoreCopyPassByValue<Spy>>(
|
||||
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__); }
|
||||
r->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> r;
|
||||
{
|
||||
Spy s(12);
|
||||
EXPECT_EQ(1, gConstructions);
|
||||
EXPECT_EQ(1, gAlive);
|
||||
Spy::ClearActions();
|
||||
r = NS_NewRunnableMethodWithArgs<StoreCopyPassByValue<Spy>>(
|
||||
rpt, &ThreadUtilsObject::TestByValue, mozilla::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();
|
||||
r->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();
|
||||
if (gDebug) { printf("%d - Test: Store copy from lvalue, pass by const lvalue ref\n", __LINE__); }
|
||||
{ // Block around nsCOMPtr lifetime.
|
||||
nsCOMPtr<nsIRunnable> r;
|
||||
{ // Block around Spy lifetime.
|
||||
if (gDebug) { printf("%d - Spy s(20)\n", __LINE__); }
|
||||
Spy s(20);
|
||||
EXPECT_EQ(1, gConstructions);
|
||||
EXPECT_EQ(1, gAlive);
|
||||
if (gDebug) { printf("%d - r = NS_NewRunnableMethodWithArgs<StoreCopyPassByConstLRef<Spy>>(&TestByConstLRef, s)\n", __LINE__); }
|
||||
r = NS_NewRunnableMethodWithArgs<StoreCopyPassByConstLRef<Spy>>(
|
||||
rpt, &ThreadUtilsObject::TestByConstLRef, s);
|
||||
EXPECT_EQ(2, gAlive);
|
||||
EXPECT_LE(1, gCopyConstructions); // At least 1 copy-construction.
|
||||
Spy::ClearActions();
|
||||
if (gDebug) { printf("%d - End block with Spy s(20)\n", __LINE__); }
|
||||
}
|
||||
EXPECT_EQ(1, gDestructions);
|
||||
EXPECT_EQ(1, gAlive);
|
||||
Spy::ClearActions();
|
||||
if (gDebug) { printf("%d - Run()\n", __LINE__); }
|
||||
r->Run();
|
||||
EXPECT_EQ(0, gCopyConstructions); // No copies in call.
|
||||
EXPECT_EQ(20, rpt->mSpy.mID);
|
||||
EXPECT_EQ(0, gDestructions);
|
||||
EXPECT_EQ(1, gAlive);
|
||||
Spy::ClearActions();
|
||||
if (gDebug) { printf("%d - End block with r\n", __LINE__); }
|
||||
}
|
||||
if (gDebug) { printf("%d - After end block with r\n", __LINE__); }
|
||||
EXPECT_EQ(1, gDestructions);
|
||||
EXPECT_EQ(0, gAlive);
|
||||
|
||||
Spy::ClearAll();
|
||||
if (gDebug) { printf("%d - Test: Store copy from prvalue, pass by const lvalue ref\n", __LINE__); }
|
||||
{
|
||||
if (gDebug) { printf("%d - r = NS_NewRunnableMethodWithArgs<StoreCopyPassByConstLRef<Spy>>(&TestByConstLRef, Spy(21))\n", __LINE__); }
|
||||
nsCOMPtr<nsIRunnable> r =
|
||||
NS_NewRunnableMethodWithArgs<StoreCopyPassByConstLRef<Spy>>(
|
||||
rpt, &ThreadUtilsObject::TestByConstLRef, Spy(21));
|
||||
EXPECT_EQ(1, gAlive);
|
||||
EXPECT_EQ(1, gConstructions);
|
||||
EXPECT_LE(1, gMoveConstructions);
|
||||
Spy::ClearActions();
|
||||
if (gDebug) { printf("%d - Run()\n", __LINE__); }
|
||||
r->Run();
|
||||
EXPECT_EQ(0, gCopyConstructions); // No copies in call.
|
||||
EXPECT_EQ(21, rpt->mSpy.mID);
|
||||
EXPECT_EQ(0, gDestructions);
|
||||
EXPECT_EQ(1, gAlive);
|
||||
Spy::ClearActions();
|
||||
if (gDebug) { printf("%d - End block with r\n", __LINE__); }
|
||||
}
|
||||
if (gDebug) { printf("%d - After end block with r\n", __LINE__); }
|
||||
EXPECT_EQ(1, gDestructions);
|
||||
EXPECT_EQ(0, gAlive);
|
||||
|
||||
Spy::ClearAll();
|
||||
if (gDebug) { printf("%d - Test: Store copy from lvalue, pass by rvalue ref\n", __LINE__); }
|
||||
{ // Block around nsCOMPtr lifetime.
|
||||
nsCOMPtr<nsIRunnable> r;
|
||||
{ // Block around Spy lifetime.
|
||||
if (gDebug) { printf("%d - Spy s(30)\n", __LINE__); }
|
||||
Spy s(30);
|
||||
EXPECT_EQ(1, gConstructions);
|
||||
EXPECT_EQ(1, gAlive);
|
||||
if (gDebug) { printf("%d - r = NS_NewRunnableMethodWithArgs<StoreCopyPassByRRef<Spy>>(&TestByRRef, s)\n", __LINE__); }
|
||||
r = NS_NewRunnableMethodWithArgs<StoreCopyPassByRRef<Spy>>(
|
||||
rpt, &ThreadUtilsObject::TestByRRef, s);
|
||||
EXPECT_EQ(2, gAlive);
|
||||
EXPECT_LE(1, gCopyConstructions); // At least 1 copy-construction.
|
||||
Spy::ClearActions();
|
||||
if (gDebug) { printf("%d - End block with Spy s(30)\n", __LINE__); }
|
||||
}
|
||||
EXPECT_EQ(1, gDestructions);
|
||||
EXPECT_EQ(1, gAlive);
|
||||
Spy::ClearActions();
|
||||
if (gDebug) { printf("%d - Run()\n", __LINE__); }
|
||||
r->Run();
|
||||
EXPECT_LE(1, gMoves); // Move in call.
|
||||
EXPECT_EQ(30, rpt->mSpy.mID);
|
||||
EXPECT_EQ(0, gDestructions);
|
||||
EXPECT_EQ(0, gAlive); // Spy inside Test is not counted.
|
||||
EXPECT_EQ(1, gZombies); // Our local spy should now be a zombie.
|
||||
Spy::ClearActions();
|
||||
if (gDebug) { printf("%d - End block with r\n", __LINE__); }
|
||||
}
|
||||
if (gDebug) { printf("%d - After end block with r\n", __LINE__); }
|
||||
EXPECT_EQ(1, gDestructions);
|
||||
EXPECT_EQ(0, gAlive);
|
||||
|
||||
Spy::ClearAll();
|
||||
if (gDebug) { printf("%d - Test: Store copy from prvalue, pass by rvalue ref\n", __LINE__); }
|
||||
{
|
||||
if (gDebug) { printf("%d - r = NS_NewRunnableMethodWithArgs<StoreCopyPassByRRef<Spy>>(&TestByRRef, Spy(31))\n", __LINE__); }
|
||||
nsCOMPtr<nsIRunnable> r =
|
||||
NS_NewRunnableMethodWithArgs<StoreCopyPassByRRef<Spy>>(
|
||||
rpt, &ThreadUtilsObject::TestByRRef, Spy(31));
|
||||
EXPECT_EQ(1, gAlive);
|
||||
EXPECT_EQ(1, gConstructions);
|
||||
EXPECT_LE(1, gMoveConstructions);
|
||||
Spy::ClearActions();
|
||||
if (gDebug) { printf("%d - Run()\n", __LINE__); }
|
||||
r->Run();
|
||||
EXPECT_LE(1, gMoves); // Move in call.
|
||||
EXPECT_EQ(31, rpt->mSpy.mID);
|
||||
EXPECT_EQ(0, gDestructions);
|
||||
EXPECT_EQ(0, gAlive); // Spy inside Test is not counted.
|
||||
EXPECT_EQ(1, gZombies); // Our local spy should now be a zombie.
|
||||
Spy::ClearActions();
|
||||
if (gDebug) { printf("%d - End block with r\n", __LINE__); }
|
||||
}
|
||||
if (gDebug) { printf("%d - After end block with r\n", __LINE__); }
|
||||
EXPECT_EQ(1, gDestructions);
|
||||
EXPECT_EQ(0, gAlive);
|
||||
|
||||
Spy::ClearAll();
|
||||
if (gDebug) { printf("%d - Test: Store lvalue ref, pass lvalue ref\n", __LINE__); }
|
||||
{
|
||||
if (gDebug) { printf("%d - Spy s(40)\n", __LINE__); }
|
||||
Spy s(40);
|
||||
EXPECT_EQ(1, gConstructions);
|
||||
EXPECT_EQ(1, gAlive);
|
||||
Spy::ClearActions();
|
||||
if (gDebug) { printf("%d - r = NS_NewRunnableMethodWithArgs<Spy&>(&TestByLRef, s)\n", __LINE__); }
|
||||
nsCOMPtr<nsIRunnable> r =
|
||||
NS_NewRunnableMethodWithArgs<Spy&>(
|
||||
rpt, &ThreadUtilsObject::TestByLRef, s);
|
||||
EXPECT_EQ(0, gAllConstructions);
|
||||
EXPECT_EQ(0, gDestructions);
|
||||
EXPECT_EQ(1, gAlive);
|
||||
Spy::ClearActions();
|
||||
if (gDebug) { printf("%d - Run()\n", __LINE__); }
|
||||
r->Run();
|
||||
EXPECT_LE(1, gAssignments); // Assignment from reference in call.
|
||||
EXPECT_EQ(40, rpt->mSpy.mID);
|
||||
EXPECT_EQ(&s, rpt->mSpyPtr);
|
||||
EXPECT_EQ(0, gDestructions);
|
||||
EXPECT_EQ(1, gAlive); // Spy inside Test is not counted.
|
||||
Spy::ClearActions();
|
||||
if (gDebug) { printf("%d - End block with r\n", __LINE__); }
|
||||
}
|
||||
if (gDebug) { printf("%d - After end block with r\n", __LINE__); }
|
||||
EXPECT_EQ(1, gDestructions);
|
||||
EXPECT_EQ(0, gAlive);
|
||||
|
||||
Spy::ClearAll();
|
||||
if (gDebug) { printf("%d - Test: Store nsRefPtr, pass by pointer\n", __LINE__); }
|
||||
{ // Block around nsCOMPtr lifetime.
|
||||
nsCOMPtr<nsIRunnable> r;
|
||||
SpyWithISupports* ptr = 0;
|
||||
{ // Block around nsRefPtr<Spy> lifetime.
|
||||
if (gDebug) { printf("%d - nsRefPtr<SpyWithISupports> s(new SpyWithISupports(45))\n", __LINE__); }
|
||||
nsRefPtr<SpyWithISupports> s(new SpyWithISupports(45));
|
||||
ptr = s.get();
|
||||
EXPECT_EQ(1, gConstructions);
|
||||
EXPECT_EQ(1, gAlive);
|
||||
if (gDebug) { printf("%d - r = NS_NewRunnableMethodWithArgs<StorensRefPtrPassByPtr<Spy>>(&TestByRRef, s.get())\n", __LINE__); }
|
||||
r = NS_NewRunnableMethodWithArgs<StorensRefPtrPassByPtr<SpyWithISupports>>(
|
||||
rpt, &ThreadUtilsObject::TestByPointer, s.get());
|
||||
EXPECT_LE(0, gAllConstructions);
|
||||
EXPECT_EQ(1, gAlive);
|
||||
Spy::ClearActions();
|
||||
if (gDebug) { printf("%d - End block with nsRefPtr<Spy> s\n", __LINE__); }
|
||||
}
|
||||
EXPECT_EQ(0, gDestructions);
|
||||
EXPECT_EQ(1, gAlive);
|
||||
Spy::ClearActions();
|
||||
if (gDebug) { printf("%d - Run()\n", __LINE__); }
|
||||
r->Run();
|
||||
EXPECT_LE(1, gAssignments); // Assignment from pointee in call.
|
||||
EXPECT_EQ(45, rpt->mSpy.mID);
|
||||
EXPECT_EQ(ptr, rpt->mSpyPtr);
|
||||
EXPECT_EQ(0, gDestructions);
|
||||
EXPECT_EQ(1, gAlive); // Spy inside Test is not counted.
|
||||
Spy::ClearActions();
|
||||
if (gDebug) { printf("%d - End block with r\n", __LINE__); }
|
||||
}
|
||||
if (gDebug) { printf("%d - After end block with r\n", __LINE__); }
|
||||
EXPECT_EQ(1, gDestructions);
|
||||
EXPECT_EQ(0, gAlive);
|
||||
|
||||
Spy::ClearAll();
|
||||
if (gDebug) { printf("%d - Test: Store pointer to lvalue, pass by pointer\n", __LINE__); }
|
||||
{
|
||||
if (gDebug) { printf("%d - Spy s(55)\n", __LINE__); }
|
||||
Spy s(55);
|
||||
EXPECT_EQ(1, gConstructions);
|
||||
EXPECT_EQ(1, gAlive);
|
||||
Spy::ClearActions();
|
||||
if (gDebug) { printf("%d - r = NS_NewRunnableMethodWithArgs<Spy*>(&TestByPointer, s)\n", __LINE__); }
|
||||
nsCOMPtr<nsIRunnable> r =
|
||||
NS_NewRunnableMethodWithArgs<Spy*>(
|
||||
rpt, &ThreadUtilsObject::TestByPointer, &s);
|
||||
EXPECT_EQ(0, gAllConstructions);
|
||||
EXPECT_EQ(0, gDestructions);
|
||||
EXPECT_EQ(1, gAlive);
|
||||
Spy::ClearActions();
|
||||
if (gDebug) { printf("%d - Run()\n", __LINE__); }
|
||||
r->Run();
|
||||
EXPECT_LE(1, gAssignments); // Assignment from pointee in call.
|
||||
EXPECT_EQ(55, rpt->mSpy.mID);
|
||||
EXPECT_EQ(&s, rpt->mSpyPtr);
|
||||
EXPECT_EQ(0, gDestructions);
|
||||
EXPECT_EQ(1, gAlive); // Spy inside Test is not counted.
|
||||
Spy::ClearActions();
|
||||
if (gDebug) { printf("%d - End block with r\n", __LINE__); }
|
||||
}
|
||||
if (gDebug) { printf("%d - After end block with r\n", __LINE__); }
|
||||
EXPECT_EQ(1, gDestructions);
|
||||
EXPECT_EQ(0, gAlive);
|
||||
|
||||
Spy::ClearAll();
|
||||
if (gDebug) { printf("%d - Test: Store pointer to const lvalue, pass by pointer\n", __LINE__); }
|
||||
{
|
||||
if (gDebug) { printf("%d - Spy s(60)\n", __LINE__); }
|
||||
Spy s(60);
|
||||
EXPECT_EQ(1, gConstructions);
|
||||
EXPECT_EQ(1, gAlive);
|
||||
Spy::ClearActions();
|
||||
if (gDebug) { printf("%d - r = NS_NewRunnableMethodWithArgs<Spy*>(&TestByPointer, s)\n", __LINE__); }
|
||||
nsCOMPtr<nsIRunnable> r =
|
||||
NS_NewRunnableMethodWithArgs<const Spy*>(
|
||||
rpt, &ThreadUtilsObject::TestByPointerToConst, &s);
|
||||
EXPECT_EQ(0, gAllConstructions);
|
||||
EXPECT_EQ(0, gDestructions);
|
||||
EXPECT_EQ(1, gAlive);
|
||||
Spy::ClearActions();
|
||||
if (gDebug) { printf("%d - Run()\n", __LINE__); }
|
||||
r->Run();
|
||||
EXPECT_LE(1, gAssignments); // Assignment from pointee in call.
|
||||
EXPECT_EQ(60, rpt->mSpy.mID);
|
||||
EXPECT_EQ(&s, rpt->mSpyPtr);
|
||||
EXPECT_EQ(0, gDestructions);
|
||||
EXPECT_EQ(1, gAlive); // Spy inside Test is not counted.
|
||||
Spy::ClearActions();
|
||||
if (gDebug) { printf("%d - End block with r\n", __LINE__); }
|
||||
}
|
||||
if (gDebug) { printf("%d - After end block with r\n", __LINE__); }
|
||||
EXPECT_EQ(1, gDestructions);
|
||||
EXPECT_EQ(0, gAlive);
|
||||
#endif // XPCOM_GLUE_AVOID_NSPR
|
||||
}
|
@ -8,6 +8,7 @@ UNIFIED_SOURCES += [
|
||||
'TestArray.cpp',
|
||||
'TestFileUtils.cpp',
|
||||
'TestGCPostBarriers.cpp',
|
||||
'TestThreadUtils.cpp',
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES = [
|
||||
|
Loading…
Reference in New Issue
Block a user