connect 过程中 slot 的连接
template<
typename R,
typename T1, typename T2
,
typename Combiner,
typename Group,
typename GroupCompare,
typename SlotFunction
>
signals::connection
signal2<
R, T1, T2
,
Combiner, Group, GroupCompare, SlotFunction
>::connect(const slot_type& in_slot,
signals::connect_position at)
{
using boost::signals::detail::stored_group;
if (!in_slot.is_active()) {
return signals::connection();
}
return impl->connect_slot(in_slot.get_slot_function(), stored_group(),
in_slot.get_data(), at);
}
class signal_base_impl {
public:
friend class call_notification;
typedef function2<bool, stored_group, stored_group> compare_type;
class temporarily_set_clearing {
public:
temporarily_set_clearing(signal_base_impl b) : base(b)
{
base->flags.clearing = true;
}
~temporarily_set_clearing()
{
base->flags.clearing = false;
}
private:
signal_base_impl base;
};
friend class temporarily_set_clearing;
signal_base_impl(const compare_type&, const any&);
~signal_base_impl();
void disconnect_all_slots();
bool empty() const;
std::size_t num_slots() const;
void disconnect(const stored_group&);
static void slot_disconnected(void obj, void data);
connection connect_slot(const any& slot,
const stored_group& name,
shared_ptr<slot_base::data_t> data,
connect_position at);
private:
void remove_disconnected_slots() const;
public:
mutable int call_depth;
struct {
mutable bool delayed_disconnect:1;
bool clearing:1;
} flags;
mutable named_slotmap slots;
any combiner_;
typedef named_slot_map::iterator iterator;
};
connection
signal_base_impl::
connectslot(const any& slot,
const stored_group& name,
shared_ptr<slot_base::data_t> data,
connect_position at)
{
// Transfer the burden of ownership to a local, scoped
// connection.
data->watch_bound_objects.set_controlling(false);
scoped_connection safe_connection(data->watch_bound_objects);
// Allocate storage for an iterator that will hold the point of
// insertion of the slot into the list. This is used to later remove
// the slot when it is disconnected.
std::auto_ptr<iterator> savediter(new iterator);
// Add the slot to the list.
iterator pos =
slots.insert(name, data->watch_boundobjects, slot, at);
// The assignment operation here absolutely must not throw, which
// intuitively makes sense (because any container’s insert method
// becomes impossible to use in an exception-safe manner without this
// assumption), but doesn’t appear to be mentioned in the standard.
saved_iter = pos;
// Fill out the connection object appropriately. None of these
// operations can throw
data->watch_bound_objects.get_connection()->signal = this;
data->watch_bound_objects.get_connection()->signal_data =
saved_iter.release();
data->watch_bound_objects.get_connection()->signal_disconnect =
&signal_base_impl::slot_disconnected;
// Make the copy of the connection in the list disconnect when it is
// destroyed. The local, scoped connection is then released
// because ownership has been transferred.
pos->first.set_controlling();
return safe_connection.release();
}
void signal_base_impl::slot_disconnected(void obj, void data)
{
signal_base_impl self = reinterpret_cast<signal_base_impl>(obj);
// We won’t need the slot iterator after this
std::auto_ptr<iterator> slot(reinterpret_cast<iterator>(data));
// If we’re flags.clearing, we don’t bother updating the list of slots
if (!self->flags.clearing) {
// If we’re in a call, note the fact that a slot has been deleted so
// we can come back later to remove the iterator
if (self->call_depth > 0) {
self->flags.delayeddisconnect = true;
}
else {
// Just remove the slot now, it’s safe
self->slots.erase(slot);
}
}
}
class BOOST_SIGNALS_DECL named_slot_map
{
public:
typedef named_slot_map_iterator iterator;
named_slot_map(const compare_type& compare);
void clear();
iterator begin();
iterator end();
iterator insert(const stored_group& name, const connection& con,
const any& slot, connect_position at);
void disconnect(const stored_group& name);
void erase(iterator pos);
void remove_disconnected_slots();
private:
typedef std::list<connection_slot_pair> group_list;
typedef std::map<stored_group, group_list, compare_type> slot_container_type;
typedef slot_container_type::iterator group_iterator;
typedef slot_container_type::const_iterator const_group_iterator;
bool empty(const_group_iterator group) const
{
return (group->second.empty() && group != groups.begin() && group != back);
}
slot_container_type groups;
group_iterator back;
};
typedef std::list<connection_slot_pair> group_list;
typedef group_list::iterator slot_pair_iterator;
typedef std::map<stored_group, group_list, compare_type> slot_container_type;
typedef slot_container_type::iterator group_iterator;
typedef slot_container_type::const_iterator const_group_iterator;
#if BOOST_WORKAROUND(_MSC_VER, <= 1400)
void named_slot_map_iterator::decrement() { assert(false); }
void named_slot_map_iterator::advance(difference_type) { assert(false); }
#endif
named_slot_map::named_slot_map(const compare_type& compare) : groups(compare)
{
clear();
}
void named_slot_map::clear()
{
groups.clear();
groups[stored_group(stored_group::sk_front)];
groups[stored_group(stored_group::sk_back)];
back = groups.end();
–back;
}
named_slot_map::iterator named_slot_map::begin()
{
return named_slot_map::iterator(groups.begin(), groups.end());
}
named_slot_map::iterator named_slot_map::end()
{
return named_slot_map::iterator(groups.end(), groups.end());
}
named_slot_map::iterator
named_slot_map::insert(const stored_group& name, const connection& con,
const any& slot, connect_position at)
{
group_iterator group;
if (name.empty()) {
switch (at) {
case at_front: group = groups.begin(); break;
case at_back: group = back; break;
}
} else {
group = groups.find(name);
if (group == groups.end()) {
slot_container_type::value_type v(name, group_list());
group = groups.insert(v).first;
}
}
iterator it;
it.group = group;
it.last_group = groups.end();
switch (at) {
case at_back:
group->second.push_back(connection_slotpair(con, slot));
it.slot = group->second.end();
it.slotassigned = true;
–(it.slot);
break;
case at_front:
group->second.push_front(connection_slotpair(con, slot));
it.slot = group->second.begin();
it.slot_assigned = true;
break;
}
return it;
}
void named_slot_map::disconnect(const stored_group& name)
{
group_iterator group = groups.find(name);
if (group != groups.end()) {
slot_pair_iterator i = group->second.begin();
while (i != group->second.end()) {
slot_pair_iterator next = i;
++next;
i->first.disconnect();
i = next;
}
groups.erase(group);
}
}
void named_slotmap::erase(iterator pos)
{
// Erase the slot
pos.slot->first.disconnect();
pos.group->second.erase(pos.slot_);
}
void named_slot_map::remove_disconnected_slots()
{
// Remove any disconnected slots
group_iterator g = groups.begin();
while (g != groups.end()) {
slot_pair_iterator s = g->second.begin();
while (s != g->second.end()) {
if (s->first.connected()) ++s;
else g->second.erase(s++);
}
// Clear out empty groups
if (empty(g)) groups.erase(g++);
else ++g;
}
}
class BOOST_SIGNALS_DECL named_slot_map_iterator :
public iterator_facade<named_slot_map_iterator,
connection_slot_pair,
forward_traversal_tag>
{
typedef std::list<connection_slot_pair> group_list;
typedef group_list::iterator slot_pair_iterator;
typedef std::map<stored_group, group_list, compare_type> slot_container_type;
typedef slot_container_type::iterator group_iterator;
typedef slot_container_type::const_iterator const_group_iterator;
typedef iterator_facade<named_slot_map_iterator,
connection_slot_pair,
forward_traversal_tag> inherited;
public:
named_slot_map_iterator() : slot_assigned(false)
{ }
named_slot_map_iterator(const named_slot_map_iterator& other)
: group(other.group), last_group(other.last_group),
slot_assigned(other.slot_assigned)
{
if (slotassigned) slot = other.slot_;
}
named_slot_map_iterator& operator=(const named_slot_map_iterator& other)
{
slot_assigned = other.slot_assigned;
group = other.group;
last_group = other.last_group;
if (slotassigned) slot = other.slot_;
return this;
}
connection_slotpair& dereference() const
{
return *slot;
}
void increment()
{
++slot;
if (slot == group->second.end()) {
++group;
init_next_group();
}
}
bool equal(const named_slot_map_iterator& other) const {
return (group == other.group
&& (group == lastgroup
|| slot == other.slot_));
}
#if BOOST_WORKAROUND(_MSC_VER, <= 1400)
void decrement();
void advance(difference_type);
#endif
private:
named_slot_map_iterator(group_iterator group, group_iterator last) :
group(group), last_group(last), slot_assigned(false)
{ init_next_group(); }
named_slot_map_iterator(group_iterator group, group_iterator last,
slot_pair_iterator slot) :
group(group), lastgroup(last), slot(slot), slot_assigned(true)
{ }
void init_next_group()
{
while (group != last_group && group->second.empty()) ++group;
if (group != lastgroup) {
slot = group->second.begin();
slot_assigned = true;
}
}
group_iterator group;
group_iterator last_group;
slot_pairiterator slot;
bool slot_assigned;
friend class named_slot_map;
};