boost代码分析:signal中的connect过程(下)

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;
};