Imported Upstream version 1.49.0
[platform/upstream/boost.git] / boost / signals2 / connection.hpp
1 /*
2   boost::signals2::connection provides a handle to a signal/slot connection.
3
4   Author: Frank Mori Hess <fmhess@users.sourceforge.net>
5   Begin: 2007-01-23
6 */
7 // Copyright Frank Mori Hess 2007-2008.
8 // Distributed under the Boost Software License, Version
9 // 1.0. (See accompanying file LICENSE_1_0.txt or copy at
10 // http://www.boost.org/LICENSE_1_0.txt)
11
12 // See http://www.boost.org/libs/signals2 for library home page.
13
14 #ifndef BOOST_SIGNALS2_CONNECTION_HPP
15 #define BOOST_SIGNALS2_CONNECTION_HPP
16
17 #include <boost/function.hpp>
18 #include <boost/mpl/bool.hpp>
19 #include <boost/noncopyable.hpp>
20 #include <boost/shared_ptr.hpp>
21 #include <boost/signals2/detail/null_output_iterator.hpp>
22 #include <boost/signals2/detail/unique_lock.hpp>
23 #include <boost/signals2/slot.hpp>
24 #include <boost/weak_ptr.hpp>
25
26 namespace boost
27 {
28   namespace signals2
29   {
30     extern inline void null_deleter(const void*) {}
31     namespace detail
32     {
33       class connection_body_base
34       {
35       public:
36         connection_body_base():
37           _connected(true)
38         {
39         }
40         virtual ~connection_body_base() {}
41         void disconnect()
42         {
43           unique_lock<connection_body_base> local_lock(*this);
44           nolock_disconnect();
45         }
46         void nolock_disconnect()
47         {
48           _connected = false;
49         }
50         virtual bool connected() const = 0;
51         shared_ptr<void> get_blocker()
52         {
53           unique_lock<connection_body_base> local_lock(*this);
54           shared_ptr<void> blocker = _weak_blocker.lock();
55           if(blocker == shared_ptr<void>())
56           {
57             blocker.reset(this, &null_deleter);
58             _weak_blocker = blocker;
59           }
60           return blocker;
61         }
62         bool blocked() const
63         {
64           return !_weak_blocker.expired();
65         }
66         bool nolock_nograb_blocked() const
67         {
68           return nolock_nograb_connected() == false || blocked();
69         }
70         bool nolock_nograb_connected() const {return _connected;}
71         // expose part of Lockable concept of mutex
72         virtual void lock() = 0;
73         virtual void unlock() = 0;
74
75       protected:
76
77         mutable bool _connected;
78         weak_ptr<void> _weak_blocker;
79       };
80
81       template<typename GroupKey, typename SlotType, typename Mutex>
82       class connection_body: public connection_body_base
83       {
84       public:
85         typedef Mutex mutex_type;
86         connection_body(const SlotType &slot_in):
87           slot(slot_in)
88         {
89         }
90         virtual ~connection_body() {}
91         virtual bool connected() const
92         {
93           unique_lock<mutex_type> local_lock(_mutex);
94           nolock_grab_tracked_objects(detail::null_output_iterator());
95           return nolock_nograb_connected();
96         }
97         const GroupKey& group_key() const {return _group_key;}
98         void set_group_key(const GroupKey &key) {_group_key = key;}
99         bool nolock_slot_expired() const
100         {
101           bool expired = slot.expired();
102           if(expired == true)
103           {
104             _connected = false;
105           }
106           return expired;
107         }
108         template<typename OutputIterator>
109           void nolock_grab_tracked_objects(OutputIterator inserter) const
110         {
111           slot_base::tracked_container_type::const_iterator it;
112           for(it = slot.tracked_objects().begin();
113             it != slot.tracked_objects().end();
114             ++it)
115           {
116             void_shared_ptr_variant locked_object
117             (
118               apply_visitor
119               (
120                 detail::lock_weak_ptr_visitor(),
121                 *it
122               )
123             );
124             if(apply_visitor(detail::expired_weak_ptr_visitor(), *it))
125             {
126               _connected = false;
127               return;
128             }
129             *inserter++ = locked_object;
130           }
131         }
132         // expose Lockable concept of mutex
133         virtual void lock()
134         {
135           _mutex.lock();
136         }
137         virtual void unlock()
138         {
139           _mutex.unlock();
140         }
141         SlotType slot;
142       private:
143         mutable mutex_type _mutex;
144         GroupKey _group_key;
145       };
146     }
147
148     class shared_connection_block;
149
150     class connection
151     {
152     public:
153       friend class shared_connection_block;
154
155       connection() {}
156       connection(const connection &other): _weak_connection_body(other._weak_connection_body)
157       {}
158       connection(const boost::weak_ptr<detail::connection_body_base> &connectionBody):
159         _weak_connection_body(connectionBody)
160       {}
161       ~connection() {}
162       void disconnect() const
163       {
164         boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock());
165         if(connectionBody == 0) return;
166         connectionBody->disconnect();
167       }
168       bool connected() const
169       {
170         boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock());
171         if(connectionBody == 0) return false;
172         return connectionBody->connected();
173       }
174       bool blocked() const
175       {
176         boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock());
177         if(connectionBody == 0) return true;
178         return connectionBody->blocked();
179       }
180       bool operator==(const connection& other) const
181       {
182         boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock());
183         boost::shared_ptr<detail::connection_body_base> otherConnectionBody(other._weak_connection_body.lock());
184         return connectionBody == otherConnectionBody;
185       }
186       bool operator!=(const connection& other) const
187       {
188         return !(*this == other);
189       }
190       bool operator<(const connection& other) const
191       {
192         boost::shared_ptr<detail::connection_body_base> connectionBody(_weak_connection_body.lock());
193         boost::shared_ptr<detail::connection_body_base> otherConnectionBody(other._weak_connection_body.lock());
194         return connectionBody < otherConnectionBody;
195       }
196       void swap(connection &other)
197       {
198         using std::swap;
199         swap(_weak_connection_body, other._weak_connection_body);
200       }
201     protected:
202
203       boost::weak_ptr<detail::connection_body_base> _weak_connection_body;
204     };
205     inline void swap(connection &conn1, connection &conn2)
206     {
207       conn1.swap(conn2);
208     }
209
210     class scoped_connection: public connection
211     {
212     public:
213       scoped_connection() {}
214       scoped_connection(const connection &other):
215         connection(other)
216       {}
217       ~scoped_connection()
218       {
219         disconnect();
220       }
221       scoped_connection& operator=(const connection &rhs)
222       {
223         disconnect();
224         connection::operator=(rhs);
225         return *this;
226       }
227       connection release()
228       {
229         connection conn(_weak_connection_body);
230         _weak_connection_body.reset();
231         return conn;
232       }
233     private:
234       scoped_connection(const scoped_connection &other);
235       scoped_connection& operator=(const scoped_connection &rhs);
236     };
237     // Sun 5.9 compiler doesn't find the swap for base connection class when
238     // arguments are scoped_connection, so we provide this explicitly.
239     inline void swap(scoped_connection &conn1, scoped_connection &conn2)
240     {
241       conn1.swap(conn2);
242     }
243   }
244 }
245
246 #endif  // BOOST_SIGNALS2_CONNECTION_HPP