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