turn linked_list into a template to improve type safety and remove some casts

This commit is contained in:
arvidn 2015-08-20 02:02:46 +02:00
parent ffa870d280
commit 8cf8e65861
7 changed files with 62 additions and 56 deletions

View File

@ -773,7 +773,7 @@ namespace libtorrent
// which torrents should be loaded into RAM and which ones // which torrents should be loaded into RAM and which ones
// shouldn't. Each torrent that's loaded is part of this // shouldn't. Each torrent that's loaded is part of this
// list. // list.
linked_list m_torrent_lru; linked_list<torrent> m_torrent_lru;
std::map<std::string, boost::shared_ptr<torrent> > m_uuids; std::map<std::string, boost::shared_ptr<torrent> > m_uuids;

View File

@ -168,7 +168,7 @@ namespace libtorrent
// list_node is here to be able to link this cache entry // list_node is here to be able to link this cache entry
// into one of the LRU lists // into one of the LRU lists
struct TORRENT_EXTRA_EXPORT cached_piece_entry : list_node struct TORRENT_EXTRA_EXPORT cached_piece_entry : list_node<cached_piece_entry>
{ {
cached_piece_entry(); cached_piece_entry();
~cached_piece_entry(); ~cached_piece_entry();
@ -362,7 +362,7 @@ namespace libtorrent
std::pair<iterator, iterator> all_pieces() const; std::pair<iterator, iterator> all_pieces() const;
int num_pieces() const { return m_pieces.size(); } int num_pieces() const { return m_pieces.size(); }
list_iterator write_lru_pieces() const list_iterator<cached_piece_entry> write_lru_pieces() const
{ return m_lru[cached_piece_entry::write_lru].iterate(); } { return m_lru[cached_piece_entry::write_lru].iterate(); }
int num_write_lru_pieces() const { return m_lru[cached_piece_entry::write_lru].size(); } int num_write_lru_pieces() const { return m_lru[cached_piece_entry::write_lru].size(); }
@ -491,7 +491,7 @@ namespace libtorrent
// [2] = read-LRU1-ghost // [2] = read-LRU1-ghost
// [3] = read-LRU2 // [3] = read-LRU2
// [4] = read-LRU2-ghost // [4] = read-LRU2-ghost
linked_list m_lru[cached_piece_entry::num_lrus]; linked_list<cached_piece_entry> m_lru[cached_piece_entry::num_lrus];
// this is used to determine whether to evict blocks from // this is used to determine whether to evict blocks from
// L1 or L2. // L1 or L2.

View File

@ -37,40 +37,46 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent namespace libtorrent
{ {
// TODO: 3 enable_if T derives from list_node<T>
template <typename T>
struct list_node struct list_node
{ {
list_node() : prev(0), next(0) {} list_node() : prev(0), next(0) {}
list_node* prev; T* prev;
list_node* next; T* next;
}; };
template <typename T>
struct list_iterator struct list_iterator
{ {
template <typename U>
friend struct linked_list; friend struct linked_list;
list_node const* get() const { return m_current; }
list_node* get() { return m_current; } T const* get() const { return m_current; }
T* get() { return m_current; }
void next() { m_current = m_current->next; } void next() { m_current = m_current->next; }
void prev() { m_current = m_current->prev; } void prev() { m_current = m_current->prev; }
private: private:
list_iterator(list_node* cur) list_iterator(T* cur)
: m_current(cur) {} : m_current(cur) {}
// the current element // the current element
list_node* m_current; T* m_current;
}; };
// TOOD: 3 make this a template and add a unit test // TOOD: 3 add a unit test
template <typename T>
struct linked_list struct linked_list
{ {
linked_list(): m_first(0), m_last(0), m_size(0) {} linked_list(): m_first(NULL), m_last(NULL), m_size(0) {}
list_iterator iterate() const list_iterator<T> iterate() const
{ return list_iterator(m_first); } { return list_iterator<T>(m_first); }
void erase(list_node* e) void erase(T* e)
{ {
#if TORRENT_USE_ASSERTS #if TORRENT_USE_ASSERTS
list_node* tmp = m_first; T* tmp = m_first;
bool found = false; bool found = false;
while (tmp) while (tmp)
{ {
@ -101,7 +107,7 @@ namespace libtorrent
--m_size; --m_size;
TORRENT_ASSERT(m_last == 0 || m_last->next == 0); TORRENT_ASSERT(m_last == 0 || m_last->next == 0);
} }
void push_front(list_node* e) void push_front(T* e)
{ {
TORRENT_ASSERT(e->next == 0); TORRENT_ASSERT(e->next == 0);
TORRENT_ASSERT(e->prev== 0); TORRENT_ASSERT(e->prev== 0);
@ -113,7 +119,7 @@ namespace libtorrent
m_first = e; m_first = e;
++m_size; ++m_size;
} }
void push_back(list_node* e) void push_back(T* e)
{ {
TORRENT_ASSERT(e->next == 0); TORRENT_ASSERT(e->next == 0);
TORRENT_ASSERT(e->prev== 0); TORRENT_ASSERT(e->prev== 0);
@ -125,25 +131,25 @@ namespace libtorrent
m_last = e; m_last = e;
++m_size; ++m_size;
} }
list_node* get_all() T* get_all()
{ {
TORRENT_ASSERT(m_last == 0 || m_last->next == 0); TORRENT_ASSERT(m_last == 0 || m_last->next == 0);
TORRENT_ASSERT(m_first == 0 || m_first->prev == 0); TORRENT_ASSERT(m_first == 0 || m_first->prev == 0);
list_node* e = m_first; T* e = m_first;
m_first = 0; m_first = 0;
m_last = 0; m_last = 0;
m_size = 0; m_size = 0;
return e; return e;
} }
list_node* back() { return m_last; } T* back() { return m_last; }
list_node* front() { return m_first; } T* front() { return m_first; }
list_node const* back() const { return m_last; } T const* back() const { return m_last; }
list_node const* front() const { return m_first; } T const* front() const { return m_first; }
int size() const { return m_size; } int size() const { return m_size; }
bool empty() const { return m_size == 0; } bool empty() const { return m_size == 0; }
private: private:
list_node* m_first; T* m_first;
list_node* m_last; T* m_last;
int m_size; int m_size;
}; };
} }

View File

@ -275,7 +275,7 @@ namespace libtorrent
, public request_callback , public request_callback
, public peer_class_set , public peer_class_set
, public boost::enable_shared_from_this<torrent> , public boost::enable_shared_from_this<torrent>
, public list_node // used for torrent activity LRU , public list_node<torrent> // used for torrent activity LRU
{ {
public: public:

View File

@ -410,7 +410,7 @@ void block_cache::bump_lru(cached_piece_entry* p)
{ {
// move to the top of the LRU list // move to the top of the LRU list
TORRENT_PIECE_ASSERT(p->cache_state == cached_piece_entry::write_lru, p); TORRENT_PIECE_ASSERT(p->cache_state == cached_piece_entry::write_lru, p);
linked_list* lru_list = &m_lru[p->cache_state]; linked_list<cached_piece_entry>* lru_list = &m_lru[p->cache_state];
// move to the back (MRU) of the list // move to the back (MRU) of the list
lru_list->erase(p); lru_list->erase(p);
@ -522,8 +522,8 @@ void block_cache::update_cache_state(cached_piece_entry* p)
TORRENT_PIECE_ASSERT(state < cached_piece_entry::num_lrus, p); TORRENT_PIECE_ASSERT(state < cached_piece_entry::num_lrus, p);
TORRENT_PIECE_ASSERT(desired_state < cached_piece_entry::num_lrus, p); TORRENT_PIECE_ASSERT(desired_state < cached_piece_entry::num_lrus, p);
linked_list* src = &m_lru[state]; linked_list<cached_piece_entry>* src = &m_lru[state];
linked_list* dst = &m_lru[desired_state]; linked_list<cached_piece_entry>* dst = &m_lru[desired_state];
src->erase(p); src->erase(p);
dst->push_back(p); dst->push_back(p);
@ -579,7 +579,7 @@ cached_piece_entry* block_cache::allocate_piece(disk_io_job const* j, int cache_
j->storage->add_piece(p); j->storage->add_piece(p);
TORRENT_PIECE_ASSERT(p->cache_state < cached_piece_entry::num_lrus, p); TORRENT_PIECE_ASSERT(p->cache_state < cached_piece_entry::num_lrus, p);
linked_list* lru_list = &m_lru[p->cache_state]; linked_list<cached_piece_entry>* lru_list = &m_lru[p->cache_state];
lru_list->push_back(p); lru_list->push_back(p);
// this piece is part of the ARC cache (as opposed to // this piece is part of the ARC cache (as opposed to
@ -897,7 +897,7 @@ void block_cache::erase_piece(cached_piece_entry* pe)
TORRENT_PIECE_ASSERT(pe->ok_to_evict(), pe); TORRENT_PIECE_ASSERT(pe->ok_to_evict(), pe);
TORRENT_PIECE_ASSERT(pe->cache_state < cached_piece_entry::num_lrus, pe); TORRENT_PIECE_ASSERT(pe->cache_state < cached_piece_entry::num_lrus, pe);
TORRENT_PIECE_ASSERT(pe->jobs.empty(), pe); TORRENT_PIECE_ASSERT(pe->jobs.empty(), pe);
linked_list* lru_list = &m_lru[pe->cache_state]; linked_list<cached_piece_entry>* lru_list = &m_lru[pe->cache_state];
if (pe->hash) if (pe->hash)
{ {
TORRENT_PIECE_ASSERT(pe->hash->offset == 0, pe); TORRENT_PIECE_ASSERT(pe->hash->offset == 0, pe);
@ -931,7 +931,7 @@ int block_cache::try_evict_blocks(int num, cached_piece_entry* ignore)
// lru_list is an array of two lists, these are the two ends to evict from, // lru_list is an array of two lists, these are the two ends to evict from,
// ordered by preference. // ordered by preference.
linked_list* lru_list[3]; linked_list<cached_piece_entry>* lru_list[3];
// however, before we consider any of the proper LRU lists, we evict pieces // however, before we consider any of the proper LRU lists, we evict pieces
// from the volatile list. These are low priority pieces that were // from the volatile list. These are low priority pieces that were
@ -979,7 +979,7 @@ int block_cache::try_evict_blocks(int num, cached_piece_entry* ignore)
// to iterate over this linked list. Presumably because of the random // to iterate over this linked list. Presumably because of the random
// access of memory. It would be nice if pieces with no evictable blocks // access of memory. It would be nice if pieces with no evictable blocks
// weren't in this list // weren't in this list
for (list_iterator i = lru_list[end]->iterate(); i.get() && num > 0;) for (list_iterator<cached_piece_entry> i = lru_list[end]->iterate(); i.get() && num > 0;)
{ {
cached_piece_entry* pe = reinterpret_cast<cached_piece_entry*>(i.get()); cached_piece_entry* pe = reinterpret_cast<cached_piece_entry*>(i.get());
TORRENT_PIECE_ASSERT(pe->in_use, pe); TORRENT_PIECE_ASSERT(pe->in_use, pe);
@ -1044,7 +1044,7 @@ int block_cache::try_evict_blocks(int num, cached_piece_entry* ignore)
{ {
for (int pass = 0; pass < 2 && num > 0; ++pass) for (int pass = 0; pass < 2 && num > 0; ++pass)
{ {
for (list_iterator i = m_lru[cached_piece_entry::write_lru].iterate(); i.get() && num > 0;) for (list_iterator<cached_piece_entry> i = m_lru[cached_piece_entry::write_lru].iterate(); i.get() && num > 0;)
{ {
cached_piece_entry* pe = reinterpret_cast<cached_piece_entry*>(i.get()); cached_piece_entry* pe = reinterpret_cast<cached_piece_entry*>(i.get());
TORRENT_PIECE_ASSERT(pe->in_use, pe); TORRENT_PIECE_ASSERT(pe->in_use, pe);
@ -1171,7 +1171,7 @@ void block_cache::move_to_ghost(cached_piece_entry* pe)
return; return;
// if the ghost list is growing too big, remove the oldest entry // if the ghost list is growing too big, remove the oldest entry
linked_list* ghost_list = &m_lru[pe->cache_state + 1]; linked_list<cached_piece_entry>* ghost_list = &m_lru[pe->cache_state + 1];
while (ghost_list->size() >= m_ghost_size) while (ghost_list->size() >= m_ghost_size)
{ {
cached_piece_entry* p = static_cast<cached_piece_entry*>(ghost_list->front()); cached_piece_entry* p = static_cast<cached_piece_entry*>(ghost_list->front());
@ -1581,7 +1581,7 @@ void block_cache::check_invariant() const
{ {
time_point timeout = min_time(); time_point timeout = min_time();
for (list_iterator p = m_lru[i].iterate(); p.get(); p.next()) for (list_iterator<cached_piece_entry> p = m_lru[i].iterate(); p.get(); p.next())
{ {
cached_piece_entry* pe = static_cast<cached_piece_entry*>(p.get()); cached_piece_entry* pe = static_cast<cached_piece_entry*>(p.get());
TORRENT_PIECE_ASSERT(pe->cache_state == i, pe); TORRENT_PIECE_ASSERT(pe->cache_state == i, pe);

View File

@ -905,13 +905,13 @@ namespace libtorrent
{ {
DLOG("try_flush_write_blocks: %d\n", num); DLOG("try_flush_write_blocks: %d\n", num);
list_iterator range = m_disk_cache.write_lru_pieces(); list_iterator<cached_piece_entry> range = m_disk_cache.write_lru_pieces();
std::vector<std::pair<piece_manager*, int> > pieces; std::vector<std::pair<piece_manager*, int> > pieces;
pieces.reserve(m_disk_cache.num_write_lru_pieces()); pieces.reserve(m_disk_cache.num_write_lru_pieces());
for (list_iterator p = range; p.get() && num > 0; p.next()) for (list_iterator<cached_piece_entry> p = range; p.get() && num > 0; p.next())
{ {
cached_piece_entry* e = (cached_piece_entry*)p.get(); cached_piece_entry* e = p.get();
if (e->num_dirty == 0) continue; if (e->num_dirty == 0) continue;
pieces.push_back(std::make_pair(e->storage.get(), int(e->piece))); pieces.push_back(std::make_pair(e->storage.get(), int(e->piece)));
} }
@ -939,7 +939,7 @@ namespace libtorrent
// when the write cache is under high pressure, it is likely // when the write cache is under high pressure, it is likely
// counter productive to actually do this, since a piece may // counter productive to actually do this, since a piece may
// not have had its flush_hashed job run on it // not have had its flush_hashed job run on it
// so only do it if no other thread is currently flushing // so only do it if no other thread is currently flushing
if (num == 0 || m_stats_counters[counters::num_writing_threads] > 0) return; if (num == 0 || m_stats_counters[counters::num_writing_threads] > 0) return;
@ -987,9 +987,9 @@ namespace libtorrent
cached_piece_entry** to_flush = TORRENT_ALLOCA(cached_piece_entry*, 200); cached_piece_entry** to_flush = TORRENT_ALLOCA(cached_piece_entry*, 200);
int num_flush = 0; int num_flush = 0;
for (list_iterator p = m_disk_cache.write_lru_pieces(); p.get(); p.next()) for (list_iterator<cached_piece_entry> p = m_disk_cache.write_lru_pieces(); p.get(); p.next())
{ {
cached_piece_entry* e = (cached_piece_entry*)p.get(); cached_piece_entry* e = p.get();
#if TORRENT_USE_ASSERTS #if TORRENT_USE_ASSERTS
TORRENT_PIECE_ASSERT(e->expire >= timeout, e); TORRENT_PIECE_ASSERT(e->expire >= timeout, e);
timeout = e->expire; timeout = e->expire;
@ -2477,7 +2477,7 @@ namespace libtorrent
ret = -1; ret = -1;
j->error.ec.assign(boost::asio::error::eof j->error.ec.assign(boost::asio::error::eof
, boost::asio::error::get_misc_category()); , boost::asio::error::get_misc_category());
m_disk_cache.free_buffer((char*)iov.iov_base); m_disk_cache.free_buffer(static_cast<char*>(iov.iov_base));
l.lock(); l.lock();
break; break;
} }

View File

@ -1372,8 +1372,8 @@ namespace aux {
if (t->next != NULL || t->prev != NULL || m_torrent_lru.front() == t) if (t->next != NULL || t->prev != NULL || m_torrent_lru.front() == t)
{ {
#ifdef TORRENT_DEBUG #ifdef TORRENT_DEBUG
torrent* i = static_cast<torrent*>(m_torrent_lru.front()); torrent* i = m_torrent_lru.front();
while (i != NULL && i != t) i = static_cast<torrent*>(i->next); while (i != NULL && i != t) i = i->next;
TORRENT_ASSERT(i == t); TORRENT_ASSERT(i == t);
#endif #endif
@ -1412,8 +1412,8 @@ namespace aux {
TORRENT_ASSERT(t->next != NULL || t->prev != NULL || m_torrent_lru.front() == t); TORRENT_ASSERT(t->next != NULL || t->prev != NULL || m_torrent_lru.front() == t);
#if defined TORRENT_DEBUG && defined TORRENT_EXPENSIVE_INVARIANT_CHECKS #if defined TORRENT_DEBUG && defined TORRENT_EXPENSIVE_INVARIANT_CHECKS
torrent* i = static_cast<torrent*>(m_torrent_lru.front()); torrent* i = m_torrent_lru.front();
while (i != NULL && i != t) i = static_cast<torrent*>(i->next); while (i != NULL && i != t) i = i->next;
TORRENT_ASSERT(i == t); TORRENT_ASSERT(i == t);
#endif #endif
@ -1451,8 +1451,8 @@ namespace aux {
if (ignore->next != NULL || ignore->prev != NULL || m_torrent_lru.front() == ignore) if (ignore->next != NULL || ignore->prev != NULL || m_torrent_lru.front() == ignore)
{ {
#ifdef TORRENT_DEBUG #ifdef TORRENT_DEBUG
torrent* i = static_cast<torrent*>(m_torrent_lru.front()); torrent* i = m_torrent_lru.front();
while (i != NULL && i != ignore) i = static_cast<torrent*>(i->next); while (i != NULL && i != ignore) i = i->next;
TORRENT_ASSERT(i == ignore); TORRENT_ASSERT(i == ignore);
#endif #endif
++loaded_limit; ++loaded_limit;
@ -1462,11 +1462,11 @@ namespace aux {
{ {
// we're at the limit of loaded torrents. Find the least important // we're at the limit of loaded torrents. Find the least important
// torrent and unload it. This is done with an LRU. // torrent and unload it. This is done with an LRU.
torrent* i = static_cast<torrent*>(m_torrent_lru.front()); torrent* i = m_torrent_lru.front();
if (i == ignore) if (i == ignore)
{ {
i = static_cast<torrent*>(i->next); i = i->next;
if (i == NULL) break; if (i == NULL) break;
} }
m_stats_counters.inc_stats_counter(counters::torrent_evicted_counter); m_stats_counters.inc_stats_counter(counters::torrent_evicted_counter);
@ -5761,12 +5761,12 @@ retry:
// clear the torrent LRU. We do this to avoid having the torrent // clear the torrent LRU. We do this to avoid having the torrent
// destructor assert because it's still linked into the lru list // destructor assert because it's still linked into the lru list
#if TORRENT_USE_ASSERTS #if TORRENT_USE_ASSERTS
list_node* i = m_torrent_lru.get_all(); list_node<torrent>* i = m_torrent_lru.get_all();
// clear the prev and next pointers in all torrents // clear the prev and next pointers in all torrents
// to avoid the assert when destructing them // to avoid the assert when destructing them
while (i) while (i)
{ {
list_node* tmp = i; list_node<torrent>* tmp = i;
i = i->next; i = i->next;
tmp->next = NULL; tmp->next = NULL;
tmp->prev = NULL; tmp->prev = NULL;
@ -6727,9 +6727,9 @@ retry:
#else #else
std::set<torrent*> unique_torrents; std::set<torrent*> unique_torrents;
#endif #endif
for (list_iterator i = m_torrent_lru.iterate(); i.get(); i.next()) for (list_iterator<torrent> i = m_torrent_lru.iterate(); i.get(); i.next())
{ {
torrent* t = static_cast<torrent*>(i.get()); torrent* t = i.get();
TORRENT_ASSERT(t->is_loaded()); TORRENT_ASSERT(t->is_loaded());
TORRENT_ASSERT(unique_torrents.count(t) == 0); TORRENT_ASSERT(unique_torrents.count(t) == 0);
unique_torrents.insert(t); unique_torrents.insert(t);