Coverage report: /home/ellis/comp/core/std/list.lisp
Kind | Covered | All | % |
expression | 51 | 828 | 6.2 |
branch | 7 | 156 | 4.5 |
Key
Not instrumented
Conditionalized out
Executed
Not executed
Both branches taken
One branch taken
Neither branch taken
1
;;; std/list.lisp --- List utils
6
(defun ensure-car (thing)
7
"If THING is a CONS, its CAR is returned. Otherwise THING is returned."
12
(defun ensure-cons (cons)
13
"If CONS is a cons, it is returned. Otherwise returns a fresh cons with CONS
14
in the car, and NIL in the cdr."
19
(define-modify-macro appendf (&rest lists) append
20
"Modify-macro for APPEND. Appends LISTS to the place designated by the first
23
(define-modify-macro nconcf (&rest lists) nconc
24
"Modify-macro for NCONC. Concatenates LISTS to place designated by the first
27
(define-modify-macro unionf (list &rest args) union
28
"Modify-macro for UNION. Saves the union of LIST and the contents of the
29
place designated by the first argument to the designated place.")
31
(define-modify-macro nunionf (list &rest args) nunion
32
"Modify-macro for NUNION. Saves the union of LIST and the contents of the
33
place designated by the first argument to the designated place. May modify
36
(define-modify-macro reversef () reverse
37
"Modify-macro for REVERSE. Copies and reverses the list stored in the given
38
place and saves back the result into the place.")
40
(define-modify-macro nreversef () nreverse
41
"Modify-macro for NREVERSE. Reverses the list stored in the given place by
42
destructively modifying it and saves back the result into the place.")
44
(declaim (inline remove/swapped-arguments))
45
(defun remove/swapped-arguments (sequence item &rest keyword-arguments)
46
(apply #'remove item sequence keyword-arguments))
48
(define-modify-macro removef (item &rest keyword-arguments)
49
remove/swapped-arguments
50
"Modify-macro for REMOVE. Sets place designated by the first argument to
51
the result of calling REMOVE with ITEM, place, and the KEYWORD-ARGUMENTS.")
53
(declaim (inline delete/swapped-arguments))
54
(defun delete/swapped-arguments (sequence item &rest keyword-arguments)
55
(apply #'delete item sequence keyword-arguments))
57
(define-modify-macro deletef (item &rest keyword-arguments)
58
delete/swapped-arguments
59
"Modify-macro for DELETE. Sets place designated by the first argument to
60
the result of calling DELETE with ITEM, place, and the KEYWORD-ARGUMENTS.")
62
(defun let-binding-transform (bs)
65
(cond ((symbolp (car bs))
70
(error "Bad let bindings")))
71
(let-binding-transform (cdr bs)))))
73
(defun circular-list (&rest elements)
74
"Creates a circular list of ELEMENTS."
75
(let ((cycle (copy-list elements)))
78
(defun circular-list-p (object)
79
"Returns true if OBJECT is a circular list, NIL otherwise."
81
(do ((fast object (cddr fast))
82
(slow (cons (car object) (cdr object)) (cdr slow)))
84
(unless (and (consp fast) (listp (cdr fast)))
89
(defun circular-tree-p (object)
90
"Returns true if OBJECT is a circular tree, NIL otherwise."
91
(labels ((circularp (object seen)
93
(do ((fast (cons (car object) (cdr object)) (cddr fast))
94
(slow object (cdr slow)))
96
(when (or (eq fast slow) (member slow seen))
97
(return-from circular-tree-p t))
98
(when (or (not (consp fast)) (not (consp (cdr slow))))
100
(do ((tail object (cdr tail)))
103
(let ((elt (car tail)))
104
(circularp elt (cons object seen))))))))))
105
(circularp object nil)))
108
(declaim (inline group))
109
(defun group (source n)
110
"Return a list of lists by grouping SOURCE into N-element batches."
112
(when (zerop n) (error "zero length"))
113
(labels ((rec (source acc)
114
(let ((rest (nthcdr n source)))
120
(cons source acc))))))
121
(if source (rec source nil) nil)))
123
(eval-when (:compile-toplevel :load-toplevel :execute)
125
"Flatten list X, removing nil elements."
138
(labels ((rec (x acc)
140
((typep x 'sb-impl::comma) (rec (sb-impl::comma-expr x) acc))
141
((atom x) (cons x acc))
144
(rec (cdr x) acc))))))
147
(eval-when (:compile-toplevel :load-toplevel :execute)
148
(defun zip-list (&rest args)
149
"Return a list of lists containing every member of ARGS at the same position."
150
(apply 'map 'list 'list args)))
152
(defun zip-tree (&rest args)
153
(if (and (some #'atom args) (some #'consp args)) nil
154
(if (every #'atom args) args
155
(apply #'mapcar #'zip-tree args))))
158
"Zips a unique gensym with each element of LST.
161
(zipsym '(a b c)) ;; ((#:G1064 A) (#:G1065 B) (#:G1066 C))"
162
(map 'list #'(lambda (x) (list (gensym) x)) lst))
164
(defun list-dimensions (lst)
166
(cons (length lst) (list-dimensions (car lst)))))
168
(defun recursive-append (&rest lsts)
169
"Append lists in a nested manner.
177
;; (LET ((X 1)) (+ X 2))"
178
(reduce #'(lambda (x y)
180
(if (typep (car y) 'symbol) y (car y))
181
(append x (and y (if (typep (car y) 'symbol) `(,y) y)))))
184
(defmacro ziprm (r m &rest args)
190
`(ziprm (and =) (a b c) (1 2 3)))
191
;; (AND (= A 1) (= B 2) (= C 3))"
192
`(,r ,@(apply #'mapcar #'(lambda (&rest atoms) (cons m atoms)) (mapcar #'ensure-list args))))
194
(defun circular-list-error (list)
197
:expected-type '(and list (not circular-list))))
199
(declaim (inline safe-endp))
201
(declare (optimize safety))
204
(macrolet ((def (name lambda-list doc step declare ret1 ret2)
205
(assert (member 'list lambda-list))
206
`(defun ,name ,lambda-list
209
(error 'type-error :datum list :expected-type 'list))
210
(do ((last list fast)
211
(fast list (cddr fast))
212
(slow (cons (car list) (cdr list)) (cdr slow))
213
,@(when step (list step)))
215
(declare (dynamic-extent slow) ,@(when declare (list declare))
217
(when (safe-endp fast)
219
(when (safe-endp (cdr fast))
222
(circular-list-error list))))))
223
(def proper-list-length (list)
224
"Returns length of LIST, signalling an error if it is not a proper list."
226
;; KLUDGE: Most implementations don't actually support lists with bignum
227
;; elements -- and this is WAY faster on most implementations then declaring
228
;; N to be an UNSIGNED-BYTE.
234
"Returns the last element of LIST. Signals a type-error if LIST is not a
241
(def (setf lastcar) (object list)
242
"Sets the last element of LIST. Signals a type-error if LIST is not a proper
246
(setf (cadr last) object)
247
(setf (car fast) object)))
249
(defun mappend (fn &rest lists)
250
(loop for ret in (apply #'mapcar fn lists)
253
(defun cart (list &rest more-lists)
254
"Returns the cartesian product of LIST and MORE-LISTS.
256
The length of the result is equal to the product of the lengths of all input
257
lists. A zero-length list anywhere in the input will always return NIL.
259
The length of each element of the result is equal to the length of the
264
(cart (list 1 2) (list 3 4 5)) ;; ((1 3) (2 3) (1 4) (2 4) (1 5) (2 5))
265
(cart (list 1 2 3) (list 4 5)) ;; ((1 4) (2 4) (3 4) (1 5) (2 5) (3 5))
266
(cart (list 1 2 3) nil (list 4 5)) ;; nil
269
(mapcan #'(lambda (y) (mapcar #'(lambda (x) (cons x y)) list)) (apply #'cart more-lists))
270
(mapcar #'list list)))
272
(defun mapcart (function list &rest more-lists)
273
"(MAPCAR (LAMBDA (X) (APPLY FUNCTION X)) (APPLY CART LIST MORE-LISTS))
275
Remember that CART always returns elements with a length equal to the smallest
276
input list. FUNCTION will need to accept at least as many args as the element
280
(mapcart '+ '(1 2 3) '(4 5)) ;; (5 6 7 6 7 8)"
281
(mapcar (lambda (args) (apply function args)) (apply #'cart list more-lists)))
283
(defmacro cart-case ((&rest vars) &body cases)
284
(let ((decl (zipsym vars)))
286
(cond ,@(mapcar #'(lambda (clause) `((ziprm (and eql) ,(mapcar #'car decl) ,(first clause)) ,@(cdr clause))) cases)))))
288
(defmacro cart-ecase ((&rest vars) &body cases)
289
(let ((decl (zipsym vars)))
291
(cond ,@(mapcar #'(lambda (clause) `((ziprm (and eql) ,(mapcar #'car decl) ,(first clause)) ,@(cdr clause))) cases)
292
(t (error "cart-ecase: Case failure."))))))
294
(defmacro cart-typecase (vars &body cases)
295
(let* ((decl (zipsym vars)))
297
(cond ,@(mapcar #'(lambda (clause) `((ziprm (and typep) ,(mapcar #'car decl) ,(mapcar #'(lambda (x) `(quote ,x)) (first clause))) ,@(cdr clause))) cases)))))
299
(defmacro cart-etypecase (vars &body cases)
300
(let* ((decl (zipsym vars)))
302
(cond ,@(mapcar #'(lambda (clause) `((ziprm (and typep) ,(mapcar #'car decl) ,(mapcar #'(lambda (x) `(quote ,x)) (first clause))) ,@(cdr clause))) cases)
303
(t (error "cart-etypecase: Case failure."))))))
305
(declaim (inline pairs))
307
"Return a new list containing each pair of elements in LIST."
308
(loop for (a . b) on list by #'cddr collect (if b (list a (first b)) (list a))))
310
(defun maptree-if (predicate transformer tree)
311
"Returns a new tree by recursively calling TRANSFORMER on sub-trees which
312
satisfy the PREDICATE.
314
predicate : tree -> boolean
315
transformer: tree -> (or tree atom) *control
317
If the transformer returns a CONTROL function, then the tree returned by the
318
transformer is replaced in-turn by the result of:
320
(funcall CONTROL #'(lambda (x) (maptree-if PREDICATE TRANSFORMER x)) transformed-tree)
322
otherwise it is left as it is.
325
(maptree-if #'(λ (x) (and (consp x) (eq (car x) 'ping)))
326
#'(λ (x) `(pong ,@(cdr x)))
327
'(progn (ping (ping (ping 1)))))
328
;; (PROGN (PONG (PING (PING 1))))
329
(maptree-if #'(λ (x) (and (consp x) (eq (car x) 'ping)))
330
#'(λ (x) (values `(pong ,@(cdr x)) #'mapcar))
331
'(progn (ping (ping (ping 1)))))
332
;; (PROGN (PONG (PONG (PONG 1))))
334
(multiple-value-bind (t-tree control) (if (funcall predicate tree)
335
(funcall transformer tree)
336
(values tree #'mapcar))
337
(if (and (consp t-tree) control)
338
(funcall control #'(lambda (x) (maptree-if predicate transformer x)) t-tree)
341
(defun maptree (keys transformer tree)
342
(maptree-if #'(lambda (x) (and (consp x) (member (car x) keys)))
345
(defmacro nconsc (var &rest args)
346
"Macro to do setf and nconc for destructive list updates.
348
If VAR is null then VAR is set to (apply #'nconc ARGS),
350
else does (apply #'nconc (cons VAR ARGS)).
354
(nconsc x (list 1 2 3) (list 'a 'b 'c))
358
(let ((x (list 'a 'b 'c)))
359
(nconsc x (list 1 2 3))
362
(assert (and (symbolp var) (not (member var '(t nil)))))
366
(setf ,var ,(car args))
367
(nconc ,var ,@(cdr args)))
368
(nconc ,var ,@args))))
371
(declaim (inline firstn))
372
(defun firstn (n list)
373
(loop repeat n for x in list collect x))
376
;; From Hansen's MS thesis.
377
(defun merge! (a b predicate)
378
"Destructively merge two sorted lists given comparison function PREDICATE."
379
(labels ((merge-loop (r a b)
380
(cond ((funcall predicate (car b) (car a))
384
(merge-loop b a (cdr b))))
385
(t ; (car a) <= (car b)
389
(merge-loop a (cdr a) b))))))
392
((funcall predicate (car b) (car a))
395
(merge-loop b a (cdr b)))
397
(t ; (car a) <= (car b)
400
(merge-loop a (cdr a) b))
403
;; Due to Richard O'Keefe; algorithm attributed to D.H.D. Warren.
404
(defun sort! (seq predicate)
405
"Stable sort which copies the input list SEQ and then sorts the new list
406
imperatively according to PREDICATE."
409
(let* ((j (truncate n 2))
413
(merge! a b predicate)))
418
(setf seq (cddr seq))
419
(when (funcall predicate y x)
430
(astep (length seq))))
433
(defun set-equal (list1 list2 &key (test #'eql) (key nil keyp))
434
"Returns true if every element of LIST1 matches some element of LIST2 and
435
every element of LIST2 matches some element of LIST1. Otherwise returns false."
436
(let ((keylist1 (if keyp (mapcar key list1) list1))
437
(keylist2 (if keyp (mapcar key list2) list2)))
438
(and (dolist (elt keylist1 t)
439
(or (member elt keylist2 :test test)
441
(dolist (elt keylist2 t)
442
(or (member elt keylist1 :test test)
446
(declaim (inline racons))
447
(defun racons (key value ralist)
448
(acons value key ralist))
451
((define-alist-get (name get-entry get-value-from-entry add doc)
453
(declaim (inline ,name))
454
(defun ,name (alist key &key (test 'eql))
456
(let ((entry (,get-entry key alist :test test)))
457
(values (,get-value-from-entry entry) entry)))
458
(define-setf-expander ,name (place key &key (test ''eql)
461
(temporary-variables initforms newvals setter getter)
462
(get-setf-expansion place env)
464
(error "~A cannot store multiple values in one place" ',name))
465
(with-gensyms (new-value key-val test-val alist entry)
467
(append temporary-variables
476
`(,',get-entry ,key-val ,alist :test ,test-val)))
480
(setf (,',get-value-from-entry ,entry) ,new-value))
483
(setf ,(first newvals) (,',add ,key ,new-value ,alist))
486
`(,',get-value-from-entry ,entry))))))))
487
(define-alist-get assoc-value assoc cdr acons
488
"ASSOC-VALUE is an alist accessor very much like ASSOC, but it can
490
(define-alist-get rassoc-value rassoc car racons
491
"RASSOC-VALUE is an alist accessor very much like RASSOC, but it can
492
be used with SETF."))
496
;; Simple doubly-linked lists
498
;; ref: https://github.com/bharath1097/matlisp/blob/94b65e68f2de5208ef9641cd105e25512c36a7f5/src/utilities/dlist.lisp
500
;; ref: https://github.com/krzysz00/dlist
502
(let ((lst (list* nil nil obj)))
503
(setf (first lst) lst
507
(defmacro dpush (obj dll &environment env)
508
(multiple-value-bind (dummies vals new setter getter) (get-setf-expansion dll env)
510
(error "Can't expand this."))
511
(with-gensyms (left right ele ncon)
512
(let ((new (car new)))
513
`(let* (,@(zip-list dummies vals)
515
(,ncon (dcons ,obj)))
517
(destructuring-bind (,left ,right . ,ele) ,new
518
(declare (ignore ,right ,ele))
519
(setf (first ,ncon) ,left
522
(first ,new) ,ncon)))
526
(defmacro dpop (dll &environment env)
527
(multiple-value-bind (dummies vals new setter getter) (get-setf-expansion dll env)
529
(error "Can't expand this."))
530
(with-gensyms (left right ele)
531
(let ((new (car new)))
532
`(let* (,@(zip-list dummies vals)
535
(destructuring-bind (,left ,right . ,ele) ,new
538
(setf (first ,new) ,new
541
(if (and (eql ,new ,left) (eql ,new ,right))
543
(setf (second ,left) ,right
548
(defun dlist (&rest objs)
549
(let* ((rev (reverse objs))
550
(ret (dcons (car rev))))
551
(loop :for ele :in (cdr rev)
555
(declaim (inline drdc dcdr dcar))
556
(defun drdc (buf) (first buf))
557
(defun dcdr (buf) (second buf))
558
(defun dcar (buf) (cddr buf))
560
(defun dappendf (&rest dlsts)
561
(let ((dlsts (remove-if #'null dlsts)))
562
(loop for se in (cdr dlsts)
563
with ft = (car dlsts)
565
(rotatef (first ft) (first se))
566
(rotatef (second (first ft)) (second (first se))))
567
finally (return ft))))
570
;; Topological sort (matlisp)
571
(defun toposort (lst func &optional (test #'eql))
572
(multiple-value-bind (nlst len) (loop :for ele :in lst
573
:for i := 0 :then (1+ i)
574
:collect (cons i ele) :into ret
575
:finally (return (values ret (1+ i))))
577
(graph (let ((ret (make-array len)))
578
(loop :for (i . ele) :in nlst
579
:do (let ((children (mapcar #'car (remove-if-not #'(lambda (x) (and (not (funcall test (cdr x) ele)) (funcall func (cdr x) ele))) nlst)))
580
(parents (mapcar #'car (remove-if-not #'(lambda (x) (and (not (funcall test (cdr x) ele)) (funcall func ele (cdr x)))) nlst))))
583
(setf (aref ret i) (list ele children parents))))
586
(let ((last-s (last s)))
587
(do ((slst s (cdr slst)))
589
(let* ((i (car slst))
590
(children (second (aref graph i))))
591
(mapcar #'(lambda (x)
592
(let ((par (third (aref graph x))))
593
(let ((par (remove i par)))
594
(setf (third (aref graph x)) par)
596
(setf (cdr last-s) (cons x nil)
597
last-s (cdr last-s))))))
600
(mapcar #'(lambda (x) (car (aref graph x))) ordering))))
602
(defun match-lambda-lists (lsta lstb)
603
(let ((optional? nil))
604
(labels ((optp? (a b)
605
(if (and (consp a) (atom b)) (optp? b a)
607
(if (or (member a lambda-list-keywords) (not optional?)) nil
608
(if (null (cddr b)) t nil)))))
611
((and (atom a) (atom b))
614
(when (member a lambda-list-keywords)
615
(setq optional? (if (member a '(&optional &key)) t nil)))
617
(if (or (member a lambda-list-keywords) (member b lambda-list-keywords)) nil t)))
618
((or (atom a) (atom b))
619
(if (optp? a b) t nil))
620
((and (consp a) (consp b))
621
(and (lst-walker (car a) (car b))
622
(lst-walker (cdr a) (cdr b)))))))
623
(lst-walker lsta lstb))))