diff options
author | Eric Abrahamsen <eric@ericabrahamsen.net> | 2018-04-26 16:26:27 -0700 |
---|---|---|
committer | Eric Abrahamsen <eric@ericabrahamsen.net> | 2019-03-22 10:23:30 -0700 |
commit | c1b63af4458e92bad33da0def2b15c206656e2fa (patch) | |
tree | 267503989ec0475b76800bb309f6cdc1da53e74e /lisp/gnus/gnus-sum.el | |
parent | 3375d08299bbc1e224d19a871012cdbbf5d787ee (diff) | |
download | emacs-c1b63af4458e92bad33da0def2b15c206656e2fa.tar.gz emacs-c1b63af4458e92bad33da0def2b15c206656e2fa.tar.bz2 emacs-c1b63af4458e92bad33da0def2b15c206656e2fa.zip |
Change Gnus hash tables into real hash tables
Gnus has used obarrays as makeshift hash tables for groups: group
names are coerced to unibyte and interned in custom obarrays, and
their symbol-value set to whatever value needs to be stored. This
patch replaces those obarrays with actual hash tables.
* lisp/gnus/gnus-util.el (gnus-intern-safe, gnus-create-hash-size):
Remove functions.
(gnus-make-hashtable): Change to return a real hash table.
(gnus-text-property-search): Utility similar to `text-property-any',
but compares on `equal'. Needed because the 'gnus-group text
property is now a string.
* lisp/gnus/gnus.el (gnus-gethash, gnus-gethash-safe, gnus-sethash):
Remove macros.
(gnus-group-list): New variable holding all group names as an
ordered list. Used because `gnus-newsrc-hashtb' used to preserve
`gnus-newsrc-alist' ordering, but now doesn't.
* lisp/gnus/nnmaildir.el (nnmaildir--servers): Change from obarray to
alist.
(nnmaildir--up2-1): Remove function.
* lisp/thingatpt.el (thing-at-point-newsgroup-p): This was making use
of Gnus obarrays, replace with a cond that can handle many different
possibilities.
* lisp/gnus/gnus-bcklg.el (gnus-backlog-articles): Remove
gnus-backlog-hashtb, which wasn't doing anything. Just keep a list
of ident strings in gnus-backlog-articles.
(gnus-backlog-setup): Delete unnecessary function.
(gnus-backlog-enter-article, gnus-backlog-remove-oldest-article,
gnus-backlog-remove-article, gnus-backlog-request-article): Alter
calls accordingly.
* lisp/gnus/gnus-dup.el (gnus-duplicate-list-max-length): Rename from
`gnus-duplicate-list-length', for accuracy.
* lisp/gnus/gnus-start.el (gnus-active-to-gnus-format,
gnus-groups-to-gnus-format, gnus-newsrc-to-gnus-format): Read group
names as strings.
(gnus-gnus-to-quick-newsrc-format): Write `gnus-newsrc-alist' using
the ordering in `gnus-group-list'.
* lisp/gnus/gnus-agent.el:
* lisp/gnus/gnus-async.el:
* lisp/gnus/gnus-cache.el:
* lisp/gnus/gnus-group.el:
* lisp/gnus/gnus-score.el:
* lisp/gnus/gnus-sum.el:
* lisp/gnus/gnus-topic.el:
* lisp/gnus/message.el:
* lisp/gnus/mml.el:
* lisp/gnus/nnagent.el:
* lisp/gnus/nnbabyl.el:
* lisp/gnus/nnvirtual.el:
* lisp/gnus/nnweb.el: In all files, change obarrays to hash-tables,
and swap `gnus-sethash' for `puthash', `gnus-gethash' for `gethash',
`mapatoms' for `maphash', etc.
* test/lisp/gnus/gnus-test-headers.el (gnus-headers-make-dependency-table,
gnus-headers-loop-dependencies): New tests to make sure we're
building `gnus-newsgroup-dependencies' correctly.
Diffstat (limited to 'lisp/gnus/gnus-sum.el')
-rw-r--r-- | lisp/gnus/gnus-sum.el | 220 |
1 files changed, 116 insertions, 104 deletions
diff --git a/lisp/gnus/gnus-sum.el b/lisp/gnus/gnus-sum.el index efb3e4f1a66..85c902a5e43 100644 --- a/lisp/gnus/gnus-sum.el +++ b/lisp/gnus/gnus-sum.el @@ -39,6 +39,8 @@ (require 'gmm-utils) (require 'mm-decode) (require 'nnoo) +(eval-when-compile + (require 'subr-x)) (autoload 'gnus-summary-limit-include-cached "gnus-cache" nil t) (autoload 'gnus-cache-write-active "gnus-cache") @@ -1361,7 +1363,15 @@ the normal Gnus MIME machinery." (defvar gnus-current-crosspost-group nil) (defvar gnus-newsgroup-display nil) -(defvar gnus-newsgroup-dependencies nil) +(defvar gnus-newsgroup-dependencies nil + "A hash table holding dependencies between messages.") +;; Dependencies are held in a tree structure: a list with the root +;; message as car, and each immediate child a sublist (perhaps +;; containing further sublists). Each message is represented as a +;; vector of headers. Each message's list can be looked up in the +;; dependency table using the message's Message-ID as the key. The +;; root key is the string "none". + (defvar gnus-newsgroup-adaptive nil) (defvar gnus-summary-display-article-function nil) (defvar gnus-summary-highlight-line-function nil @@ -3937,7 +3947,7 @@ If SELECT-ARTICLES, only select those articles from GROUP." ;; Killed foreign groups can't be entered. ;; (when (and (not (gnus-group-native-p group)) - ;; (not (gnus-gethash group gnus-newsrc-hashtb))) + ;; (not (gethash group gnus-newsrc-hashtb))) ;; (error "Dead non-native groups can't be entered")) (gnus-message 7 "Retrieving newsgroup: %s..." (gnus-group-decoded-name group)) @@ -4167,7 +4177,7 @@ If SELECT-ARTICLES, only select those articles from GROUP." "Gather threads by looking at Subject headers." (if (not gnus-summary-make-false-root) threads - (let ((hashtb (gnus-make-hashtable 1024)) + (let ((hashtb (gnus-make-hashtable 1000)) (prev threads) (result threads) subject hthread whole-subject) @@ -4176,7 +4186,7 @@ If SELECT-ARTICLES, only select those articles from GROUP." (setq whole-subject (mail-header-subject (caar threads))))) (when subject - (if (setq hthread (gnus-gethash subject hashtb)) + (if (setq hthread (gethash subject hashtb)) (progn ;; We enter a dummy root into the thread, if we ;; haven't done that already. @@ -4190,24 +4200,24 @@ If SELECT-ARTICLES, only select those articles from GROUP." (setcdr prev (cdr threads)) (setq threads prev)) ;; Enter this thread into the hash table. - (gnus-sethash subject - (if gnus-summary-make-false-root-always - (progn - ;; If you want a dummy root above all - ;; threads... - (setcar threads (list whole-subject - (car threads))) - threads) - threads) - hashtb))) + (puthash subject + (if gnus-summary-make-false-root-always + (progn + ;; If you want a dummy root above all + ;; threads... + (setcar threads (list whole-subject + (car threads))) + threads) + threads) + hashtb))) (setq prev threads) (setq threads (cdr threads))) result))) (defun gnus-gather-threads-by-references (threads) "Gather threads by looking at References headers." - (let ((idhashtb (gnus-make-hashtable 1024)) - (thhashtb (gnus-make-hashtable 1024)) + (let ((idhashtb (gnus-make-hashtable 1000)) + (thhashtb (gnus-make-hashtable 1000)) (prev threads) (result threads) ids references id gthread gid entered ref) @@ -4218,11 +4228,11 @@ If SELECT-ARTICLES, only select those articles from GROUP." entered nil) (while (setq ref (pop ids)) (setq ids (delete ref ids)) - (if (not (setq gid (gnus-gethash ref idhashtb))) + (if (not (setq gid (gethash ref idhashtb))) (progn - (gnus-sethash ref id idhashtb) - (gnus-sethash id threads thhashtb)) - (setq gthread (gnus-gethash gid thhashtb)) + (puthash ref id idhashtb) + (puthash id threads thhashtb)) + (setq gthread (gethash gid thhashtb)) (unless entered ;; We enter a dummy root into the thread, if we ;; haven't done that already. @@ -4234,7 +4244,7 @@ If SELECT-ARTICLES, only select those articles from GROUP." (setcdr (car gthread) (nconc (cdar gthread) (list (car threads))))) ;; Add it into the thread hash table. - (gnus-sethash id gthread thhashtb) + (puthash id gthread thhashtb) (setq entered t) ;; Remove it from the list of threads. (setcdr prev (cdr threads)) @@ -4267,12 +4277,12 @@ If SELECT-ARTICLES, only select those articles from GROUP." ;; We have found a loop. (let (ref-dep) (setcdr thread (delq (car th) (cdr thread))) - (if (boundp (setq ref-dep (intern "none" - gnus-newsgroup-dependencies))) - (setcdr (symbol-value ref-dep) - (nconc (cdr (symbol-value ref-dep)) + (if (setq ref-dep (gethash "none" + gnus-newsgroup-dependencies)) + (setcdr ref-dep + (nconc (cdr ref-dep) (list (car th)))) - (set ref-dep (list nil (car th)))) + (puthash ref-dep (list nil (car th)) gnus-newsgroup-dependencies)) (setq infloop 1 stack nil)) ;; Push all the subthreads onto the stack. @@ -4283,31 +4293,30 @@ If SELECT-ARTICLES, only select those articles from GROUP." "Go through the dependency hashtb and find the roots. Return all threads." (let (threads) (while (catch 'infloop - (mapatoms - (lambda (refs) + (maphash + (lambda (_id refs) ;; Deal with self-referencing References loops. - (when (and (car (symbol-value refs)) + (when (and (car refs) (not (zerop (apply '+ (mapcar (lambda (thread) (gnus-thread-loop-p - (car (symbol-value refs)) thread)) - (cdr (symbol-value refs))))))) + (car refs) thread)) + (cdr refs)))))) (setq threads nil) (throw 'infloop t)) - (unless (car (symbol-value refs)) + (unless (car refs) ;; These threads do not refer back to any other ;; articles, so they're roots. - (setq threads (append (cdr (symbol-value refs)) threads)))) + (setq threads (append (cdr refs) threads)))) gnus-newsgroup-dependencies))) threads)) ;; Build the thread tree. (defsubst gnus-dependencies-add-header (header dependencies force-new) "Enter HEADER into the DEPENDENCIES table if it is not already there. - If FORCE-NEW is not nil, enter HEADER into the DEPENDENCIES table even if it was already present. @@ -4318,33 +4327,38 @@ Message-ID before being entered. Returns HEADER if it was entered in the DEPENDENCIES. Returns nil otherwise." (let* ((id (mail-header-id header)) - (id-dep (and id (intern id dependencies))) + ;; An "id-dep" is a list holding the vector headers of this + ;; message, plus equivalent "id-deps" for each immediate + ;; child message. + (id-dep (and id (gethash id dependencies))) parent-id ref ref-dep ref-header replaced) ;; Enter this `header' in the `dependencies' table. (cond - ((not id-dep) + ((null id) + ;; Omit this article altogether if there is no Message-ID. (setq header nil)) - ;; The first two cases do the normal part: enter a new `header' - ;; in the `dependencies' table. - ((not (boundp id-dep)) - (set id-dep (list header))) - ((null (car (symbol-value id-dep))) - (setcar (symbol-value id-dep) header)) - + ;; Enter a new id and `header' in the `dependencies' table. + ((null id-dep) + (setq id-dep (puthash id (list header) dependencies))) + ;; A child message has already added this id, just insert the header. + ((null (car id-dep)) + (setcar (gethash id dependencies) header) + (setq id-dep (gethash id dependencies))) ;; From here the `header' was already present in the ;; `dependencies' table. (force-new ;; Overrides an existing entry; ;; just set the header part of the entry. - (setcar (symbol-value id-dep) header) + (setcar (gethash id dependencies) header) (setq replaced t)) ;; Renames the existing `header' to a unique Message-ID. ((not gnus-summary-ignore-duplicates) ;; An article with this Message-ID has already been seen. ;; We rename the Message-ID. - (set (setq id-dep (intern (setq id (nnmail-message-id)) dependencies)) - (list header)) + (setq id-dep (puthash (setq id (nnmail-message-id)) + (list header) + dependencies)) (mail-header-set-id header id)) ;; The last case ignores an existing entry, except it adds any @@ -4354,8 +4368,8 @@ Returns HEADER if it was entered in the DEPENDENCIES. Returns nil otherwise." ;; table was *not* modified. (t (mail-header-set-xref - (car (symbol-value id-dep)) - (concat (or (mail-header-xref (car (symbol-value id-dep))) + (car id-dep) + (concat (or (mail-header-xref (car id-dep)) "") (or (mail-header-xref header) ""))) (setq header nil))) @@ -4365,23 +4379,27 @@ Returns HEADER if it was entered in the DEPENDENCIES. Returns nil otherwise." (setq parent-id (gnus-parent-id (mail-header-references header))) (setq ref parent-id) (while (and ref - (setq ref-dep (intern-soft ref dependencies)) - (boundp ref-dep) - (setq ref-header (car (symbol-value ref-dep)))) + (setq ref-dep (gethash ref dependencies)) + (setq ref-header (car-safe ref-dep))) (if (string= id ref) ;; Yuk! This is a reference loop. Make the article be a ;; root article. (progn - (mail-header-set-references (car (symbol-value id-dep)) "none") + (mail-header-set-references (car id-dep) "none") (setq ref nil) (setq parent-id nil)) (setq ref (gnus-parent-id (mail-header-references ref-header))))) - (setq ref-dep (intern (or parent-id "none") dependencies)) - (if (boundp ref-dep) - (setcdr (symbol-value ref-dep) - (nconc (cdr (symbol-value ref-dep)) - (list (symbol-value id-dep)))) - (set ref-dep (list nil (symbol-value id-dep))))) + (setq ref (or parent-id "none") + ref-dep (gethash ref dependencies)) + ;; Add `header' to its parent's list of children, creating that + ;; list if the parent isn't yet registered in the dependency + ;; table. + (if ref-dep + (setcdr (gethash ref dependencies) + (nconc (cdr ref-dep) + (list id-dep))) + (puthash ref (list nil id-dep) + dependencies))) header)) (defun gnus-extract-message-id-from-in-reply-to (string) @@ -4444,15 +4462,14 @@ Returns HEADER if it was entered in the DEPENDENCIES. Returns nil otherwise." ;; server, that is. (let ((mail-parse-charset gnus-newsgroup-charset) id heads) - (mapatoms - (lambda (refs) - (when (not (car (symbol-value refs))) - (setq heads (cdr (symbol-value refs))) + (maphash + (lambda (id refs) + (when (not (car refs)) + (setq heads (cdr refs)) (while heads (if (memq (mail-header-number (caar heads)) gnus-newsgroup-dormant) (setq heads (cdr heads)) - (setq id (symbol-name refs)) (while (and (setq id (gnus-build-get-header id)) (not (car (gnus-id-to-thread id))))) (setq heads nil))))) @@ -4733,7 +4750,7 @@ If LINE, insert the rebuilt thread starting on line LINE." (defun gnus-id-to-thread (id) "Return the (sub-)thread where ID appears." - (gnus-gethash id gnus-newsgroup-dependencies)) + (gethash id gnus-newsgroup-dependencies)) (defun gnus-id-to-article (id) "Return the article number of ID." @@ -5586,7 +5603,7 @@ If SELECT-ARTICLES, only select those articles from GROUP." (if (eq (car (gnus-find-method-for-group group)) 'nnvirtual) t gnus-summary-ignore-duplicates)) - (info (nth 2 entry)) + (info (nth 1 entry)) charset articles fetched-articles cached) (unless (gnus-check-server @@ -5605,7 +5622,7 @@ If SELECT-ARTICLES, only select those articles from GROUP." (decode-coding-string group charset) (decode-coding-string (gnus-status-message group) charset)))) - (unless (gnus-request-group group t nil (gnus-get-info group)) + (unless (gnus-request-group group t nil info) (when (derived-mode-p 'gnus-summary-mode) (gnus-kill-buffer (current-buffer))) (error "Couldn't request group %s: %s" @@ -6208,9 +6225,9 @@ The resulting hash table is returned, or nil if no Xrefs were found." (setq number (string-to-number (substring xrefs (match-beginning 2) (match-end 2)))) - (if (setq entry (gnus-gethash group xref-hashtb)) + (if (setq entry (gethash group xref-hashtb)) (setcdr entry (cons number (cdr entry))) - (gnus-sethash group (cons number nil) xref-hashtb))))) + (puthash group (cons number nil) xref-hashtb))))) (and start xref-hashtb))) (defun gnus-mark-xrefs-as-read (from-newsgroup headers unreads) @@ -6220,10 +6237,9 @@ The resulting hash table is returned, or nil if no Xrefs were found." (with-current-buffer gnus-group-buffer (when (setq xref-hashtb (gnus-create-xref-hashtb from-newsgroup headers unreads)) - (mapatoms - (lambda (group) - (unless (string= from-newsgroup (setq name (symbol-name group))) - (setq idlist (symbol-value group)) + (maphash + (lambda (group idlist) + (unless (string= from-newsgroup group) ;; Dead groups are not updated. (and (prog1 (setq info (gnus-get-info name)) @@ -6249,7 +6265,7 @@ The resulting hash table is returned, or nil if no Xrefs were found." (defun gnus-compute-read-articles (group articles) (let* ((entry (gnus-group-entry group)) - (info (nth 2 entry)) + (info (nth 1 entry)) (active (gnus-active group)) ninfo) (when entry @@ -6286,7 +6302,7 @@ The resulting hash table is returned, or nil if no Xrefs were found." "Update the info of GROUP to say that ARTICLES are read." (let* ((num 0) (entry (gnus-group-entry group)) - (info (nth 2 entry)) + (info (nth 1 entry)) (active (gnus-active group)) (set-marks (gnus-method-option-p @@ -8848,11 +8864,11 @@ fetch-old-headers verbiage, and so on." (null gnus-thread-expunge-below))) (push gnus-newsgroup-limit gnus-newsgroup-limits) (setq gnus-newsgroup-limit nil) - (mapatoms - (lambda (node) - (unless (car (symbol-value node)) + (maphash + (lambda (id deps) + (unless (car deps) ;; These threads have no parents -- they are roots. - (let ((nodes (cdr (symbol-value node))) + (let ((nodes (cdr deps)) thread) (while nodes (if (and gnus-thread-expunge-below @@ -12288,12 +12304,11 @@ save those articles instead." (nreverse split-name))) (defun gnus-valid-move-group-p (group) - (and (symbolp group) - (boundp group) - (symbol-name group) - (symbol-value group) - (gnus-get-function (gnus-find-method-for-group - (symbol-name group)) 'request-accept-article t))) + (when (and (stringp group) + (null (string-empty-p group))) + (gnus-get-function (gnus-find-method-for-group + group) + 'request-accept-article t))) (defun gnus-read-move-group-name (prompt default articles prefix) "Read a group name." @@ -12304,27 +12319,24 @@ save those articles instead." (if (> (length articles) 1) (format "these %d articles" (length articles)) "this article"))) - valid-names + (valid-names + (seq-filter #'gnus-valid-move-group-p + (hash-table-keys gnus-active-hashtb))) (to-newsgroup - (progn - (mapatoms (lambda (g) - (when (gnus-valid-move-group-p g) - (push g valid-names))) - gnus-active-hashtb) - (cond - ((null split-name) - (gnus-group-completing-read - prom - valid-names - nil prefix nil default)) - ((= 1 (length split-name)) - (gnus-group-completing-read - prom - valid-names - nil prefix 'gnus-group-history (car split-name))) - (t - (gnus-completing-read - prom (nreverse split-name) nil nil 'gnus-group-history))))) + (cond + ((null split-name) + (gnus-group-completing-read + prom + valid-names + nil prefix nil default)) + ((= 1 (length split-name)) + (gnus-group-completing-read + prom + valid-names + nil prefix 'gnus-group-history (car split-name))) + (t + (gnus-completing-read + prom (nreverse split-name) nil nil 'gnus-group-history)))) (to-method (gnus-server-to-method (gnus-group-method to-newsgroup))) encoded) (when to-newsgroup |