branch: externals/listen
commit 5b456c2e6793b3149a4edff2a30b4cf632073f4c
Author: Adam Porter <[email protected]>
Commit: Adam Porter <[email protected]>

    Change: (listen-queue-add-tracks) Use a hash table for deduplication
    
    This is much, much faster (especially noticeable, e.g. when adding
    5,000 tracks to a queue already containing those tracks).
---
 README.org      |  3 +++
 docs/README.org |  3 +++
 listen-lib.el   | 25 +++++++++++++++++++++++++
 listen-queue.el |  5 +----
 4 files changed, 32 insertions(+), 4 deletions(-)

diff --git a/README.org b/README.org
index 3afd3bfb19..38f3e00668 100644
--- a/README.org
+++ b/README.org
@@ -206,6 +206,9 @@ The ~listen-mode~ minor mode runs a timer which plays the 
next track in the curr
 - Option ~listen-backend~, which sets the backend to use: MPV or VLC.  (The 
default is to auto-detect which is available at load time, with MPV being 
preferred due to more robust IPC support.)
 - Faces for parts of mode line lighter.
 
+*Changes*
+- Improve performance of adding large numbers of tracks to large queues (using 
a hash table for deduplication).
+
 *Fixes*
 - Playing next track in queue after current track has been removed.
 - Updating vtables for Emacs versions before 30.
diff --git a/docs/README.org b/docs/README.org
index 7a62cb9767..10ced3139e 100644
--- a/docs/README.org
+++ b/docs/README.org
@@ -243,6 +243,9 @@ The ~listen-mode~ minor mode runs a timer which plays the 
next track in the curr
 + Option ~listen-backend~, which sets the backend to use: MPV or VLC.  (The 
default is to auto-detect which is available at load time, with MPV being 
preferred due to more robust IPC support.)
 + Faces for parts of mode line lighter.
 
+*Changes*
++ Improve performance of adding large numbers of tracks to large queues (using 
a hash table for deduplication).
+
 *Fixes*
 + Playing next track in queue after current track has been removed.
 + Updating vtables for Emacs versions before 30.
diff --git a/listen-lib.el b/listen-lib.el
index 0cb45c786c..852b5beed6 100644
--- a/listen-lib.el
+++ b/listen-lib.el
@@ -154,6 +154,31 @@ return a list of values; otherwise return the sole value."
   "Return SECONDS formatted as an hour:minute:second-style duration."
   (format-seconds "%h:%z%m:%.2s" seconds))
 
+(define-hash-table-test
+ 'listen-track-equal
+ #'equal
+ (lambda (track)
+   (sxhash-equal (expand-file-name (listen-track-filename track)))))
+
+(cl-defun listen-delete-dups (list &optional (test 'listen-track-equal))
+  "Return LIST having destructively removed duplicates.
+Similar to `delete-dups', but TEST may be specified.
+Unlike `delete-dups', this function always uses a hash table to find
+duplicates; therefore TEST should be compatible with `make-hash-table',
+which see."
+  ;; Copies the body of `delete-dups', passing through TEST, and removing the 
length-based
+  ;; non-hash-table case..
+  (let ((hash (make-hash-table :test test))
+        (tail list) retail)
+    (puthash (car list) t hash)
+    (while (setq retail (cdr tail))
+      (let ((elt (car retail)))
+        (if (gethash elt hash)
+            (setcdr tail (cdr retail))
+          (puthash elt t hash)
+          (setq tail retail))))
+    list))
+
 ;;;; Methods
 
 (cl-defgeneric listen--elapsed (player)
diff --git a/listen-queue.el b/listen-queue.el
index ea1203ebae..189aaa7261 100644
--- a/listen-queue.el
+++ b/listen-queue.el
@@ -473,10 +473,7 @@ the queue's buffer is updated, if any."
   (cl-callf append (listen-queue-tracks queue) tracks)
   ;; TODO: Consider updating the metadata of any duplicate tracks.
   (setf (listen-queue-tracks queue)
-        (cl-delete-duplicates (listen-queue-tracks queue)
-                              :key (lambda (track)
-                                     (expand-file-name (listen-track-filename 
track)))
-                              :test #'file-equal-p))
+        (listen-delete-dups (listen-queue-tracks queue) 'listen-track-equal))
   (listen-queue--update-buffer queue))
 
 (cl-defun listen-queue-add-from-playlist-file (filename queue)

Reply via email to