From: marca@ncsa.uiuc.edu (Marc Andreessen)
Subject: Re: GNUS need not be slow (Source announcement)
X-Md4-Signature: 358a885fa9be05b41a7776b135b85310
Organization: Nat'l Center for Supercomputing Applications
Date: Sat, 19 Dec 1992 11:47:25 GMT

People not yet familiar with the gnus-speedup code previously posted
more than once may want to try it first.  I have no idea how it
compares with Scott's new code, but it does speed up stock GNUS quite
a bit and is trivial to install.  Here 'tis:

;; gnus-speedups|Felix Lee|flee@cs.psu.edu
;; |Simple performance enhancements for GNUS
;; |1992-05-18|1.2: stable||

;; This package contains two plug-compatible performance enhancements
;; for GNUS 3.13 and 3.14:

;; 1. A faster version of gnus-find-new-newsgroups, for making GNUS
;; start more quickly.

;; 2. Faster subject and date sorting in the *Subject* buffer.

;; This file must be loaded after "gnus.el".  You can do this by
;; adding '(load "gnus-speedups") at the end of your local gnus
;; wrapper, or at the end of "gnus.el".  Or you could just include
;; this file directly.

(require 'gnus)

;;;;;
;; 1. A faster version of gnus-find-new-newsgroups.

;; We reduce an O(N**2) process to O(N) by building a hash table for
;; the list of known newsgroups.  (It's a little strange that GNUS
;; doesn't already have a hash table for this.)

(defun gnus-find-new-newsgroups ()
  "Look for new newsgroups and return names.
`-n' option of options line in .newsrc file is recognized."
  (let ( (group nil)
	 (new-groups nil)
	 (known-groups (gnus-make-hashtable)) )
    ;; Build a table of known newsgroups.
    (mapcar
     (function (lambda (group) (gnus-sethash (car group) t known-groups)))
     gnus-killed-assoc)
    (mapcar
     (function (lambda (group) (gnus-sethash (car group) t known-groups)))
     gnus-newsrc-assoc)
    ;; Compare the active file against what's known.
    (mapatoms
     (function
      (lambda (sym)
	(setq group (symbol-name sym))
	;; Take into account the -n option.
	(and (or (null gnus-newsrc-options-n-no)
		 (not (string-match gnus-newsrc-options-n-no group))
		 (and gnus-newsrc-options-n-yes
		      (string-match gnus-newsrc-options-n-yes group)))
	     (null (gnus-gethash group known-groups))
	     (setq new-groups (cons group new-groups)))
	))
     gnus-active-hashtb)
    new-groups
    ))


;;;;;
;; 2. Faster subject and date sorting in the *Subject* buffer.

;; The basic idea is explained in 'gnus-keyed-sort.

;; Sample hook usage:
;; (setq gnus-Select-group-hook
;;	 (function
;;	  (lambda ()
;;	    (gnus-keyed-sort-headers
;;	     (function gnus-string-lessp)
;;	     (function (lambda (it) (gnus-simplify-subject it 're-only))))
;;	    )))

(defun gnus-keyed-sort (list compare extract)
  "Sort LIST stably and return the sorted list.  Does not modify LIST.
Arguments are (LIST COMPARE EXTRACT).  Elements in the list are
compared as if the predicate were:
	(COMPARE (EXTRACT a) (EXTRACT b))
but EXTRACT is run over each element of the list in a preprocessing
stage for efficiency.  This reduces the number of EXTRACT calls from
O(N log N) to O(N).

Example: (gnus-keyed-sort load-path 'string< 'downcase)
"
  (let ( (keyed-list
	  (mapcar
	   (function (lambda (it) (cons (funcall extract it) it)))
	   list)) )
    (setq keyed-list
	  (sort keyed-list
		(function
		 (lambda (a b) (funcall compare (car a) (car b))))))
    (mapcar (function (lambda (it) (cdr it)))
	    keyed-list)
    ))

(defun gnus-keyed-sort-headers (compare extract)
  "Sort current group's headers by COMPARE and EXTRACT.  Sorting is
done as if the predicate were
	(COMPARE (EXTRACT a) (EXTRACT b))
See 'gnus-keyed-sort for details.
Note: interrupting the sort leaves the headers unsorted.
"
  (setq gnus-newsgroup-headers
	(gnus-keyed-sort
	 gnus-newsgroup-headers
	 compare extract)))

(defun gnus-Subject-keyed-sort-subjects (compare extract &optional reverse)
  "Sort and redisplay the *Subject* buffer by COMPARE and EXTRACT.
Calls 'gnus-keyed-sort-headers to do the sorting.  Optional argument
REVERSE means to do an 'nreverse after sorting.
"
  (let ( (current (gnus-Subject-article-number)) )
    (gnus-keyed-sort-headers compare extract)
    (if reverse
	(setq gnus-newsgroup-headers (nreverse gnus-newsgroup-headers)))
    (gnus-Subject-prepare)
    (gnus-Subject-goto-subject current)
    ))

;; XXX It should be 'gnus-sort-fold-case, not 'case-fold-search
(defun gnus-Subject-sort-by-subject (reverse)
  "Sort *Subject* buffer by subject alphabetically.  Argument REVERSE
means reverse order.  \"Re:\"s are ignored.  If 'case-fold-search, then
case of letters will be ignored.
"
  (interactive "P")
  ;; The main complication here is we try to speed up the sort process
  ;; by hoisting conditions outside the sort.
  (gnus-Subject-keyed-sort-subjects
   'string<
   (if case-fold-search
       (function
	(lambda (it)
	  (downcase (gnus-simplify-subject (nntp-header-subject it) 're-only))))
     (function
      (lambda (it)
	(gnus-simplify-subject (nntp-header-subject it) 're-only)))
     )
   reverse)
  )

;; For backward compatibility with GNUS 3.13
(if (not (fboundp 'gnus-sortable-date))
    (fset 'gnus-sortable-date 'gnus-comparable-date))

(defun gnus-Subject-sort-by-date (reverse)
  "Sort *Subject* buffer by posted date.  Argument REVERSE means
reverse order."
  (interactive "P")
  (gnus-Subject-keyed-sort-subjects
   'string<
   (function
    (lambda (it)
      (gnus-sortable-date (nntp-header-date it))))
   reverse)
  )

Cheers,

Marc

--
Marc Andreessen
Software Development Group
National Center for Supercomputing Applications
marca@ncsa.uiuc.edu
Newsgroups: gnu.emacs.gnus