Optimized insertion of grouped slots so it doesn't take O(n) time

anymore.


[SVN r3676]
This commit is contained in:
Frank Mori Hess 2007-02-12 16:43:12 +00:00
parent 6e9a154a75
commit c1b82c7644
2 changed files with 144 additions and 55 deletions

View File

@ -52,7 +52,7 @@ namespace boost
class slot_invoker;
typedef typename signalslib::detail::group_key<Group>::type group_key_type;
typedef boost::shared_ptr<signalslib::detail::ConnectionBody<group_key_type, SlotFunction> > connection_body_type;
typedef std::list<connection_body_type> ConnectionList;
typedef signalslib::detail::grouped_list<Group, GroupCompare, connection_body_type> connection_list_type;
public:
typedef SlotFunction slot_function_type;
typedef slot<slot_function_type> slot_type;
@ -62,7 +62,7 @@ namespace boost
typedef Group group_type;
typedef GroupCompare group_compare_type;
typedef typename signalslib::detail::slot_call_iterator_t<slot_invoker,
typename ConnectionList::iterator > slot_call_iterator;
typename connection_list_type::iterator > slot_call_iterator;
// typedef Tn argn_type;
#define EPG_SIGNAL_MISC_STATEMENT(z, n, data) \
typedef BOOST_PP_CAT(T, BOOST_PP_INC(n)) BOOST_PP_CAT(BOOST_PP_CAT(arg, BOOST_PP_INC(n)), _type);
@ -78,8 +78,7 @@ namespace boost
EPG_SIGNAL_CLASS_NAME(const combiner_type &combiner = combiner_type(),
const group_compare_type &group_compare = group_compare_type()):
_combiner(new combiner_type(combiner)), _connectionBodies(new ConnectionList),
_group_key_comparator(group_compare)
_combiner(new combiner_type(combiner)), _connectionBodies(new connection_list_type(group_compare))
{};
virtual ~EPG_SIGNAL_CLASS_NAME()
{}
@ -93,11 +92,11 @@ namespace boost
if(position == signalslib::at_back)
{
group_key.first = signalslib::detail::back_ungrouped_slots;
_connectionBodies->push_back(newConnectionBody);
_connectionBodies->push_back(group_key, newConnectionBody);
}else
{
group_key.first = signalslib::detail::front_ungrouped_slots;
_connectionBodies->push_front(newConnectionBody);
_connectionBodies->push_front(group_key, newConnectionBody);
}
newConnectionBody->set_group_key(group_key);
return signalslib::connection(newConnectionBody);
@ -113,34 +112,10 @@ namespace boost
newConnectionBody->set_group_key(group_key);
if(position == signalslib::at_back)
{
typename ConnectionList::reverse_iterator rit;
for(rit = _connectionBodies->rbegin(); rit != _connectionBodies->rend(); ++rit)
{
if(_group_key_comparator(group_key, (*rit)->group_key()) == false)
{
_connectionBodies->insert(rit.base(), newConnectionBody);
break;
}
}
if(rit == _connectionBodies->rend())
{
_connectionBodies->insert(rit.base(), newConnectionBody);
}
_connectionBodies.push_back(group_key, newConnectionBody);
}else // at_front
{
typename ConnectionList::iterator it;
for(it = _connectionBodies->begin(); it != _connectionBodies->end(); ++it)
{
if(_group_key_comparator((*it)->group_key(), group_key) == false)
{
_connectionBodies->insert(it, newConnectionBody);
break;
}
}
if(it == _connectionBodies->end())
{
_connectionBodies->insert(it, newConnectionBody);
}
_connectionBodies.push_front(group_key, newConnectionBody);
}
return signalslib::connection(newConnectionBody);
}
@ -148,7 +123,7 @@ namespace boost
void disconnect_all_slots()
{
boost::mutex::scoped_lock listLock(_mutex);
typename ConnectionList::iterator it;
typename connection_list_type::iterator it;
for(it = _connectionBodies->begin(); it != _connectionBodies->end(); ++it)
{
(*it)->disconnect();
@ -159,24 +134,19 @@ namespace boost
{
boost::mutex::scoped_lock listLock(_mutex);
group_key_type group_key(signalslib::detail::grouped_slots, group);
typename ConnectionList::iterator it;
for(it = _connectionBodies->begin(); it != _connectionBodies->end();)
typename connection_list_type::iterator it;
typename connection_list_type::iterator end_it = _connectionBodies->upper_bound(group);
for(it = _connectionBodies->lower_bound(group); it != end_it; ++it)
{
if(_group_key_comparator((*it)->group_key(), group_key))
{
++it;
continue;
}
if(_group_key_comparator(group_key, (*it)->group_key())) break;
(*it)->disconnect();
it = _connectionBodies->erase(it);
}
_connectionBodies->erase(group);
}
template <typename Slot>
void disconnect(const Slot &slot)
{
boost::mutex::scoped_lock listLock(_mutex);
typename ConnectionList::iterator it;
typename connection_list_type::iterator it;
for(it = _connectionBodies->begin(); it != _connectionBodies->end(); ++it)
{
bool disconnect;
@ -193,7 +163,7 @@ namespace boost
if(disconnect)
{
(*it)->nolock_disconnect();
it = _connectionBodies->erase(it);
it = _connectionBodies->erase((*it)->group_key(), it);
break;
}
}
@ -201,9 +171,9 @@ namespace boost
// emit signal
result_type operator ()(EPG_SIGNAL_SIGNATURE_FULL_ARGS(EPG_SIGNALS_NUM_ARGS, ~))
{
boost::shared_ptr<ConnectionList> localConnectionBodies;
boost::shared_ptr<connection_list_type> localConnectionBodies;
boost::shared_ptr<combiner_type> local_combiner;
typename ConnectionList::iterator it;
typename connection_list_type::iterator it;
{
boost::mutex::scoped_lock listLock(_mutex);
// only clean up if it is safe to do so
@ -230,7 +200,7 @@ namespace boost
std::size_t num_slots() const
{
boost::mutex::scoped_lock listLock(_mutex);
typename ConnectionList::iterator it;
typename connection_list_type::iterator it;
std::size_t count = 0;
for(it = _connectionBodies->begin(); it != _connectionBodies->end(); ++it)
{
@ -241,7 +211,7 @@ namespace boost
bool empty() const
{
boost::mutex::scoped_lock listLock(_mutex);
typename ConnectionList::iterator it;
typename connection_list_type::iterator it;
for(it = _connectionBodies->begin(); it != _connectionBodies->end(); ++it)
{
if((*it)->connected()) return false;
@ -291,10 +261,10 @@ namespace boost
};
// clean up disconnected connections
void nolockCleanupConnections(boost::shared_ptr<ConnectionList> &connectionBodies, bool grab_tracked)
void nolockCleanupConnections(boost::shared_ptr<connection_list_type> &connectionBodies, bool grab_tracked)
{
assert(connectionBodies.use_count() == 1);
typename ConnectionList::iterator it;
typename connection_list_type::iterator it;
for(it = connectionBodies->begin(); it != connectionBodies->end();)
{
bool connected;
@ -308,7 +278,7 @@ namespace boost
}// scoped lock destructs here, safe to erase now
if(connected == false)
{
it = connectionBodies->erase(it);
it = connectionBodies->erase((*it)->group_key(), it);
}else
{
++it;
@ -321,7 +291,7 @@ namespace boost
{
if(_connectionBodies.use_count() > 1)
{
boost::shared_ptr<ConnectionList> newList(new ConnectionList(*_connectionBodies));
boost::shared_ptr<connection_list_type> newList(new connection_list_type(*_connectionBodies));
_connectionBodies = newList;
}
}
@ -331,10 +301,9 @@ namespace boost
nolockCleanupConnections(_connectionBodies, true);
return connection_body_type(new signalslib::detail::ConnectionBody<group_key_type, slot_function_type>(slot));
}
boost::shared_ptr<combiner_type> _combiner;
boost::shared_ptr<ConnectionList> _connectionBodies;
// holds first connection body of each group
signalslib::detail::group_key_less<Group, GroupCompare> _group_key_comparator;
boost::shared_ptr<connection_list_type> _connectionBodies;
mutable boost::mutex _mutex;
};
namespace signalslib

View File

@ -16,6 +16,9 @@
#include <boost/thread_safe_signals/connection.hpp>
#include <boost/optional.hpp>
#include <cassert>
#include <list>
#include <map>
#include <utility>
namespace boost {
@ -44,6 +47,123 @@ namespace boost {
private:
GroupCompare _group_compare;
};
template<typename Group, typename GroupCompare, typename ValueType>
class grouped_list
{
private:
typedef std::list<ValueType> list_type;
typedef std::map<typename group_key<Group>::type, typename list_type::iterator> map_type;
typedef typename map_type::iterator map_iterator;
public:
typedef typename list_type::iterator iterator;
typedef typename group_key<Group>::type group_key_type;
typedef group_key_less<Group, GroupCompare> group_key_compare_type;
grouped_list(const group_key_compare_type &group_key_compare):
_group_key_compare(group_key_compare)
{}
iterator begin()
{
return _list.begin();
}
iterator end()
{
return _list.end();
}
iterator lower_bound(const group_key_type &key)
{
map_iterator map_it = _group_map.lower_bound(key);
return get_list_iterator(map_it);
}
iterator upper_bound(const group_key_type &key)
{
map_iterator map_it = _group_map.upper_bound(key);
return get_list_iterator(map_it);
}
void push_front(const group_key_type &key, const ValueType &value)
{
map_iterator map_it = _group_map.lower_bound(key);
m_insert(map_it, key, value);
}
void push_back(const group_key_type &key, const ValueType &value)
{
map_iterator map_it = _group_map.upper_bound(key);
m_insert(map_it, key, value);
}
void erase(const group_key_type &key)
{
map_iterator map_it = _group_map.lower_bound(key);
iterator begin_list_it = get_list_iterator(map_it);
iterator end_list_it = upper_bound(key);
if(begin_list_it != end_list_it)
{
_list.erase(begin_list_it, end_list_it);
map_it.erase(map_it);
}
}
iterator erase(const group_key_type &key, const iterator &it)
{
map_iterator map_it = _group_map.lower_bound(key);
assert(map_it != _group_map.end());
assert(weakly_equivalent(map_it->first, key));
iterator next = it;
++next;
// if next is in same group
if(next != _list.end() && next != upper_bound(key))
{
_group_map.insert(map_type::value_type(key, next));
}
if(map_it->second == it)
{
_group_map.erase(map_it);
}
return _list.erase(it);
}
void clear()
{
_list.clear();
_group_map.clear();
}
private:
bool weakly_equivalent(const group_key_type &arg1, const group_key_type &arg2)
{
if(_group_key_compare(arg1, arg2)) return false;
if(_group_key_compare(arg2, arg1)) return false;
return true;
}
void m_insert(map_iterator map_it, const group_key_type &key, const ValueType &value)
{
iterator list_it = get_list_iterator(map_it);
_list.insert(list_it, value);
if(map_it != _group_map.end() && weakly_equivalent(key, map_it->first))
{
_group_map.erase(map_it);
}
map_iterator lower_bound_it = _group_map.lower_bound(key);
if(lower_bound_it == _group_map.end() ||
weakly_equivalent(lower_bound_it->first, key) == false)
{
_group_map.insert(map_type::value_type(key, list_it));
}
}
iterator get_list_iterator(const map_iterator &map_it)
{
iterator list_it;
if(map_it == _group_map.end())
{
list_it = _list.end();
}else
{
list_it = map_it->second;
}
return list_it;
}
list_type _list;
// holds iterators to first list item in each group
map_type _group_map;
group_key_compare_type _group_key_compare;
};
} // end namespace detail
enum connect_position { at_back, at_front };
} // end namespace signalslib