From 7cc377b550da13d1e12ce4e852799fbb575cbe9a Mon Sep 17 00:00:00 2001 From: rakshasa Date: Fri, 9 Dec 2005 05:22:36 +0000 Subject: [PATCH] * Cleaned up rak::priority_queue. * Added download time left display, need to tweak it. * Removed libtorrent/src/download/download_setup.cc. git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@607 e378c898-3ddf-0310-93e7-cc216c733640 --- rak/priority_queue.h | 56 +++++++++++++++++++++++++------ rak/priority_queue_default.h | 65 +++++------------------------------- src/control.cc | 2 +- src/core/download_factory.cc | 4 +-- src/display/manager.cc | 6 ++-- src/display/utils.cc | 30 +++++++++++++++++ src/display/utils.h | 2 ++ src/display/window.cc | 4 +-- src/display/window.h | 2 +- src/main.cc | 6 ++-- src/ui/download_list.cc | 2 +- 11 files changed, 102 insertions(+), 77 deletions(-) diff --git a/rak/priority_queue.h b/rak/priority_queue.h index 8185b09b..c395c2fb 100644 --- a/rak/priority_queue.h +++ b/rak/priority_queue.h @@ -46,7 +46,7 @@ namespace rak { -template +template class priority_queue : public std::vector { public: typedef std::vector base_type; @@ -59,8 +59,8 @@ public: using base_type::size; using base_type::empty; - priority_queue(Compare l = Compare(), Equal e = Equal(), Remove r = Remove()) - : m_compare(l), m_equal(e), m_remove(r) {} + priority_queue(Compare l = Compare(), Equal e = Equal()) + : m_compare(l), m_equal(e) {} const_reference top() const { return base_type::front(); @@ -76,16 +76,23 @@ public: std::push_heap(base_type::begin(), base_type::end(), m_compare); } - // Removes 'value' from the queue. The Remove functor must change the - // priority of the value such that it comes before any other in the - // queue. - void erase(value_type value) { - iterator itr = std::find_if(base_type::begin(), base_type::end(), std::bind2nd(m_equal, value)); + template + iterator find(const Key& key) { + return std::find_if(base_type::begin(), base_type::end(), std::bind2nd(m_equal, key)); + } + template + void erase(const Key& key) { + erase(find(key)); + } + + // Removes 'itr' from the queue. This assumes 'itr' has been + // modified such that it has a higher priority than any other + // element in the queue. + void erase(iterator itr) { if (itr == base_type::end()) return; - m_remove(*itr); std::push_heap(base_type::begin(), ++itr, m_compare); pop(); } @@ -93,9 +100,38 @@ public: private: Compare m_compare; Equal m_equal; - Remove m_remove; }; +// Iterate while the top node has higher priority, as 'Compare' +// returns false. +template +class queue_pop_iterator + : public std::iterator { +public: + typedef Queue container_type; + + queue_pop_iterator() : m_queue(NULL) {} + queue_pop_iterator(Queue* q, Compare c) : m_queue(q), m_compare(c) {} + + queue_pop_iterator& operator ++ () { m_queue->pop(); return *this; } + queue_pop_iterator& operator ++ (int) { m_queue->pop(); return *this; } + + typename container_type::const_reference operator * () { return m_queue->top(); } + + bool operator != (const queue_pop_iterator& itr) { return !m_queue->empty() && !m_compare(m_queue->top()); } + bool operator == (const queue_pop_iterator& itr) { return m_queue->empty() || m_compare(m_queue->top()); } + +private: + Queue* m_queue; + Compare m_compare; +}; + +template +inline queue_pop_iterator +queue_popper(Queue& queue, Compare comp) { + return queue_pop_iterator(&queue, comp); +} + } #endif diff --git a/rak/priority_queue_default.h b/rak/priority_queue_default.h index da8b3f87..de5a98d5 100644 --- a/rak/priority_queue_default.h +++ b/rak/priority_queue_default.h @@ -47,15 +47,17 @@ namespace rak { class priority_item { public: - bool is_queued() const { return m_time != timer(); } + bool is_queued() const { return m_time != timer(); } - void call() { m_slot(); } - void set_slot(function s) { m_slot = s; } + void call() { m_slot(); } + void set_slot(function s) { m_slot = s; } - const timer& time() const { return m_time; } - void clear_time() { m_time = timer(); } + const timer& time() const { return m_time; } priority_item* prepare(const timer& t); + priority_item* clear() { m_time = timer(); return this; } + + bool compare(const timer& t) const { return m_time > t; } private: timer m_time; @@ -72,62 +74,13 @@ priority_item::prepare(const timer& t) { } struct priority_compare { - bool operator () (const priority_item* p1, const priority_item* p2) const { + bool operator () (const priority_item* const p1, const priority_item* const p2) const { return p1->time() > p2->time(); } }; -struct priority_erase { - void operator () (priority_item* p1) const { - p1->clear_time(); - } -}; - typedef std::equal_to priority_equal; -typedef priority_queue priority_queue_default; - -template -class queue_pop_iterator - : public std::iterator { -public: - typedef Queue container_type; - - queue_pop_iterator() : m_queue(NULL) {} - queue_pop_iterator(Queue* q, Compare c) : m_queue(q), m_compare(c) {} - - queue_pop_iterator& operator ++ () { m_queue->pop(); return *this; } - queue_pop_iterator& operator ++ (int) { m_queue->pop(); return *this; } - - typename container_type::const_reference operator * () { return m_queue->top(); } - - bool operator != (const queue_pop_iterator& itr) { return !m_queue->empty() && m_compare(m_queue->top()); } - bool operator == (const queue_pop_iterator& itr) { return m_queue->empty() || !m_compare(m_queue->top()); } - -private: - Queue* m_queue; - Compare m_compare; -}; - -struct priority_ready { - priority_ready() {} - priority_ready(timer t) : m_timer(t) {} - - bool operator () (const priority_item* p1) const { - return p1->time() <= m_timer; - } - - timer m_timer; -}; - -inline queue_pop_iterator -queue_popper(priority_queue_default& queue, priority_ready comp) { - return queue_pop_iterator(&queue, comp); -} - -inline queue_pop_iterator -queue_popper() { - return queue_pop_iterator(); -} +typedef priority_queue priority_queue_default; } diff --git a/src/control.cc b/src/control.cc index 4c21ea1e..a47a7b79 100644 --- a/src/control.cc +++ b/src/control.cc @@ -89,7 +89,7 @@ Control::initialize() { void Control::cleanup() { - taskScheduler.erase(&m_taskShutdown); + taskScheduler.erase(m_taskShutdown.clear()); m_inputStdin->remove(m_core->get_poll_manager()->get_torrent_poll()); diff --git a/src/core/download_factory.cc b/src/core/download_factory.cc index 72c9a0ba..5984c4eb 100644 --- a/src/core/download_factory.cc +++ b/src/core/download_factory.cc @@ -65,8 +65,8 @@ DownloadFactory::DownloadFactory(const std::string& uri, Manager* m) : } DownloadFactory::~DownloadFactory() { - taskScheduler.erase(&m_taskLoad); - taskScheduler.erase(&m_taskCommit); + taskScheduler.erase(m_taskLoad.clear()); + taskScheduler.erase(m_taskCommit.clear()); delete m_stream; m_stream = NULL; diff --git a/src/display/manager.cc b/src/display/manager.cc index e13e6659..482c5c21 100644 --- a/src/display/manager.cc +++ b/src/display/manager.cc @@ -100,8 +100,10 @@ Manager::do_update() { std::list workQueue; - std::copy(rak::queue_popper(displayScheduler, rak::priority_ready(cachedTime)), rak::queue_popper(), std::back_inserter(workQueue)); - std::for_each(workQueue.begin(), workQueue.end(), std::mem_fun(&rak::priority_item::clear_time)); + std::copy(rak::queue_popper(displayScheduler, rak::bind2nd(std::mem_fun(&rak::priority_item::compare), cachedTime)), + rak::queue_popper(displayScheduler, rak::bind2nd(std::mem_fun(&rak::priority_item::compare), rak::timer())), + std::back_inserter(workQueue)); + std::for_each(workQueue.begin(), workQueue.end(), std::mem_fun(&rak::priority_item::clear)); std::for_each(workQueue.begin(), workQueue.end(), std::mem_fun(&rak::priority_item::call)); std::for_each(begin(), end(), rak::if_then(std::mem_fun(&Window::is_active), std::mem_fun(&Window::refresh))); diff --git a/src/display/utils.cc b/src/display/utils.cc index 70d2c449..6557844f 100644 --- a/src/display/utils.cc +++ b/src/display/utils.cc @@ -71,6 +71,18 @@ print_hhmmss(char* buf, unsigned int length, time_t t) { return buf + std::min(s, length); } +char* +print_hhhhmmss(char* buf, unsigned int length, time_t t) { + std::tm *u = std::localtime(&t); + + if (u == NULL) + return "inv_time"; + + unsigned int s = snprintf(buf, length, "%2u:%02u:%02u", u->tm_hour, u->tm_min, u->tm_sec); + + return buf + std::min(s, length); +} + char* print_ddmmyyyy(char* buf, unsigned int length, time_t t) { std::tm *u = std::gmtime(&t); @@ -110,6 +122,9 @@ print_download_info(char* buf, unsigned int length, core::Download* d) { (double)d->get_download().down_rate()->rate() / (1 << 10), (double)d->get_download().up_rate()->total() / (1 << 20))); + buf += std::max(0, snprintf(buf, length, " Left: ")); + buf = print_download_time_left(buf, length, d); + return buf; } @@ -138,6 +153,21 @@ print_download_status(char* buf, unsigned int length, core::Download* d) { return buf; } +char* +print_download_time_left(char* buf, unsigned int length, core::Download* d) { + uint32_t rate; + + if (!d->get_download().is_active() || + (rate = d->get_download().down_rate()->rate()) < 512) { + buf += std::max(0, snprintf(buf, length, "--:--:--")); + return buf; + } + + time_t remaining = (d->get_download().bytes_total() - d->get_download().bytes_done()) / (rate & ~(uint32_t)(512 - 1)); + + return print_hhhhmmss(buf, length, remaining); +} + // char* // print_entry_tags(char* buf, unsigned int length) { diff --git a/src/display/utils.h b/src/display/utils.h index 9a8ae0c1..f23a040d 100644 --- a/src/display/utils.h +++ b/src/display/utils.h @@ -57,11 +57,13 @@ namespace display { char* print_string(char* buf, unsigned int length, char* str); char* print_hhmmss(char* buf, unsigned int length, time_t t); +char* print_hhhhmmss(char* buf, unsigned int length, time_t t); char* print_ddmmyyyy(char* buf, unsigned int length, time_t t); char* print_download_title(char* buf, unsigned int length, core::Download* d); char* print_download_info(char* buf, unsigned int length, core::Download* d); char* print_download_status(char* buf, unsigned int length, core::Download* d); +char* print_download_time_left(char* buf, unsigned int length, core::Download* d); char* print_entry_tags(char* buf, unsigned int length); char* print_entry_file(char* buf, unsigned int length, const torrent::Entry& entry); diff --git a/src/display/window.cc b/src/display/window.cc index ac4b704a..f90a1a52 100644 --- a/src/display/window.cc +++ b/src/display/window.cc @@ -54,7 +54,7 @@ Window::Window(Canvas* c, bool d, int h) : } Window::~Window() { - displayScheduler.erase(&m_taskUpdate); + displayScheduler.erase(m_taskUpdate.clear()); delete m_canvas; } @@ -63,7 +63,7 @@ Window::set_active(bool a) { if (a) mark_dirty(); else - displayScheduler.erase(&m_taskUpdate); + displayScheduler.erase(m_taskUpdate.clear()); m_active = a; } diff --git a/src/display/window.h b/src/display/window.h index 99352585..27508a83 100644 --- a/src/display/window.h +++ b/src/display/window.h @@ -92,7 +92,7 @@ protected: inline void Window::mark_dirty() { - displayScheduler.erase(&m_taskUpdate); + displayScheduler.erase(m_taskUpdate.clear()); displayScheduler.push(m_taskUpdate.prepare(cachedTime)); } diff --git a/src/main.cc b/src/main.cc index 58b8dfc9..fd11f91c 100644 --- a/src/main.cc +++ b/src/main.cc @@ -223,8 +223,10 @@ main(int argc, char** argv) { std::list workQueue; - std::copy(rak::queue_popper(taskScheduler, rak::priority_ready(cachedTime)), rak::queue_popper(), std::back_inserter(workQueue)); - std::for_each(workQueue.begin(), workQueue.end(), std::mem_fun(&rak::priority_item::clear_time)); + std::copy(rak::queue_popper(taskScheduler, rak::bind2nd(std::mem_fun(&rak::priority_item::compare), cachedTime)), + rak::queue_popper(taskScheduler, rak::bind2nd(std::mem_fun(&rak::priority_item::compare), rak::timer())), + std::back_inserter(workQueue)); + std::for_each(workQueue.begin(), workQueue.end(), std::mem_fun(&rak::priority_item::clear)); std::for_each(workQueue.begin(), workQueue.end(), std::mem_fun(&rak::priority_item::call)); // This needs to be called every second or so. Currently done by diff --git a/src/ui/download_list.cc b/src/ui/download_list.cc index dd9bde73..29839da3 100644 --- a/src/ui/download_list.cc +++ b/src/ui/download_list.cc @@ -138,7 +138,7 @@ DownloadList::disable() { disable_display(); - taskScheduler.erase(&m_taskUpdate); + taskScheduler.erase(m_taskUpdate.clear()); m_control->display()->erase(m_window); m_control->display()->erase(m_windowTitle);