1 /// \file
2 /// \brief Contains the definition of the Sharedd_connection_block class.
3 #ifndef SHARED_CONNECTION_BLOCK_HPP
4 #define SHARED_CONNECTION_BLOCK_HPP
5 #include <signals/connection.hpp>
6 
7 #include <memory>
8 
9 namespace sig {
10 class Connection_impl_base;
11 
12 /// \brief Blocks a Signal/Slot Connection.
13 ///
14 /// Any number of Shared_connection_blocks can be built on a single connection,
15 /// when the last block goes out of scope, the connection is unblocked.
16 class Shared_connection_block {
17    public:
18     /// \brief Create a Shared_connection_block from a Connection and a boolean.
19     ///
20     /// Default constructs to blocking an empty Connection.
21     /// \param conn The Connection to be blocked by *this.
22     /// \param initially_block If true, *this blocks the Connection, otherwise
23     /// *this only holds a reference to the Connection and can block the
24     /// Connection at some other time by calling block().
Shared_connection_block(const Connection & conn=Connection{},bool initially_block=true)25     explicit Shared_connection_block(const Connection& conn = Connection{},
26                                      bool initially_block = true)
27         : connection_{conn.pimpl_}, blocking_{initially_block} {
28         if (this->active()) {
29             connection_.lock()->add_block();
30         }
31     }
32 
33     /// \brief Creates a copy of \p x, increasing the block count on the
34     /// Connection if \p x is blocking.
Shared_connection_block(const Shared_connection_block & x)35     Shared_connection_block(const Shared_connection_block& x)
36         : connection_{x.connection_}, blocking_{x.blocking_} {
37         if (this->active()) {
38             connection_.lock()->add_block();
39         }
40     }
41 
42     /// \brief Reset *this' Connection to point to \p x's Connection.
43     ///
44     /// If *this was blocking, then the block count is decremented on the
45     /// original Connection. If \p x is blocking, then \p x's Connection gets
46     /// an additional block.
operator =(const Shared_connection_block & x)47     Shared_connection_block& operator=(const Shared_connection_block& x) {
48         if (this == &x) {
49             return *this;
50         }
51         this->reset(x);
52         return *this;
53     }
54 
55     /// \brief Releases this block from the Connection.
56     ///
57     /// Connection may still be blocked by other Shared_connection_block
58     /// objects.
~Shared_connection_block()59     ~Shared_connection_block() { this->unblock(); }
60 
61     /// Releases the Connection block. No-op if not currently blocking.
unblock()62     void unblock() {
63         if (this->active()) {
64             connection_.lock()->remove_block();
65             blocking_ = false;
66         }
67     }
68 
69     /// Reasserts a block on a Connection. No-op if currently blocking.
block()70     void block() {
71         if (!connection_.expired() && !blocking_) {
72             connection_.lock()->add_block();
73             blocking_ = true;
74         }
75     }
76 
77     /// \returns True if *this is currently blocking a Connection, else false.
blocking() const78     bool blocking() const { return !connection_.expired() && blocking_; }
79 
80     /// \returns The Connection object associated with *this.
connection() const81     Connection connection() const { return Connection(connection_); }
82 
83    private:
84     // Remove the block to the associated Connection and reset with the contents
85     // of \p x, applying a block to the new Connection if x is blocking.
reset(const Shared_connection_block & x)86     void reset(const Shared_connection_block& x) {
87         this->unblock();
88         connection_ = x.connection_;
89         blocking_ = x.blocking_;
90         if (this->active()) {
91             connection_.lock()->add_block();
92         }
93     }
94 
95     // Return true if the connection pointed to is still alive and *this is
96     // currently blocking.
active()97     bool active() { return !connection_.expired() && blocking_; }
98 
99     std::weak_ptr<Connection_impl_base> connection_;
100     bool blocking_;
101 };
102 
103 }  // namespace sig
104 #endif  // SHARED_CONNECTION_BLOCK_HPP
105