Further GV/CL cleanups.
[bpt/emacs.git] / lisp / emacs-lisp / cl-extra.el
CommitLineData
bb3faf5b 1;;; cl-extra.el --- Common Lisp features, part 2 -*- lexical-binding: t -*-
fcd73769 2
bf350d6a 3;; Copyright (C) 1993, 2000-2012 Free Software Foundation, Inc.
fcd73769
RS
4
5;; Author: Dave Gillespie <daveg@synaptics.com>
fcd73769 6;; Keywords: extensions
bd78fa1d 7;; Package: emacs
fcd73769
RS
8
9;; This file is part of GNU Emacs.
10
d6cba7ae 11;; GNU Emacs is free software: you can redistribute it and/or modify
fcd73769 12;; it under the terms of the GNU General Public License as published by
d6cba7ae
GM
13;; the Free Software Foundation, either version 3 of the License, or
14;; (at your option) any later version.
fcd73769
RS
15
16;; GNU Emacs is distributed in the hope that it will be useful,
17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;; GNU General Public License for more details.
20
21;; You should have received a copy of the GNU General Public License
d6cba7ae 22;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
fcd73769 23
07b3798c 24;;; Commentary:
fcd73769
RS
25
26;; These are extensions to Emacs Lisp that provide a degree of
27;; Common Lisp compatibility, beyond what is already built-in
28;; in Emacs Lisp.
29;;
30;; This package was written by Dave Gillespie; it is a complete
31;; rewrite of Cesar Quiroz's original cl.el package of December 1986.
32;;
fcd73769
RS
33;; Bug reports, comments, and suggestions are welcome!
34
35;; This file contains portions of the Common Lisp extensions
36;; package which are autoloaded since they are relatively obscure.
37
07b3798c 38;;; Code:
fcd73769 39
7c1898a7 40(require 'cl-lib)
fcd73769 41
fcd73769
RS
42;;; Type coercion.
43
7ed162bc 44;;;###autoload
7c1898a7 45(defun cl-coerce (x type)
fcd73769 46 "Coerce OBJECT to type TYPE.
9ae5b0b9
JB
47TYPE is a Common Lisp type specifier.
48\n(fn OBJECT TYPE)"
fcd73769
RS
49 (cond ((eq type 'list) (if (listp x) x (append x nil)))
50 ((eq type 'vector) (if (vectorp x) x (vconcat x)))
51 ((eq type 'string) (if (stringp x) x (concat x)))
52 ((eq type 'array) (if (arrayp x) x (vconcat x)))
53 ((and (eq type 'character) (stringp x) (= (length x) 1)) (aref x 0))
7c1898a7 54 ((and (eq type 'character) (symbolp x)) (cl-coerce (symbol-name x) type))
fcd73769 55 ((eq type 'float) (float x))
7c1898a7 56 ((cl-typep x type) x)
fcd73769
RS
57 (t (error "Can't coerce %s to type %s" x type))))
58
59
60;;; Predicates.
61
7ed162bc 62;;;###autoload
7c1898a7 63(defun cl-equalp (x y)
4ea3cc0e 64 "Return t if two Lisp objects have similar structures and contents.
fcd73769
RS
65This is like `equal', except that it accepts numerically equal
66numbers of different types (float vs. integer), and also compares
67strings case-insensitively."
68 (cond ((eq x y) t)
69 ((stringp x)
70 (and (stringp y) (= (length x) (length y))
76f61009
EN
71 (or (string-equal x y)
72 (string-equal (downcase x) (downcase y))))) ; lazy but simple!
fcd73769
RS
73 ((numberp x)
74 (and (numberp y) (= x y)))
75 ((consp x)
7c1898a7 76 (while (and (consp x) (consp y) (cl-equalp (car x) (car y)))
e5b633cf 77 (setq x (cdr x) y (cdr y)))
7c1898a7 78 (and (not (consp x)) (cl-equalp x y)))
fcd73769
RS
79 ((vectorp x)
80 (and (vectorp y) (= (length x) (length y))
81 (let ((i (length x)))
82 (while (and (>= (setq i (1- i)) 0)
7c1898a7 83 (cl-equalp (aref x i) (aref y i))))
fcd73769
RS
84 (< i 0))))
85 (t (equal x y))))
86
87
88;;; Control structures.
89
7ed162bc 90;;;###autoload
bb3faf5b 91(defun cl--mapcar-many (cl-func cl-seqs)
fcd73769
RS
92 (if (cdr (cdr cl-seqs))
93 (let* ((cl-res nil)
94 (cl-n (apply 'min (mapcar 'length cl-seqs)))
95 (cl-i 0)
96 (cl-args (copy-sequence cl-seqs))
97 cl-p1 cl-p2)
98 (setq cl-seqs (copy-sequence cl-seqs))
99 (while (< cl-i cl-n)
100 (setq cl-p1 cl-seqs cl-p2 cl-args)
101 (while cl-p1
102 (setcar cl-p2
103 (if (consp (car cl-p1))
104 (prog1 (car (car cl-p1))
105 (setcar cl-p1 (cdr (car cl-p1))))
106 (aref (car cl-p1) cl-i)))
107 (setq cl-p1 (cdr cl-p1) cl-p2 (cdr cl-p2)))
abfb2fe6 108 (push (apply cl-func cl-args) cl-res)
fcd73769
RS
109 (setq cl-i (1+ cl-i)))
110 (nreverse cl-res))
111 (let ((cl-res nil)
112 (cl-x (car cl-seqs))
113 (cl-y (nth 1 cl-seqs)))
114 (let ((cl-n (min (length cl-x) (length cl-y)))
115 (cl-i -1))
116 (while (< (setq cl-i (1+ cl-i)) cl-n)
abfb2fe6 117 (push (funcall cl-func
7c1898a7
SM
118 (if (consp cl-x) (pop cl-x) (aref cl-x cl-i))
119 (if (consp cl-y) (pop cl-y) (aref cl-y cl-i)))
120 cl-res)))
fcd73769
RS
121 (nreverse cl-res))))
122
7ed162bc 123;;;###autoload
7c1898a7 124(defun cl-map (cl-type cl-func cl-seq &rest cl-rest)
9ae5b0b9
JB
125 "Map a FUNCTION across one or more SEQUENCEs, returning a sequence.
126TYPE is the sequence type to return.
127\n(fn TYPE FUNCTION SEQUENCE...)"
7c1898a7
SM
128 (let ((cl-res (apply 'cl-mapcar cl-func cl-seq cl-rest)))
129 (and cl-type (cl-coerce cl-res cl-type))))
fcd73769 130
7ed162bc 131;;;###autoload
7c1898a7 132(defun cl-maplist (cl-func cl-list &rest cl-rest)
9ae5b0b9 133 "Map FUNCTION to each sublist of LIST or LISTs.
fcd73769 134Like `mapcar', except applies to lists and their cdr's rather than to
9ae5b0b9
JB
135the elements themselves.
136\n(fn FUNCTION LIST...)"
fcd73769
RS
137 (if cl-rest
138 (let ((cl-res nil)
139 (cl-args (cons cl-list (copy-sequence cl-rest)))
140 cl-p)
141 (while (not (memq nil cl-args))
abfb2fe6 142 (push (apply cl-func cl-args) cl-res)
fcd73769 143 (setq cl-p cl-args)
abfb2fe6 144 (while cl-p (setcar cl-p (cdr (pop cl-p)) )))
fcd73769
RS
145 (nreverse cl-res))
146 (let ((cl-res nil))
147 (while cl-list
abfb2fe6 148 (push (funcall cl-func cl-list) cl-res)
fcd73769
RS
149 (setq cl-list (cdr cl-list)))
150 (nreverse cl-res))))
151
e10b9e32 152(defun cl-mapc (cl-func cl-seq &rest cl-rest)
9ae5b0b9
JB
153 "Like `mapcar', but does not accumulate values returned by the function.
154\n(fn FUNCTION SEQUENCE...)"
fcd73769 155 (if cl-rest
7c1898a7 156 (progn (apply 'cl-map nil cl-func cl-seq cl-rest)
cf6bc7c3 157 cl-seq)
e2b1c424 158 (mapc cl-func cl-seq)))
fcd73769 159
7ed162bc 160;;;###autoload
7c1898a7
SM
161(defun cl-mapl (cl-func cl-list &rest cl-rest)
162 "Like `cl-maplist', but does not accumulate values returned by the function.
9ae5b0b9 163\n(fn FUNCTION LIST...)"
fcd73769 164 (if cl-rest
7c1898a7 165 (apply 'cl-maplist cl-func cl-list cl-rest)
fcd73769
RS
166 (let ((cl-p cl-list))
167 (while cl-p (funcall cl-func cl-p) (setq cl-p (cdr cl-p)))))
168 cl-list)
169
7ed162bc 170;;;###autoload
7c1898a7 171(defun cl-mapcan (cl-func cl-seq &rest cl-rest)
9ae5b0b9
JB
172 "Like `mapcar', but nconc's together the values returned by the function.
173\n(fn FUNCTION SEQUENCE...)"
7c1898a7 174 (apply 'nconc (apply 'cl-mapcar cl-func cl-seq cl-rest)))
fcd73769 175
7ed162bc 176;;;###autoload
7c1898a7
SM
177(defun cl-mapcon (cl-func cl-list &rest cl-rest)
178 "Like `cl-maplist', but nconc's together the values returned by the function.
9ae5b0b9 179\n(fn FUNCTION LIST...)"
7c1898a7 180 (apply 'nconc (apply 'cl-maplist cl-func cl-list cl-rest)))
fcd73769 181
7ed162bc 182;;;###autoload
7c1898a7 183(defun cl-some (cl-pred cl-seq &rest cl-rest)
fcd73769 184 "Return true if PREDICATE is true of any element of SEQ or SEQs.
9ae5b0b9
JB
185If so, return the true (non-nil) value returned by PREDICATE.
186\n(fn PREDICATE SEQ...)"
fcd73769
RS
187 (if (or cl-rest (nlistp cl-seq))
188 (catch 'cl-some
7c1898a7 189 (apply 'cl-map nil
fcd73769
RS
190 (function (lambda (&rest cl-x)
191 (let ((cl-res (apply cl-pred cl-x)))
192 (if cl-res (throw 'cl-some cl-res)))))
193 cl-seq cl-rest) nil)
194 (let ((cl-x nil))
abfb2fe6 195 (while (and cl-seq (not (setq cl-x (funcall cl-pred (pop cl-seq))))))
fcd73769
RS
196 cl-x)))
197
7ed162bc 198;;;###autoload
7c1898a7 199(defun cl-every (cl-pred cl-seq &rest cl-rest)
9ae5b0b9
JB
200 "Return true if PREDICATE is true of every element of SEQ or SEQs.
201\n(fn PREDICATE SEQ...)"
fcd73769
RS
202 (if (or cl-rest (nlistp cl-seq))
203 (catch 'cl-every
7c1898a7 204 (apply 'cl-map nil
fcd73769
RS
205 (function (lambda (&rest cl-x)
206 (or (apply cl-pred cl-x) (throw 'cl-every nil))))
207 cl-seq cl-rest) t)
208 (while (and cl-seq (funcall cl-pred (car cl-seq)))
209 (setq cl-seq (cdr cl-seq)))
210 (null cl-seq)))
211
7ed162bc 212;;;###autoload
7c1898a7 213(defun cl-notany (cl-pred cl-seq &rest cl-rest)
9ae5b0b9
JB
214 "Return true if PREDICATE is false of every element of SEQ or SEQs.
215\n(fn PREDICATE SEQ...)"
7c1898a7 216 (not (apply 'cl-some cl-pred cl-seq cl-rest)))
fcd73769 217
7ed162bc 218;;;###autoload
7c1898a7 219(defun cl-notevery (cl-pred cl-seq &rest cl-rest)
9ae5b0b9
JB
220 "Return true if PREDICATE is false of some element of SEQ or SEQs.
221\n(fn PREDICATE SEQ...)"
7c1898a7 222 (not (apply 'cl-every cl-pred cl-seq cl-rest)))
fcd73769 223
7ed162bc 224;;;###autoload
bb3faf5b 225(defun cl--map-keymap-recursively (cl-func-rec cl-map &optional cl-base)
fcd73769 226 (or cl-base
61255981 227 (setq cl-base (copy-sequence [0])))
09dae035 228 (map-keymap
fcd73769
RS
229 (function
230 (lambda (cl-key cl-bind)
231 (aset cl-base (1- (length cl-base)) cl-key)
232 (if (keymapp cl-bind)
bb3faf5b 233 (cl--map-keymap-recursively
fcd73769 234 cl-func-rec cl-bind
61255981 235 (vconcat cl-base (list 0)))
fcd73769
RS
236 (funcall cl-func-rec cl-base cl-bind))))
237 cl-map))
238
7ed162bc 239;;;###autoload
bb3faf5b 240(defun cl--map-intervals (cl-func &optional cl-what cl-prop cl-start cl-end)
fcd73769
RS
241 (or cl-what (setq cl-what (current-buffer)))
242 (if (bufferp cl-what)
243 (let (cl-mark cl-mark2 (cl-next t) cl-next2)
cf6bc7c3 244 (with-current-buffer cl-what
fcd73769
RS
245 (setq cl-mark (copy-marker (or cl-start (point-min))))
246 (setq cl-mark2 (and cl-end (copy-marker cl-end))))
247 (while (and cl-next (or (not cl-mark2) (< cl-mark cl-mark2)))
cf6bc7c3
DL
248 (setq cl-next (if cl-prop (next-single-property-change
249 cl-mark cl-prop cl-what)
250 (next-property-change cl-mark cl-what))
251 cl-next2 (or cl-next (with-current-buffer cl-what
252 (point-max))))
fcd73769
RS
253 (funcall cl-func (prog1 (marker-position cl-mark)
254 (set-marker cl-mark cl-next2))
255 (if cl-mark2 (min cl-next2 cl-mark2) cl-next2)))
256 (set-marker cl-mark nil) (if cl-mark2 (set-marker cl-mark2 nil)))
257 (or cl-start (setq cl-start 0))
258 (or cl-end (setq cl-end (length cl-what)))
259 (while (< cl-start cl-end)
cf6bc7c3
DL
260 (let ((cl-next (or (if cl-prop (next-single-property-change
261 cl-start cl-prop cl-what)
262 (next-property-change cl-start cl-what))
fcd73769
RS
263 cl-end)))
264 (funcall cl-func cl-start (min cl-next cl-end))
265 (setq cl-start cl-next)))))
266
7ed162bc 267;;;###autoload
bb3faf5b 268(defun cl--map-overlays (cl-func &optional cl-buffer cl-start cl-end cl-arg)
fcd73769
RS
269 (or cl-buffer (setq cl-buffer (current-buffer)))
270 (if (fboundp 'overlay-lists)
271
272 ;; This is the preferred algorithm, though overlay-lists is undocumented.
273 (let (cl-ovl)
cf6bc7c3 274 (with-current-buffer cl-buffer
fcd73769
RS
275 (setq cl-ovl (overlay-lists))
276 (if cl-start (setq cl-start (copy-marker cl-start)))
277 (if cl-end (setq cl-end (copy-marker cl-end))))
278 (setq cl-ovl (nconc (car cl-ovl) (cdr cl-ovl)))
279 (while (and cl-ovl
280 (or (not (overlay-start (car cl-ovl)))
281 (and cl-end (>= (overlay-start (car cl-ovl)) cl-end))
282 (and cl-start (<= (overlay-end (car cl-ovl)) cl-start))
283 (not (funcall cl-func (car cl-ovl) cl-arg))))
284 (setq cl-ovl (cdr cl-ovl)))
285 (if cl-start (set-marker cl-start nil))
286 (if cl-end (set-marker cl-end nil)))
287
288 ;; This alternate algorithm fails to find zero-length overlays.
cf6bc7c3
DL
289 (let ((cl-mark (with-current-buffer cl-buffer
290 (copy-marker (or cl-start (point-min)))))
291 (cl-mark2 (and cl-end (with-current-buffer cl-buffer
292 (copy-marker cl-end))))
fcd73769
RS
293 cl-pos cl-ovl)
294 (while (save-excursion
295 (and (setq cl-pos (marker-position cl-mark))
296 (< cl-pos (or cl-mark2 (point-max)))
297 (progn
298 (set-buffer cl-buffer)
299 (setq cl-ovl (overlays-at cl-pos))
300 (set-marker cl-mark (next-overlay-change cl-pos)))))
301 (while (and cl-ovl
302 (or (/= (overlay-start (car cl-ovl)) cl-pos)
303 (not (and (funcall cl-func (car cl-ovl) cl-arg)
304 (set-marker cl-mark nil)))))
305 (setq cl-ovl (cdr cl-ovl))))
306 (set-marker cl-mark nil) (if cl-mark2 (set-marker cl-mark2 nil)))))
307
2ee3d7f0 308;;; Support for `setf'.
7ed162bc 309;;;###autoload
bb3faf5b 310(defun cl--set-frame-visible-p (frame val)
fcd73769
RS
311 (cond ((null val) (make-frame-invisible frame))
312 ((eq val 'icon) (iconify-frame frame))
313 (t (make-frame-visible frame)))
314 val)
315
7c1898a7 316;;; Support for `cl-progv'.
bb3faf5b 317(defvar cl--progv-save)
7ed162bc 318;;;###autoload
bb3faf5b 319(defun cl--progv-before (syms values)
fcd73769 320 (while syms
abfb2fe6 321 (push (if (boundp (car syms))
fcd73769 322 (cons (car syms) (symbol-value (car syms)))
bb3faf5b 323 (car syms)) cl--progv-save)
fcd73769 324 (if values
abfb2fe6
SM
325 (set (pop syms) (pop values))
326 (makunbound (pop syms)))))
fcd73769 327
bb3faf5b
SM
328(defun cl--progv-after ()
329 (while cl--progv-save
330 (if (consp (car cl--progv-save))
331 (set (car (car cl--progv-save)) (cdr (car cl--progv-save)))
332 (makunbound (car cl--progv-save)))
333 (pop cl--progv-save)))
fcd73769
RS
334
335
336;;; Numbers.
337
7ed162bc 338;;;###autoload
7c1898a7 339(defun cl-gcd (&rest args)
fcd73769 340 "Return the greatest common divisor of the arguments."
abfb2fe6 341 (let ((a (abs (or (pop args) 0))))
fcd73769 342 (while args
abfb2fe6 343 (let ((b (abs (pop args))))
fcd73769
RS
344 (while (> b 0) (setq b (% a (setq a b))))))
345 a))
346
7ed162bc 347;;;###autoload
7c1898a7 348(defun cl-lcm (&rest args)
fcd73769
RS
349 "Return the least common multiple of the arguments."
350 (if (memq 0 args)
351 0
abfb2fe6 352 (let ((a (abs (or (pop args) 1))))
fcd73769 353 (while args
abfb2fe6 354 (let ((b (abs (pop args))))
7c1898a7 355 (setq a (* (/ a (cl-gcd a b)) b))))
fcd73769
RS
356 a)))
357
7ed162bc 358;;;###autoload
7c1898a7 359(defun cl-isqrt (x)
fcd73769 360 "Return the integer square root of the argument."
9ae5b0b9
JB
361 (if (and (integerp x) (> x 0))
362 (let ((g (cond ((<= x 100) 10) ((<= x 10000) 100)
363 ((<= x 1000000) 1000) (t x)))
fcd73769 364 g2)
9ae5b0b9 365 (while (< (setq g2 (/ (+ g (/ x g)) 2)) g)
fcd73769
RS
366 (setq g g2))
367 g)
9ae5b0b9 368 (if (eq x 0) 0 (signal 'arith-error nil))))
fcd73769 369
7ed162bc 370;;;###autoload
7c1898a7 371(defun cl-floor (x &optional y)
fcd73769
RS
372 "Return a list of the floor of X and the fractional part of X.
373With two arguments, return floor and remainder of their quotient."
ebe6b814
PE
374 (let ((q (floor x y)))
375 (list q (- x (if y (* y q) q)))))
fcd73769 376
7ed162bc 377;;;###autoload
7c1898a7 378(defun cl-ceiling (x &optional y)
fcd73769
RS
379 "Return a list of the ceiling of X and the fractional part of X.
380With two arguments, return ceiling and remainder of their quotient."
7c1898a7 381 (let ((res (cl-floor x y)))
fcd73769
RS
382 (if (= (car (cdr res)) 0) res
383 (list (1+ (car res)) (- (car (cdr res)) (or y 1))))))
384
7ed162bc 385;;;###autoload
7c1898a7 386(defun cl-truncate (x &optional y)
fcd73769
RS
387 "Return a list of the integer part of X and the fractional part of X.
388With two arguments, return truncation and remainder of their quotient."
389 (if (eq (>= x 0) (or (null y) (>= y 0)))
7c1898a7 390 (cl-floor x y) (cl-ceiling x y)))
fcd73769 391
7ed162bc 392;;;###autoload
7c1898a7 393(defun cl-round (x &optional y)
fcd73769
RS
394 "Return a list of X rounded to the nearest integer and the remainder.
395With two arguments, return rounding and remainder of their quotient."
396 (if y
397 (if (and (integerp x) (integerp y))
398 (let* ((hy (/ y 2))
7c1898a7 399 (res (cl-floor (+ x hy) y)))
fcd73769
RS
400 (if (and (= (car (cdr res)) 0)
401 (= (+ hy hy) y)
402 (/= (% (car res) 2) 0))
403 (list (1- (car res)) hy)
404 (list (car res) (- (car (cdr res)) hy))))
405 (let ((q (round (/ x y))))
406 (list q (- x (* q y)))))
407 (if (integerp x) (list x 0)
408 (let ((q (round x)))
409 (list q (- x q))))))
410
7ed162bc 411;;;###autoload
7c1898a7 412(defun cl-mod (x y)
fcd73769 413 "The remainder of X divided by Y, with the same sign as Y."
7c1898a7 414 (nth 1 (cl-floor x y)))
fcd73769 415
7ed162bc 416;;;###autoload
7c1898a7 417(defun cl-rem (x y)
fcd73769 418 "The remainder of X divided by Y, with the same sign as X."
7c1898a7 419 (nth 1 (cl-truncate x y)))
fcd73769 420
7ed162bc 421;;;###autoload
7c1898a7 422(defun cl-signum (x)
9ae5b0b9
JB
423 "Return 1 if X is positive, -1 if negative, 0 if zero."
424 (cond ((> x 0) 1) ((< x 0) -1) (t 0)))
fcd73769
RS
425
426
427;; Random numbers.
428
7ed162bc 429;;;###autoload
7c1898a7 430(defun cl-random (lim &optional state)
fcd73769
RS
431 "Return a random nonnegative number less than LIM, an integer or float.
432Optional second arg STATE is a random-state object."
4735906a 433 (or state (setq state cl--random-state))
fcd73769
RS
434 ;; Inspired by "ran3" from Numerical Recipes. Additive congruential method.
435 (let ((vec (aref state 3)))
436 (if (integerp vec)
7ed162bc 437 (let ((i 0) (j (- 1357335 (% (abs vec) 1357333))) (k 1))
fcd73769
RS
438 (aset state 3 (setq vec (make-vector 55 nil)))
439 (aset vec 0 j)
440 (while (> (setq i (% (+ i 21) 55)) 0)
441 (aset vec i (setq j (prog1 k (setq k (- j k))))))
7c1898a7 442 (while (< (setq i (1+ i)) 200) (cl-random 2 state))))
fcd73769
RS
443 (let* ((i (aset state 1 (% (1+ (aref state 1)) 55)))
444 (j (aset state 2 (% (1+ (aref state 2)) 55)))
445 (n (logand 8388607 (aset vec i (- (aref vec i) (aref vec j))))))
446 (if (integerp lim)
447 (if (<= lim 512) (% n lim)
7c1898a7 448 (if (> lim 8388607) (setq n (+ (lsh n 9) (cl-random 512 state))))
fcd73769
RS
449 (let ((mask 1023))
450 (while (< mask (1- lim)) (setq mask (1+ (+ mask mask))))
7c1898a7 451 (if (< (setq n (logand n mask)) lim) n (cl-random lim state))))
fcd73769
RS
452 (* (/ n '8388608e0) lim)))))
453
7ed162bc 454;;;###autoload
7c1898a7 455(defun cl-make-random-state (&optional state)
4735906a 456 "Return a copy of random-state STATE, or of the internal state if omitted.
fcd73769 457If STATE is t, return a new state object seeded from the time of day."
7c1898a7 458 (cond ((null state) (cl-make-random-state cl--random-state))
6fa6c4ae 459 ((vectorp state) (copy-tree state t))
fcd73769 460 ((integerp state) (vector 'cl-random-state-tag -1 30 state))
7c1898a7 461 (t (cl-make-random-state (cl-random-time)))))
fcd73769 462
7ed162bc 463;;;###autoload
7c1898a7 464(defun cl-random-state-p (object)
fcd73769
RS
465 "Return t if OBJECT is a random-state object."
466 (and (vectorp object) (= (length object) 4)
467 (eq (aref object 0) 'cl-random-state-tag)))
468
469
470;; Implementation limits.
471
bb3faf5b
SM
472(defun cl--finite-do (func a b)
473 (condition-case _
fcd73769
RS
474 (let ((res (funcall func a b))) ; check for IEEE infinity
475 (and (numberp res) (/= res (/ res 2)) res))
476 (arith-error nil)))
477
7ed162bc 478;;;###autoload
fcd73769 479(defun cl-float-limits ()
416a2c45 480 "Initialize the Common Lisp floating-point parameters.
7c1898a7
SM
481This sets the values of: `cl-most-positive-float', `cl-most-negative-float',
482`cl-least-positive-float', `cl-least-negative-float', `cl-float-epsilon',
483`cl-float-negative-epsilon', `cl-least-positive-normalized-float', and
484`cl-least-negative-normalized-float'."
485 (or cl-most-positive-float (not (numberp '2e1))
fcd73769
RS
486 (let ((x '2e0) y z)
487 ;; Find maximum exponent (first two loops are optimizations)
bb3faf5b
SM
488 (while (cl--finite-do '* x x) (setq x (* x x)))
489 (while (cl--finite-do '* x (/ x 2)) (setq x (* x (/ x 2))))
490 (while (cl--finite-do '+ x x) (setq x (+ x x)))
fcd73769 491 (setq z x y (/ x 2))
7c1898a7 492 ;; Now cl-fill in 1's in the mantissa.
bb3faf5b 493 (while (and (cl--finite-do '+ x y) (/= (+ x y) x))
fcd73769 494 (setq x (+ x y) y (/ y 2)))
7c1898a7
SM
495 (setq cl-most-positive-float x
496 cl-most-negative-float (- x))
fcd73769
RS
497 ;; Divide down until mantissa starts rounding.
498 (setq x (/ x z) y (/ 16 z) x (* x y))
bb3faf5b 499 (while (condition-case _ (and (= x (* (/ x 2) 2)) (> (/ y 2) 0))
fcd73769
RS
500 (arith-error nil))
501 (setq x (/ x 2) y (/ y 2)))
7c1898a7
SM
502 (setq cl-least-positive-normalized-float y
503 cl-least-negative-normalized-float (- y))
fcd73769
RS
504 ;; Divide down until value underflows to zero.
505 (setq x (/ 1 z) y x)
bb3faf5b 506 (while (condition-case _ (> (/ x 2) 0) (arith-error nil))
fcd73769 507 (setq x (/ x 2)))
7c1898a7
SM
508 (setq cl-least-positive-float x
509 cl-least-negative-float (- x))
fcd73769
RS
510 (setq x '1e0)
511 (while (/= (+ '1e0 x) '1e0) (setq x (/ x 2)))
7c1898a7 512 (setq cl-float-epsilon (* x 2))
fcd73769
RS
513 (setq x '1e0)
514 (while (/= (- '1e0 x) '1e0) (setq x (/ x 2)))
7c1898a7 515 (setq cl-float-negative-epsilon (* x 2))))
fcd73769
RS
516 nil)
517
518
519;;; Sequence functions.
520
7ed162bc 521;;;###autoload
7c1898a7 522(defun cl-subseq (seq start &optional end)
fcd73769
RS
523 "Return the subsequence of SEQ from START to END.
524If END is omitted, it defaults to the length of the sequence.
525If START or END is negative, it counts from the end."
36cec983
SM
526 (declare (gv-setter
527 (lambda (new)
528 `(progn (cl-replace ,seq ,new :start1 ,start :end1 ,end)
529 ,new))))
fcd73769
RS
530 (if (stringp seq) (substring seq start end)
531 (let (len)
532 (and end (< end 0) (setq end (+ end (setq len (length seq)))))
533 (if (< start 0) (setq start (+ start (or len (setq len (length seq))))))
534 (cond ((listp seq)
535 (if (> start 0) (setq seq (nthcdr start seq)))
536 (if end
537 (let ((res nil))
538 (while (>= (setq end (1- end)) start)
abfb2fe6 539 (push (pop seq) res))
fcd73769
RS
540 (nreverse res))
541 (copy-sequence seq)))
542 (t
543 (or end (setq end (or len (length seq))))
544 (let ((res (make-vector (max (- end start) 0) nil))
545 (i 0))
546 (while (< start end)
547 (aset res i (aref seq start))
548 (setq i (1+ i) start (1+ start)))
549 res))))))
550
7ed162bc 551;;;###autoload
7c1898a7 552(defun cl-concatenate (type &rest seqs)
9ae5b0b9
JB
553 "Concatenate, into a sequence of type TYPE, the argument SEQUENCEs.
554\n(fn TYPE SEQUENCE...)"
fcd73769
RS
555 (cond ((eq type 'vector) (apply 'vconcat seqs))
556 ((eq type 'string) (apply 'concat seqs))
557 ((eq type 'list) (apply 'append (append seqs '(nil))))
558 (t (error "Not a sequence type name: %s" type))))
559
560
561;;; List functions.
562
7ed162bc 563;;;###autoload
7c1898a7 564(defun cl-revappend (x y)
fcd73769
RS
565 "Equivalent to (append (reverse X) Y)."
566 (nconc (reverse x) y))
567
7ed162bc 568;;;###autoload
7c1898a7 569(defun cl-nreconc (x y)
fcd73769
RS
570 "Equivalent to (nconc (nreverse X) Y)."
571 (nconc (nreverse x) y))
572
7ed162bc 573;;;###autoload
7c1898a7 574(defun cl-list-length (x)
9ae5b0b9 575 "Return the length of list X. Return nil if list is circular."
fcd73769
RS
576 (let ((n 0) (fast x) (slow x))
577 (while (and (cdr fast) (not (and (eq fast slow) (> n 0))))
578 (setq n (+ n 2) fast (cdr (cdr fast)) slow (cdr slow)))
579 (if fast (if (cdr fast) nil (1+ n)) n)))
580
7ed162bc 581;;;###autoload
7c1898a7 582(defun cl-tailp (sublist list)
fcd73769
RS
583 "Return true if SUBLIST is a tail of LIST."
584 (while (and (consp list) (not (eq sublist list)))
585 (setq list (cdr list)))
586 (if (numberp sublist) (equal sublist list) (eq sublist list)))
587
fcd73769
RS
588;;; Property lists.
589
7ed162bc 590;;;###autoload
d9857e53 591(defun cl-get (sym tag &optional def)
9ae5b0b9
JB
592 "Return the value of SYMBOL's PROPNAME property, or DEFAULT if none.
593\n(fn SYMBOL PROPNAME &optional DEFAULT)"
36cec983
SM
594 (declare (compiler-macro cl--compiler-macro-get)
595 (gv-setter (lambda (store) `(put ,sym ,tag ,store))))
fcd73769
RS
596 (or (get sym tag)
597 (and def
2ee3d7f0 598 ;; Make sure `def' is really absent as opposed to set to nil.
fcd73769
RS
599 (let ((plist (symbol-plist sym)))
600 (while (and plist (not (eq (car plist) tag)))
601 (setq plist (cdr (cdr plist))))
602 (if plist (car (cdr plist)) def)))))
d9857e53 603(autoload 'cl--compiler-macro-get "cl-macs")
fcd73769 604
7ed162bc 605;;;###autoload
7c1898a7 606(defun cl-getf (plist tag &optional def)
fcd73769 607 "Search PROPLIST for property PROPNAME; return its value or DEFAULT.
9ae5b0b9
JB
608PROPLIST is a list of the sort returned by `symbol-plist'.
609\n(fn PROPLIST PROPNAME &optional DEFAULT)"
36cec983
SM
610 (declare (gv-expander
611 (lambda (do)
612 (gv-letplace (getter setter) plist
613 (macroexp-let2 nil k tag
614 (macroexp-let2 nil d def
615 (funcall do `(cl-getf ,getter ,k ,d)
616 (lambda (v)
617 (funcall setter
618 `(cl--set-getf ,getter ,k ,v))))))))))
fcd73769
RS
619 (setplist '--cl-getf-symbol-- plist)
620 (or (get '--cl-getf-symbol-- tag)
7c1898a7
SM
621 ;; Originally we called cl-get here,
622 ;; but that fails, because cl-get has a compiler macro
318f417c
KH
623 ;; definition that uses getf!
624 (when def
2ee3d7f0 625 ;; Make sure `def' is really absent as opposed to set to nil.
318f417c
KH
626 (while (and plist (not (eq (car plist) tag)))
627 (setq plist (cdr (cdr plist))))
628 (if plist (car (cdr plist)) def))))
fcd73769 629
7ed162bc 630;;;###autoload
bb3faf5b 631(defun cl--set-getf (plist tag val)
fcd73769
RS
632 (let ((p plist))
633 (while (and p (not (eq (car p) tag))) (setq p (cdr (cdr p))))
7c1898a7 634 (if p (progn (setcar (cdr p) val) plist) (cl-list* tag val plist))))
fcd73769 635
7ed162bc 636;;;###autoload
bb3faf5b 637(defun cl--do-remf (plist tag)
fcd73769
RS
638 (let ((p (cdr plist)))
639 (while (and (cdr p) (not (eq (car (cdr p)) tag))) (setq p (cdr (cdr p))))
640 (and (cdr p) (progn (setcdr p (cdr (cdr (cdr p)))) t))))
641
7ed162bc 642;;;###autoload
fcd73769 643(defun cl-remprop (sym tag)
9ae5b0b9
JB
644 "Remove from SYMBOL's plist the property PROPNAME and its value.
645\n(fn SYMBOL PROPNAME)"
fcd73769
RS
646 (let ((plist (symbol-plist sym)))
647 (if (and plist (eq tag (car plist)))
648 (progn (setplist sym (cdr (cdr plist))) t)
bb3faf5b 649 (cl--do-remf plist tag))))
fcd73769 650
fcd73769
RS
651;;; Some debugging aids.
652
653(defun cl-prettyprint (form)
654 "Insert a pretty-printed rendition of a Lisp FORM in current buffer."
655 (let ((pt (point)) last)
656 (insert "\n" (prin1-to-string form) "\n")
657 (setq last (point))
658 (goto-char (1+ pt))
659 (while (search-forward "(quote " last t)
d355a0b7 660 (delete-char -7)
fcd73769
RS
661 (insert "'")
662 (forward-sexp)
663 (delete-char 1))
664 (goto-char (1+ pt))
bb3faf5b 665 (cl--do-prettyprint)))
fcd73769 666
bb3faf5b 667(defun cl--do-prettyprint ()
fcd73769
RS
668 (skip-chars-forward " ")
669 (if (looking-at "(")
670 (let ((skip (or (looking-at "((") (looking-at "(prog")
671 (looking-at "(unwind-protect ")
672 (looking-at "(function (")
bb3faf5b 673 (looking-at "(cl--block-wrapper ")))
fcd73769
RS
674 (two (or (looking-at "(defun ") (looking-at "(defmacro ")))
675 (let (or (looking-at "(let\\*? ") (looking-at "(while ")))
676 (set (looking-at "(p?set[qf] ")))
677 (if (or skip let
678 (progn
679 (forward-sexp)
680 (and (>= (current-column) 78) (progn (backward-sexp) t))))
681 (let ((nl t))
682 (forward-char 1)
bb3faf5b
SM
683 (cl--do-prettyprint)
684 (or skip (looking-at ")") (cl--do-prettyprint))
685 (or (not two) (looking-at ")") (cl--do-prettyprint))
fcd73769
RS
686 (while (not (looking-at ")"))
687 (if set (setq nl (not nl)))
688 (if nl (insert "\n"))
689 (lisp-indent-line)
bb3faf5b 690 (cl--do-prettyprint))
fcd73769
RS
691 (forward-char 1))))
692 (forward-sexp)))
693
7ed162bc 694;;;###autoload
fcd73769
RS
695(defun cl-prettyexpand (form &optional full)
696 (message "Expanding...")
bb3faf5b 697 (let ((cl--compiling-file full)
fcd73769 698 (byte-compile-macro-environment nil))
6fa6c4ae
SM
699 (setq form (macroexpand-all form
700 (and (not full) '((cl-block) (cl-eval-when)))))
fcd73769
RS
701 (message "Formatting...")
702 (prog1 (cl-prettyprint form)
703 (message ""))))
704
705
706
707(run-hooks 'cl-extra-load-hook)
708
7ed162bc 709;; Local variables:
91677576
GM
710;; byte-compile-dynamic: t
711;; byte-compile-warnings: (not cl-functions)
7ed162bc
SM
712;; generated-autoload-file: "cl-loaddefs.el"
713;; End:
714
fcd73769 715;;; cl-extra.el ends here