From 1b22c5e8ce87ddbd9a349632355b2a552e7521e0 Mon Sep 17 00:00:00 2001 From: JW Wang Date: Tue, 18 Aug 2015 11:11:53 +0800 Subject: [PATCH] Bug 1194112. Part 4 - reimplement Listener/ListenerImpl to support Move. r=kinetik. --- dom/media/MediaEventSource.h | 124 +++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/dom/media/MediaEventSource.h b/dom/media/MediaEventSource.h index 33d12f17918c..67d695c3f307 100644 --- a/dom/media/MediaEventSource.h +++ b/dom/media/MediaEventSource.h @@ -190,6 +190,124 @@ private: Function mFunction; }; +/** + * Define whether an event data should be copied or moved to the listeners. + * + * @Copy Data will always be copied. Each listener gets a copy. + * @Move Data will always be moved. + * @Both Data will be moved when possible or copied when necessary. + */ +enum class EventPassMode : int8_t { + Copy, + Move, + Both +}; + +class ListenerBase { +public: + ListenerBase() : mToken(new RevocableToken()) {} + ~ListenerBase() { + MOZ_ASSERT(Token()->IsRevoked(), "Must disconnect the listener."); + } + RevocableToken* Token() const { + return mToken; + } +private: + const nsRefPtr mToken; +}; + +/** + * Stored by MediaEventSource to send notifications to the listener. + * Since virtual methods can not be templated, this class is specialized + * to provide different Dispatch() overloads depending on EventPassMode. + */ +template +class Listener : public ListenerBase { +public: + virtual ~Listener() {} + virtual void Dispatch(const ArgType& aEvent) = 0; +}; + +template +class Listener : public ListenerBase { +public: + virtual ~Listener() {} + virtual void Dispatch(const ArgType& aEvent) = 0; + virtual void Dispatch(ArgType&& aEvent) = 0; +}; + +template +class Listener : public ListenerBase { +public: + virtual ~Listener() {} + virtual void Dispatch(ArgType&& aEvent) = 0; +}; + +/** + * Store the registered target thread and function so it knows where and to + * whom to send the event data. + */ +template +class ListenerImpl : public Listener { +public: + ListenerImpl(Target* aTarget, const Function& aFunction) + : mHelper(ListenerBase::Token(), aTarget, aFunction) {} + void Dispatch(const ArgType& aEvent) override { + mHelper.Dispatch(aEvent); + } +private: + ListenerHelper mHelper; +}; + +template +class ListenerImpl + : public Listener { +public: + ListenerImpl(Target* aTarget, const Function& aFunction) + : mHelper(ListenerBase::Token(), aTarget, aFunction) {} + void Dispatch(const ArgType& aEvent) override { + mHelper.Dispatch(aEvent); + } + void Dispatch(ArgType&& aEvent) override { + mHelper.Dispatch(Move(aEvent)); + } +private: + ListenerHelper mHelper; +}; + +template +class ListenerImpl + : public Listener { +public: + ListenerImpl(Target* aTarget, const Function& aFunction) + : mHelper(ListenerBase::Token(), aTarget, aFunction) {} + void Dispatch(ArgType&& aEvent) override { + mHelper.Dispatch(Move(aEvent)); + } +private: + ListenerHelper mHelper; +}; + +/** + * Select EventPassMode based on ListenerMode and if the type is copyable. + * + * @Copy Selected when ListenerMode is NonExclusive because each listener + * must get a copy. + * + * @Move Selected when ListenerMode is Exclusive and the type is move-only. + * + * @Both Selected when ListenerMode is Exclusive and the type is copyable. + * The data will be moved when possible and copied when necessary. + */ +template +struct PassModePicker { + // TODO: pick EventPassMode::Both when we can detect if a type is + // copy-constructible to allow copy-only types in Exclusive mode. + static const EventPassMode Value = + Mode == ListenerMode::NonExclusive ? + EventPassMode::Copy : EventPassMode::Move; +}; + } // namespace detail template class MediaEventSource; @@ -239,6 +357,12 @@ template class MediaEventSource { static_assert(!IsReference::value, "Ref-type not supported!"); typedef typename detail::EventTypeTraits::ArgType ArgType; + static const detail::EventPassMode PassMode + = detail::PassModePicker::Value; + typedef detail::Listener Listener; + + template + using ListenerImpl = detail::ListenerImpl; template using TakeArgs = detail::TakeArgs;