/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Thomas Voß */ #ifndef COM_UBUNTU_CONNECTION_H_ #define COM_UBUNTU_CONNECTION_H_ #include #include #include namespace core { class ScopedConnection; /** * @brief The Connection class models a signal-slot connection. */ class Connection { public: typedef std::function&)> Dispatcher; /** * @brief Checks if this instance corresponds to an active signal-slot connection. * @return true iff the instance corresponds to an active signal-slot connection. */ inline bool is_connected() const { if (!d) return false; return (d->disconnector ? true : false); } /** * @brief End a signal-slot connection. */ inline void disconnect() { if (d) d->disconnect(); } /** * @brief Installs a dispatcher for this signal-slot connection. * @param dispatcher The dispatcher to be used for signal emissions. */ inline void dispatch_via(const Dispatcher& dispatcher) { if (d && d->dispatcher_installer) d->dispatcher_installer(dispatcher); } private: friend class ScopedConnection; typedef std::function Disconnector; typedef std::function DispatcherInstaller; template friend class Signal; inline Connection(const Disconnector& disconnector, const DispatcherInstaller& installer) : d(std::make_shared(disconnector, installer)) { } inline bool operator<(const Connection& rhs) const { return d < rhs.d; } inline void reset() { if (d) d->reset(); } struct Private { Private(const Connection::Disconnector& disconnector, const Connection::DispatcherInstaller& dispatcher_installer) : disconnector(disconnector), dispatcher_installer(dispatcher_installer) { } inline void reset() { std::lock_guard lg(guard); reset_locked(); } inline void reset_locked() { static const Connection::Disconnector empty_disconnector{}; static const Connection::DispatcherInstaller empty_dispatcher_installer{}; disconnector = empty_disconnector; dispatcher_installer = empty_dispatcher_installer; } inline void disconnect() { static const Connection::Disconnector empty_disconnector{}; std::lock_guard lg(guard); if (disconnector) disconnector(); reset_locked(); } std::mutex guard; Connection::Disconnector disconnector; Connection::DispatcherInstaller dispatcher_installer; }; // The whole class is implicitly shared and we thus forward our complete // shared state to a private structure that is lifetime-managed by a shared_ptr. std::shared_ptr d; }; /** * @brief Scoped helper class to map signal-slot connection mgmt. to RAII. */ class ScopedConnection { public: /** * @brief Constructs an instance for an existing signal-slot connection. * @param c The existing signal-slot connection. */ inline ScopedConnection(const Connection& c) : connection(c) { } inline ScopedConnection(ScopedConnection&& rhs) : connection(std::move(rhs.connection)) { } ScopedConnection(const ScopedConnection&) = delete; /** * @brief Disconnects the signal-slot connection. */ inline ~ScopedConnection() noexcept(true) { try { connection.disconnect(); } catch(...) { } } inline ScopedConnection& operator=(ScopedConnection&& rhs) { connection = std::move(rhs.connection); return *this; } ScopedConnection& operator=(const ScopedConnection&) = delete; bool operator==(const ScopedConnection&) = delete; inline bool operator<(const ScopedConnection& rhs) const { return connection < rhs.connection; } private: Connection connection; }; } #endif // COM_UBUNTU_CONNECTION_H_