Commit 6d3e41e9 authored by Hugo Beauzée-Luyssen's avatar Hugo Beauzée-Luyssen

EventManager: Accept forward references to perfect forward the event handler

parent 2cb7083c
...@@ -34,6 +34,8 @@ ...@@ -34,6 +34,8 @@
#include <memory> #include <memory>
#include <atomic> #include <atomic>
#define EXPECT_SIGNATURE(sig) static_assert(signature_match<decltype(f), sig>::value, "Expected a function with prototype " #sig)
namespace VLC namespace VLC
{ {
...@@ -50,6 +52,26 @@ using EventToken = unsigned int; ...@@ -50,6 +52,26 @@ using EventToken = unsigned int;
*/ */
class EventManager : public Internal<libvlc_event_manager_t> class EventManager : public Internal<libvlc_event_manager_t>
{ {
protected:
template <typename T>
using Decay = typename std::decay<T>::type;
template <typename T>
using DecayPtr = typename std::add_pointer<typename std::decay<T>::type>::type;
template <typename, typename, typename = void>
struct signature_match : std::false_type {};
template <typename Func, typename Ret, typename... Args>
struct signature_match<Func, Ret(Args...),
typename std::enable_if<
std::is_convertible<
decltype(std::declval<Func>()(std::declval<Args>()...)),
Ret
>::value
>::type
> : std::true_type {};
private: private:
// Polymorphic base to hold a templated implementation // Polymorphic base to hold a templated implementation
struct EventHandlerBase struct EventHandlerBase
...@@ -58,13 +80,12 @@ private: ...@@ -58,13 +80,12 @@ private:
virtual ~EventHandlerBase() {} virtual ~EventHandlerBase() {}
}; };
template <typename Ret, typename... Args> template <typename Func>
class EventHandler : public EventHandlerBase class EventHandler : public EventHandlerBase
{ {
public: public:
using UserCallback = std::function<Ret(Args...)>; EventHandler(EventManager& em, libvlc_event_e eventType, Func&& userCallback, Wrapper wrapper)
EventHandler(EventManager& em, libvlc_event_e eventType, UserCallback&& userCallback, Wrapper wrapper) : m_userCallback( std::forward<Func>(userCallback) )
: m_userCallback( userCallback )
, m_eventManager(&em) , m_eventManager(&em)
, m_wrapper(wrapper) , m_wrapper(wrapper)
, m_eventType( eventType ) , m_eventType( eventType )
...@@ -81,7 +102,7 @@ private: ...@@ -81,7 +102,7 @@ private:
EventHandler(const EventHandler&) = delete; EventHandler(const EventHandler&) = delete;
private: private:
UserCallback m_userCallback; Decay<Func> m_userCallback;
// EventManager always outlive EventHandler, no need for smart pointer // EventManager always outlive EventHandler, no need for smart pointer
EventManager* m_eventManager; EventManager* m_eventManager;
Wrapper m_wrapper; Wrapper m_wrapper;
...@@ -95,20 +116,22 @@ protected: ...@@ -95,20 +116,22 @@ protected:
{ {
} }
template <typename Ret, typename... Args> template <typename Func>
EventToken handle(libvlc_event_e eventType, std::function<Ret(Args...)>&& f, EventHandlerBase::Wrapper wrapper) EventToken handle(libvlc_event_e eventType, Func&& f, EventHandlerBase::Wrapper wrapper)
{ {
auto token = ++m_lastEvent; auto token = ++m_lastEvent;
m_lambdas[token] = std::unique_ptr<EventHandlerBase>( new EventHandler<Ret, Args...>( m_lambdas[token] = std::unique_ptr<EventHandlerBase>( new EventHandler<Func>(
*this, eventType, std::move( f ), wrapper ) ); *this, eventType, std::forward<Func>( f ), wrapper ) );
return token; return token;
} }
EventToken handle(libvlc_event_e eventType, std::function<void()>&& f) template <typename Func>
EventToken handle(libvlc_event_e eventType, Func&& f)
{ {
return handle(eventType, std::move( f ), [](const libvlc_event_t*, void* data) EXPECT_SIGNATURE(void());
return handle(eventType, std::forward<Func>( f ), [](const libvlc_event_t*, void* data)
{ {
auto callback = static_cast<std::function<void()>*>( data ); auto callback = static_cast<DecayPtr<Func>>( data );
(*callback)(); (*callback)();
}); });
} }
...@@ -132,65 +155,87 @@ class MediaEventManager : public EventManager ...@@ -132,65 +155,87 @@ class MediaEventManager : public EventManager
public: public:
MediaEventManager(InternalPtr ptr) : EventManager( ptr ) {} MediaEventManager(InternalPtr ptr) : EventManager( ptr ) {}
EventToken onMetaChanged( std::function<void(libvlc_meta_t)>&& f) /**
* @brief onMetaChanged
* @param f A std::function<void(libvlc_meta_t)>
*/
template <typename Func>
EventToken onMetaChanged( Func&& f)
{ {
return handle( libvlc_MediaMetaChanged, std::move( f ), [](const libvlc_event_t* e, void* data) EXPECT_SIGNATURE(void(libvlc_meta_t));
return handle( libvlc_MediaMetaChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
{ {
auto callback = static_cast<std::function<void(libvlc_meta_t)>*>(data); auto callback = static_cast<DecayPtr<Func>>(data);
(*callback)( e->u.media_meta_changed.meta_type ); (*callback)( e->u.media_meta_changed.meta_type );
}); });
} }
EventToken onSubItemAdded( std::function<void(MediaPtr)>&& f ) /**
* @brief onSubItemAdded
* @param f A std::function<void(MediaPtr)>
*/
template <typename Func>
EventToken onSubItemAdded( Func&& f )
{ {
return handle(libvlc_MediaSubItemAdded, std::move( f ), [](const libvlc_event_t* e, void* data) EXPECT_SIGNATURE(void(MediaPtr));
return handle(libvlc_MediaSubItemAdded, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
{ {
auto callback = static_cast<std::function<void(MediaPtr)>*>(data); auto callback = static_cast<DecayPtr<Func>>(data);
(*callback)( std::make_shared<Media>( e->u.media_subitem_added.new_child, true ) ); (*callback)( std::make_shared<Media>( e->u.media_subitem_added.new_child, true ) );
}); });
} }
EventToken onDurationChanged( std::function<void(int64_t)>&& f ) template <typename Func>
EventToken onDurationChanged( Func&& f )
{ {
return handle(libvlc_MediaDurationChanged, std::move( f ), [](const libvlc_event_t* e, void* data) EXPECT_SIGNATURE(void(int64_t));
return handle(libvlc_MediaDurationChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
{ {
auto callback = static_cast<std::function<void(int64_t)>*>(data); auto callback = static_cast<DecayPtr<Func>>(data);
(*callback)( e->u.media_duration_changed.new_duration ); (*callback)( e->u.media_duration_changed.new_duration );
}); });
} }
EventToken onParsedChanged( std::function<void(bool)>&& f ) template <typename Func>
EventToken onParsedChanged( Func&& f )
{ {
return handle( libvlc_MediaParsedChanged, std::move( f ), [](const libvlc_event_t* e, void* data) EXPECT_SIGNATURE(void(bool));
return handle( libvlc_MediaParsedChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
{ {
auto callback = static_cast<std::function<void(bool)>*>(data); auto callback = static_cast<DecayPtr<Func>>(data);
(*callback)( e->u.media_parsed_changed.new_status ); (*callback)( e->u.media_parsed_changed.new_status );
}); });
} }
EventToken onFreed( std::function<void(MediaPtr)>&& f) template <typename Func>
EventToken onFreed( Func&& f)
{ {
return handle(libvlc_MediaFreed, std::move( f ), [](const libvlc_event_t* e, void* data) EXPECT_SIGNATURE(void(MediaPtr));
return handle(libvlc_MediaFreed, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
{ {
auto callback = static_cast<std::function<void(MediaPtr)>*>(data); auto callback = static_cast<DecayPtr<Func>>(data);
(*callback)( std::make_shared<Media>( e->u.media_freed.md, true ) ); (*callback)( std::make_shared<Media>( e->u.media_freed.md, true ) );
}); });
} }
EventToken onStateChanged( std::function<void(libvlc_state_t)>&& f) template <typename Func>
EventToken onStateChanged( Func&& f)
{ {
return handle(libvlc_MediaStateChanged, std::move( f ), [](const libvlc_event_t* e, void* data) EXPECT_SIGNATURE(void(libvlc_state_t));
return handle(libvlc_MediaStateChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
{ {
auto callback = static_cast<std::function<void(libvlc_state_t)>*>(data); auto callback = static_cast<DecayPtr<Func>>(data);
(*callback)( e->u.media_state_changed.new_state ); (*callback)( e->u.media_state_changed.new_state );
}); });
} }
EventToken onSubItemTreeAdded( std::function<void(MediaPtr)>&& f) template <typename Func>
EventToken onSubItemTreeAdded( Func&& f)
{ {
return handle(libvlc_MediaSubItemAdded, std::move( f ), [](const libvlc_event_t* e, void* data) EXPECT_SIGNATURE(void(MediaPtr));
return handle(libvlc_MediaSubItemAdded, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
{ {
auto callback = static_cast<std::function<void(MediaPtr)>*>(data); auto callback = static_cast<DecayPtr<Func>>(data);
(*callback)( std::make_shared<Media>( e->u.media_subitemtree_added.item, true ) ); (*callback)( std::make_shared<Media>( e->u.media_subitemtree_added.item, true ) );
}); });
} }
...@@ -201,168 +246,205 @@ class MediaPlayerEventManager : public EventManager ...@@ -201,168 +246,205 @@ class MediaPlayerEventManager : public EventManager
public: public:
MediaPlayerEventManager(InternalPtr ptr) : EventManager( ptr ) {} MediaPlayerEventManager(InternalPtr ptr) : EventManager( ptr ) {}
EventToken onMediaChanged( std::function<void(MediaPtr)>&& f ) template <typename Func>
EventToken onMediaChanged( Func&& f )
{ {
return handle(libvlc_MediaPlayerMediaChanged, std::move( f ), [](const libvlc_event_t* e, void* data) EXPECT_SIGNATURE(void(MediaPtr));
return handle(libvlc_MediaPlayerMediaChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
{ {
auto callback = static_cast<std::function<void(MediaPtr)>*>( data ); auto callback = static_cast<DecayPtr<Func>>( data );
(*callback)( std::make_shared<Media>( e->u.media_player_media_changed.new_media, true ) ); (*callback)( std::make_shared<Media>( e->u.media_player_media_changed.new_media, true ) );
}); });
} }
EventToken onNothingSpecial(std::function<void()>&& f)
template <typename Func>
EventToken onNothingSpecial( Func&& f )
{ {
return handle(libvlc_MediaPlayerNothingSpecial, std::move( f )); return handle(libvlc_MediaPlayerNothingSpecial, std::forward<Func>( f ));
} }
EventToken onOpening(std::function<void()>&& f) template <typename Func>
EventToken onOpening( Func&& f )
{ {
return handle(libvlc_MediaPlayerOpening, std::move( f ) ); return handle(libvlc_MediaPlayerOpening, std::forward<Func>( f ) );
} }
EventToken onBuffering( std::function<void()>&& f) template <typename Func>
EventToken onBuffering( Func&& f )
{ {
return handle(libvlc_MediaPlayerBuffering, std::move( f ) ); return handle(libvlc_MediaPlayerBuffering, std::forward<Func>( f ) );
} }
EventToken onPlaying(std::function<void()>&& f) template <typename Func>
EventToken onPlaying( Func&& f )
{ {
return handle( libvlc_MediaPlayerPlaying, std::move( f ) ); return handle( libvlc_MediaPlayerPlaying, std::forward<Func>( f ) );
} }
EventToken onPaused(std::function<void()>&& f) template <typename Func>
EventToken onPaused(Func&& f)
{ {
return handle( libvlc_MediaPlayerPaused, std::move( f ) ); return handle( libvlc_MediaPlayerPaused, std::forward<Func>( f ) );
} }
EventToken onStopped(std::function<void()>&& f) template <typename Func>
EventToken onStopped(Func&& f)
{ {
return handle( libvlc_MediaPlayerStopped, std::move( f ) ); return handle( libvlc_MediaPlayerStopped, std::forward<Func>( f ) );
} }
EventToken onForward(std::function<void()>&& f) template <typename Func>
EventToken onForward(Func&& f)
{ {
return handle( libvlc_MediaPlayerForward, std::move( f ) ); return handle( libvlc_MediaPlayerForward, std::forward<Func>( f ) );
} }
EventToken onBackward(std::function<void()>&& f) template <typename Func>
EventToken onBackward(Func&& f)
{ {
return handle( libvlc_MediaPlayerBackward, std::move( f ) ); return handle( libvlc_MediaPlayerBackward, std::forward<Func>( f ) );
} }
EventToken onEndReached(std::function<void()>&& f) template <typename Func>
EventToken onEndReached(Func&& f)
{ {
return handle( libvlc_MediaPlayerEndReached, std::move( f ) ); return handle( libvlc_MediaPlayerEndReached, std::forward<Func>( f ) );
} }
EventToken onEncounteredError(std::function<void()>&& f) template <typename Func>
EventToken onEncounteredError(Func&& f)
{ {
return handle( libvlc_MediaPlayerEncounteredError, std::move( f ) ); return handle( libvlc_MediaPlayerEncounteredError, std::forward<Func>( f ) );
} }
EventToken onTimeChanged( std::function<void(libvlc_time_t)>&& f ) template <typename Func>
EventToken onTimeChanged( Func&& f )
{ {
return handle( libvlc_MediaPlayerTimeChanged, std::move( f ), [](const libvlc_event_t* e, void* data) EXPECT_SIGNATURE(void(libvlc_time_t));
return handle( libvlc_MediaPlayerTimeChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
{ {
auto callback = static_cast<std::function<void(libvlc_time_t)>*>( data ); auto callback = static_cast<DecayPtr<Func>>( data );
(*callback)( e->u.media_player_time_changed.new_time ); (*callback)( e->u.media_player_time_changed.new_time );
}); });
} }
EventToken onPositionChanged( std::function<void(float)>&& f ) template <typename Func>
EventToken onPositionChanged( Func&& f )
{ {
return handle( libvlc_MediaPlayerPositionChanged, std::move( f ), [](const libvlc_event_t* e, void* data) EXPECT_SIGNATURE(void(float));
return handle( libvlc_MediaPlayerPositionChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
{ {
auto callback = static_cast<std::function<void(float)>*>( data ); auto callback = static_cast<DecayPtr<Func>>( data );
(*callback)( e->u.media_player_position_changed.new_position ); (*callback)( e->u.media_player_position_changed.new_position );
}); });
} }
EventToken onSeekableChanged( std::function<void(bool)>&& f ) template <typename Func>
EventToken onSeekableChanged( Func&& f )
{ {
return handle( libvlc_MediaPlayerSeekableChanged, std::move( f ), [](const libvlc_event_t* e, void* data) EXPECT_SIGNATURE(void(bool));
return handle( libvlc_MediaPlayerSeekableChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
{ {
auto callback = static_cast<std::function<void(bool)>*>( data ); auto callback = static_cast<DecayPtr<Func>>( data );
(*callback)( e->u.media_player_seekable_changed.new_seekable ); (*callback)( e->u.media_player_seekable_changed.new_seekable );
}); });
} }
EventToken onPausableChanged( std::function<void(bool)>&& f ) template <typename Func>
EventToken onPausableChanged( Func&& f )
{ {
return handle( libvlc_MediaPlayerSeekableChanged, std::move( f ), [](const libvlc_event_t* e, void* data) EXPECT_SIGNATURE(void(bool));
return handle( libvlc_MediaPlayerSeekableChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
{ {
auto callback = static_cast<std::function<void(bool)>*>( data ); auto callback = static_cast<DecayPtr<Func>>( data );
(*callback)( e->u.media_player_seekable_changed.new_seekable ); (*callback)( e->u.media_player_seekable_changed.new_seekable );
}); });
} }
EventToken onTitleChanged( std::function<void(int)>&& f ) template <typename Func>
EventToken onTitleChanged( Func&& f )
{ {
return handle( libvlc_MediaPlayerTitleChanged, std::move( f ), [](const libvlc_event_t* e, void* data) EXPECT_SIGNATURE(void(int));
return handle( libvlc_MediaPlayerTitleChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
{ {
auto callback = static_cast<std::function<void(int)>*>( data ); auto callback = static_cast<DecayPtr<Func>>( data );
(*callback)( e->u.media_player_title_changed.new_title ); (*callback)( e->u.media_player_title_changed.new_title );
}); });
} }
EventToken onSnapshotTaken( std::function<void(std::string)>&& f ) template <typename Func>
EventToken onSnapshotTaken( Func&& f )
{ {
return handle( libvlc_MediaPlayerSnapshotTaken, std::move( f ), [](const libvlc_event_t* e, void* data) EXPECT_SIGNATURE(void(std::string));
return handle( libvlc_MediaPlayerSnapshotTaken, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
{ {
auto callback = static_cast<std::function<void(std::string)>*>( data ); auto callback = static_cast<DecayPtr<Func>>( data );
(*callback)( e->u.media_player_snapshot_taken.psz_filename ); (*callback)( e->u.media_player_snapshot_taken.psz_filename );
}); });
} }
EventToken onLengthChanged( std::function<void(libvlc_time_t)>&& f ) template <typename Func>
EventToken onLengthChanged( Func&& f )
{ {
return handle( libvlc_MediaPlayerLengthChanged, std::move( f ), [](const libvlc_event_t* e, void* data) EXPECT_SIGNATURE(void(libvlc_time_t));
return handle( libvlc_MediaPlayerLengthChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
{ {
auto callback = static_cast<std::function<void(libvlc_time_t)>*>( data ); auto callback = static_cast<DecayPtr<Func>>( data );
(*callback)( e->u.media_player_length_changed.new_length ); (*callback)( e->u.media_player_length_changed.new_length );
}); });
} }
EventToken onVout( std::function<void(int)>&& f ) template <typename Func>
EventToken onVout( Func&& f )
{ {
return handle( libvlc_MediaPlayerVout, std::move( f ), [](const libvlc_event_t* e, void* data) EXPECT_SIGNATURE(void(int));
return handle( libvlc_MediaPlayerVout, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
{ {
auto callback = static_cast<std::function<void(int)>*>( data ); auto callback = static_cast<DecayPtr<Func>>( data );
(*callback)( e->u.media_player_vout.new_count ); (*callback)( e->u.media_player_vout.new_count );
}); });
} }
EventToken onScrambledChanged( std::function<void(int)>&& f ) template <typename Func>
EventToken onScrambledChanged( Func&& f )
{ {
return handle( libvlc_MediaPlayerScrambledChanged, std::move( f ), [](const libvlc_event_t* e, void* data) EXPECT_SIGNATURE(void(int));
return handle( libvlc_MediaPlayerScrambledChanged, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
{ {
auto callback = static_cast<std::function<void(int)>*>( data ); auto callback = static_cast<DecayPtr<Func>>( data );
(*callback)( e->u.media_player_scrambled_changed.new_scrambled ); (*callback)( e->u.media_player_scrambled_changed.new_scrambled );
}); });
} }
EventToken onESAdded( std::function<void(libvlc_track_type_t, int)>&& f ) template <typename Func>
EventToken onESAdded( Func&& f )
{ {
return handle( libvlc_MediaPlayerESAdded, std::move( f ), [](const libvlc_event_t* e, void* data) EXPECT_SIGNATURE(void(libvlc_track_type_t, int));
return handle( libvlc_MediaPlayerESAdded, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
{ {
auto callback = static_cast<std::function<void(libvlc_track_type_t, int)>*>( data ); auto callback = static_cast<DecayPtr<Func>>( data );
(*callback)( e->u.media_player_es_changed.i_type, e->u.media_player_es_changed.i_id ); (*callback)( e->u.media_player_es_changed.i_type, e->u.media_player_es_changed.i_id );
}); });
} }
EventToken onESDeleted( std::function<void(libvlc_track_type_t, int)>&& f ) template <typename Func>
EventToken onESDeleted( Func&& f )
{ {
return handle( libvlc_MediaPlayerESDeleted, std::move( f ), [](const libvlc_event_t* e, void* data) EXPECT_SIGNATURE(void(libvlc_track_type_t, int));
return handle( libvlc_MediaPlayerESDeleted, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
{ {
auto callback = static_cast<std::function<void(libvlc_track_type_t, int)>*>( data ); auto callback = static_cast<DecayPtr<Func>>( data );
(*callback)( e->u.media_player_es_changed.i_type, e->u.media_player_es_changed.i_id ); (*callback)( e->u.media_player_es_changed.i_type, e->u.media_player_es_changed.i_id );
}); });
} }
EventToken onESSelected( std::function<void(libvlc_track_type_t, int)>&& f ) template <typename Func>
EventToken onESSelected( Func&& f )
{ {
return handle( libvlc_MediaPlayerESSelected, std::move( f ), [](const libvlc_event_t* e, void* data) EXPECT_SIGNATURE(void(libvlc_track_type_t, int));
return handle( libvlc_MediaPlayerESSelected, std::forward<Func>( f ), [](const libvlc_event_t* e, void* data)
{ {
auto callback = static_cast<std::function<void(libvlc_track_type_t, int)>*>( data ); auto callback = static_cast<DecayPtr<Func