From e60e75fadc7b78e1219623b0af794b0cfe9a5b8f Mon Sep 17 00:00:00 2001 From: Mike Gelfand Date: Sun, 24 Apr 2016 07:56:41 +0000 Subject: [PATCH] Reduce torrents model memory requirements (Qt client) Keep torrents sorted by ID. This allows to remove ID to row/torrent mappings (using binary search instead) and thus also reduce complexity a bit. --- qt/TorrentModel.cc | 125 ++++++++++++++++++++++++++++----------------- qt/TorrentModel.h | 6 +-- 2 files changed, 78 insertions(+), 53 deletions(-) diff --git a/qt/TorrentModel.cc b/qt/TorrentModel.cc index 5f6509a03..56019ebb0 100644 --- a/qt/TorrentModel.cc +++ b/qt/TorrentModel.cc @@ -17,13 +17,32 @@ #include "TorrentDelegate.h" #include "TorrentModel.h" +namespace +{ + struct TorrentIdLessThan + { + bool operator () (Torrent * left, Torrent * right) const + { + return left->id () < right->id (); + } + + bool operator () (int leftId, Torrent * right) const + { + return leftId < right->id (); + } + + bool operator () (Torrent * left, int rightId) const + { + return left->id () < rightId; + } + }; +} + void TorrentModel::clear () { beginResetModel (); - myIdToRow.clear (); - myIdToTorrent.clear (); qDeleteAll (myTorrents); myTorrents.clear (); @@ -76,9 +95,35 @@ TorrentModel::data (const QModelIndex& index, int role) const void TorrentModel::addTorrent (Torrent * t) { - myIdToTorrent.insert (t->id (), t); - myIdToRow.insert (t->id (), myTorrents.size ()); - myTorrents.append (t); + const torrents_t::iterator torrentIt = qLowerBound (myTorrents.begin (), myTorrents.end (), t, TorrentIdLessThan ()); + const int row = torrentIt == myTorrents.end () ? myTorrents.size () : torrentIt - myTorrents.begin (); + + beginInsertRows (QModelIndex(), row, row); + myTorrents.insert (torrentIt, t); + endInsertRows (); +} + +void +TorrentModel::addTorrents (torrents_t&& torrents, QSet& addIds) +{ + if (myTorrents.isEmpty ()) + { + qSort (torrents.begin (), torrents.end (), TorrentIdLessThan ()); + + beginInsertRows (QModelIndex (), 0, torrents.size () - 1); + myTorrents.swap (torrents); + endInsertRows (); + + addIds += getIds (); + } + else + { + for (Torrent * const tor: torrents) + { + addTorrent (tor); + addIds.insert (tor->id ()); + } + } } TorrentModel::TorrentModel (const Prefs& prefs): @@ -98,15 +143,15 @@ TorrentModel::~TorrentModel () Torrent* TorrentModel::getTorrentFromId (int id) { - id_to_torrent_t::iterator it (myIdToTorrent.find (id)); - return it == myIdToTorrent.end() ? 0 : it.value (); + const torrents_t::const_iterator torrentIt = qBinaryFind (myTorrents.begin (), myTorrents.end (), id, TorrentIdLessThan ()); + return torrentIt == myTorrents.end () ? nullptr : *torrentIt; } const Torrent* TorrentModel::getTorrentFromId (int id) const { - id_to_torrent_t::const_iterator it (myIdToTorrent.find (id)); - return it == myIdToTorrent.end() ? 0 : it.value (); + const torrents_t::const_iterator torrentIt = qBinaryFind (myTorrents.begin (), myTorrents.end (), id, TorrentIdLessThan ()); + return torrentIt == myTorrents.end () ? nullptr : *torrentIt; } /*** @@ -116,12 +161,14 @@ TorrentModel::getTorrentFromId (int id) const void TorrentModel::onTorrentChanged (int torrentId) { - const int row (myIdToRow.value (torrentId, -1)); - if (row >= 0) - { - QModelIndex qmi (index (row, 0)); - emit dataChanged (qmi, qmi); - } + const torrents_t::iterator torrentIt = qBinaryFind (myTorrents.begin (), myTorrents.end (), torrentId, TorrentIdLessThan ()); + if (torrentIt == myTorrents.end ()) + return; + + const int row = torrentIt - myTorrents.begin (); + const QModelIndex qmi (index (row, 0)); + + emit dataChanged (qmi, qmi); } void @@ -140,12 +187,12 @@ TorrentModel::removeTorrents (tr_variant * torrents) void TorrentModel::updateTorrents (tr_variant * torrents, bool isCompleteList) { - QList newTorrents; + torrents_t newTorrents; QSet oldIds; QSet addIds; QSet newIds; - if (isCompleteList) + if (isCompleteList) oldIds = getIds (); if (tr_variantIsList (torrents)) @@ -157,7 +204,8 @@ TorrentModel::updateTorrents (tr_variant * torrents, bool isCompleteList) int64_t id; if (tr_variantDictFindInt (child, TR_KEY_id, &id)) { - newIds.insert (id); + if (isCompleteList) + newIds.insert (id); Torrent * tor = getTorrentFromId (id); if (tor == 0) @@ -183,21 +231,7 @@ TorrentModel::updateTorrents (tr_variant * torrents, bool isCompleteList) } if (!newTorrents.isEmpty ()) - { - const int oldCount (rowCount ()); - const int newCount (oldCount + newTorrents.size ()); - QSet ids; - - beginInsertRows (QModelIndex(), oldCount, newCount - 1); - - for (Torrent * const tor: newTorrents) - { - addTorrent (tor); - addIds.insert (tor->id ()); - } - - endInsertRows (); - } + addTorrents (std::move (newTorrents), addIds); if (!addIds.isEmpty()) emit torrentsAdded (addIds); @@ -214,23 +248,18 @@ TorrentModel::updateTorrents (tr_variant * torrents, bool isCompleteList) void TorrentModel::removeTorrent (int id) { - const int row = myIdToRow.value (id, -1); - if (row >= 0) - { - Torrent * tor = myIdToTorrent.value (id, 0); + const torrents_t::iterator torrentIt = qBinaryFind (myTorrents.begin (), myTorrents.end (), id, TorrentIdLessThan ()); + if (torrentIt == myTorrents.end ()) + return; - beginRemoveRows (QModelIndex(), row, row); - // make the myIdToRow map consistent with list view/model - for (auto i = myIdToRow.begin(); i != myIdToRow.end(); ++i) - if (i.value() > row) - --i.value(); - myIdToRow.remove (id); - myIdToTorrent.remove (id); - myTorrents.remove (myTorrents.indexOf (tor)); - endRemoveRows (); + Torrent * const tor = *torrentIt; + const int row = torrentIt - myTorrents.begin (); - delete tor; - } + beginRemoveRows (QModelIndex(), row, row); + myTorrents.remove (row); + endRemoveRows (); + + delete tor; } void diff --git a/qt/TorrentModel.h b/qt/TorrentModel.h index 96949fac5..a349ac46a 100644 --- a/qt/TorrentModel.h +++ b/qt/TorrentModel.h @@ -10,7 +10,6 @@ #pragma once #include -#include #include #include @@ -59,12 +58,11 @@ class TorrentModel: public QAbstractListModel void torrentsAdded (QSet); private: - typedef QMap id_to_row_t; - typedef QMap id_to_torrent_t; typedef QVector torrents_t; private: void addTorrent (Torrent *); + void addTorrents (torrents_t&& torrents, QSet& addIds); QSet getIds () const; private slots: @@ -73,8 +71,6 @@ class TorrentModel: public QAbstractListModel private: const Prefs& myPrefs; - id_to_row_t myIdToRow; - id_to_torrent_t myIdToTorrent; torrents_t myTorrents; };