]> git.lyx.org Git - lyx.git/blob - boost/boost/signals/connection.hpp
c-assert expects an int, so don't pass it a pointer.
[lyx.git] / boost / boost / signals / connection.hpp
1 // Boost.Signals library
2 //
3 // Copyright (C) 2001 Doug Gregor (gregod@cs.rpi.edu)
4 //
5 // Permission to copy, use, sell and distribute this software is granted
6 // provided this copyright notice appears in all copies.
7 // Permission to modify the code and to distribute modified code is granted
8 // provided this copyright notice appears in all copies, and a notice
9 // that the code was modified is included with the copyright notice.
10 //
11 // This software is provided "as is" without express or implied warranty,
12 // and with no claim as to its suitability for any purpose.
13  
14 // For more information, see http://www.boost.org
15
16 #ifndef BOOST_SIGNALS_CONNECTION_HPP
17 #define BOOST_SIGNALS_CONNECTION_HPP
18
19 #include <boost/signals/detail/signals_common.hpp>
20 #include <boost/smart_ptr.hpp>
21 #include <boost/operators.hpp>
22 #include <boost/any.hpp>
23 #include <list>
24 #include <cassert>
25 #include <utility>
26
27 namespace boost {
28   namespace signals {
29     class trackable;
30
31     namespace detail {
32       // Represents an object that has been bound as part of a slot, and how
33       // to notify that object of a disconnect
34       struct bound_object {
35         void* obj;
36         void* data;
37         void (*disconnect)(void*, void*);
38
39         bool operator==(const bound_object& other) const
40           { return obj == other.obj && data == other.data; }
41         bool operator<(const bound_object& other) const 
42           { return obj < other.obj; }
43       };
44       
45       // Describes the connection between a signal and the objects that are
46       // bound for a specific slot. Enables notification of the signal and the
47       // slots when a disconnect is requested.
48       struct basic_connection {
49         void* signal;
50         void* signal_data;
51         void (*signal_disconnect)(void*, void*);
52         
53         std::list<bound_object> bound_objects;
54       };
55     } // end namespace detail
56
57     // The user may freely pass around the "connection" object and terminate
58     // the connection at any time using disconnect().
59     class connection : 
60       private less_than_comparable1<connection>,
61       private equality_comparable1<connection>
62     {
63     public:
64       connection();
65       connection(const connection&);
66       ~connection();
67
68       // Disconnect the signal and slot, if they are connected
69       void disconnect() const;
70
71       // Returns true if the signal and slot are connected
72       bool connected() const { return con.get() && con->signal_disconnect; }
73
74       // Comparison of connections
75       inline bool operator==(const connection& other) const;
76       inline bool operator<(const connection& other) const;
77
78       // Connection assignment
79       connection& operator=(const connection& other) ;
80
81       // Swap connections
82       inline void swap(connection& other);
83
84     public: // TBD: CHANGE THIS
85       // Set whether this connection object is controlling or not
86       void set_controlling() { controlling_connection = true; }
87
88     private:
89       friend class detail::signal_base_impl;
90       friend class detail::slot_base;
91       friend class trackable;
92
93       // Reset this connection to refer to a different actual connection
94       void reset(signals::detail::basic_connection*);
95
96       // Add a bound object to this connection (not for users)
97       void add_bound_object(const signals::detail::bound_object& b);
98
99       friend class signals::detail::bound_objects_visitor;
100
101       // Pointer to the actual contents of the connection
102       shared_ptr<signals::detail::basic_connection> con;
103
104       // True if the destruction of this connection object should disconnect
105       bool controlling_connection;
106     };
107
108     // Similar to connection, but will disconnect the connection when it is
109     // destroyed unless release() has been called.
110     class scoped_connection : public connection {
111     public:
112       scoped_connection() : connection(), released(false) {}
113       scoped_connection(const connection&);
114       scoped_connection(const scoped_connection&);
115       ~scoped_connection();
116
117       connection release();
118
119       void swap(scoped_connection&);
120
121       scoped_connection& operator=(const connection&);
122       scoped_connection& operator=(const scoped_connection&);
123
124     private:
125       bool released;
126     };
127
128     inline connection::connection() :
129       con(), controlling_connection(false)
130     {
131     }
132
133     inline connection::connection(const connection& other) :
134       con(other.con), controlling_connection(other.controlling_connection) 
135     {
136     }
137
138     inline connection::~connection()
139     {
140       if (controlling_connection) {
141         disconnect();
142       }
143     }
144
145     inline void 
146     connection::reset(signals::detail::basic_connection* new_con)
147     {
148       con.reset(new_con);
149     }
150
151     inline void 
152     connection::add_bound_object(const signals::detail::bound_object& b)
153     {
154       // c-assert expects an int, so don't pass it a pointer
155       assert(con.get() != 0);
156       con->bound_objects.push_back(b);
157     }
158
159     inline bool connection::operator==(const connection& other) const
160     {
161       return con.get() == other.con.get();
162     }
163
164     inline bool connection::operator<(const connection& other) const
165     {
166       return con.get() < other.con.get();
167     }
168
169     inline connection& connection::operator=(const connection& other)
170     { 
171       connection(other).swap(*this);
172       return *this;
173     }
174
175     inline void connection::swap(connection& other)
176     {
177       this->con.swap(other.con);
178       std::swap(this->controlling_connection, other.controlling_connection);
179     }
180
181     inline void swap(connection& c1, connection& c2)
182     {
183       c1.swap(c2);
184     }
185
186     inline scoped_connection::scoped_connection(const connection& other) :
187       connection(other),
188       released(false)
189     {
190     }
191
192     inline 
193     scoped_connection::scoped_connection(const scoped_connection& other) :
194       connection(other),
195       released(other.released)
196     {
197     }
198
199     inline scoped_connection::~scoped_connection()
200     {
201       if (!released) {
202         this->disconnect();
203       }
204     }
205
206     inline connection scoped_connection::release()
207     {
208       released = true;
209       return *this;
210     }
211
212     inline void scoped_connection::swap(scoped_connection& other)
213     {
214       this->connection::swap(other);
215       bool other_released = other.released;
216       other.released = this->released;
217       this->released = other_released;
218     }
219
220     inline void swap(scoped_connection& c1, scoped_connection& c2)
221     {
222       c1.swap(c2);
223     }
224
225     inline scoped_connection& 
226     scoped_connection::operator=(const connection& other)
227     {
228       scoped_connection(other).swap(*this);
229       return *this;
230     }
231
232     inline scoped_connection& 
233     scoped_connection::operator=(const scoped_connection& other)
234     {
235       scoped_connection(other).swap(*this);
236       return *this;
237     }
238
239     namespace detail {
240       struct connection_slot_pair {
241         connection first;
242         any second;
243
244         connection_slot_pair() {}
245
246         connection_slot_pair(const connection& c, const any& a) 
247           : first(c), second(a) 
248         {
249         }
250
251         // Dummys to allow explicit instantiation to work
252         bool operator==(const connection_slot_pair&) const { return false; }
253         bool operator<(const connection_slot_pair&) const { return false;} 
254       };
255       
256       // Determines if the underlying connection is disconnected
257       struct is_disconnected {
258         typedef std::pair<const any, connection_slot_pair> argument_type;
259         typedef bool result_type;
260
261         inline bool operator()(const argument_type& c) const
262         {
263           return !c.second.first.connected();
264         }
265       };
266
267       // Autodisconnects the bound object when it is destroyed unless the
268       // release method is invoked.
269       class auto_disconnect_bound_object {
270       public:
271         auto_disconnect_bound_object(const bound_object& b) : 
272           binding(b), auto_disconnect(true)
273         {
274         }
275
276         ~auto_disconnect_bound_object()
277         {
278           if (auto_disconnect)
279             binding.disconnect(binding.obj, binding.data);
280         }
281
282         void release() { auto_disconnect = false; }
283
284       private:
285         bound_object binding;
286         bool auto_disconnect;
287       };
288     } // end namespace detail
289   } // end namespace signals
290 } // end namespace boost
291
292 #endif // BOOST_SIGNALS_CONNECTION_HPP