]> granicus.if.org Git - transmission/commitdiff
Reduce torrents model memory requirements (Qt client)
authorMike Gelfand <mikedld@mikedld.com>
Sun, 24 Apr 2016 07:56:41 +0000 (07:56 +0000)
committerMike Gelfand <mikedld@mikedld.com>
Sun, 24 Apr 2016 07:56:41 +0000 (07:56 +0000)
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
qt/TorrentModel.h

index 5f6509a03f11972f551715426e249644ef9a00b9..56019ebb0e9a612e5e1e2b1fe7b0c35ef6154c36 100644 (file)
 #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<int>& 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<Torrent*> newTorrents;
+  torrents_t newTorrents;
   QSet<int> oldIds;
   QSet<int> addIds;
   QSet<int> 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<int> 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);
-
-      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 ();
-
-      delete tor;
-    }
+  const torrents_t::iterator torrentIt = qBinaryFind (myTorrents.begin (), myTorrents.end (), id, TorrentIdLessThan ());
+  if (torrentIt == myTorrents.end ())
+    return;
+
+  Torrent * const tor = *torrentIt;
+  const int row = torrentIt - myTorrents.begin ();
+
+  beginRemoveRows (QModelIndex(), row, row);
+  myTorrents.remove (row);
+  endRemoveRows ();
+
+  delete tor;
 }
 
 void
index 96949fac5d6247ba992beb6ee41951e0f975728c..a349ac46aed92e99fc04a8245cc486b3ddae7229 100644 (file)
@@ -10,7 +10,6 @@
 #pragma once
 
 #include <QAbstractListModel>
-#include <QMap>
 #include <QSet>
 #include <QVector>
 
@@ -59,12 +58,11 @@ class TorrentModel: public QAbstractListModel
     void torrentsAdded (QSet<int>);
 
   private:
-    typedef QMap<int, int> id_to_row_t;
-    typedef QMap<int, Torrent*> id_to_torrent_t;
     typedef QVector<Torrent*> torrents_t;
 
   private:
     void addTorrent (Torrent *);
+    void addTorrents (torrents_t&& torrents, QSet<int>& addIds);
     QSet<int> 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;
 };