Coverage report: /home/ellis/.stash/quicklisp/dists/ultralisp/software/sharplispers-split-sequence-20211208061629/list.lisp

KindCoveredAll%
expression0189 0.0
branch020 0.0
Key
Not instrumented
Conditionalized out
Executed
Not executed
 
Both branches taken
One branch taken
Neither branch taken
1
 ;;;; -*- Mode: Lisp; indent-tabs-mode: nil -*-
2
 
3
 (in-package :split-sequence)
4
 
5
 (declaim (inline
6
           collect-until count-while
7
           split-list split-list-if split-list-if-not
8
           split-list-from-end split-list-from-start split-list-internal))
9
 
10
 (declaim (ftype (function (&rest t) (values list unsigned-byte))
11
                 split-list split-list-if split-list-if-not))
12
 
13
 (declaim (ftype (function (function list unsigned-byte (or null unsigned-byte) (or null unsigned-byte)
14
                                     boolean)
15
                           (values list unsigned-byte))
16
                 split-list-from-start split-list-from-end split-list-internal))
17
 
18
 (defun collect-until (predicate list end)
19
   "Collect elements from LIST until one that satisfies PREDICATE is found.
20
 
21
   At most END elements will be examined. If END is null, all elements will be examined.
22
 
23
   Returns four values:
24
 
25
   * The collected items.
26
   * The remaining items.
27
   * The number of elements examined.
28
   * Whether the search ended by running off the end, instead of by finding a delimiter."
29
   (let ((examined 0)
30
         (found nil))
31
     (flet ((examine (value)
32
              (incf examined)
33
              (setf found (funcall predicate value))))
34
       (loop :for (value . remaining) :on list
35
             :until (eql examined end)
36
             :until (examine value)
37
             :collect value :into result
38
             :finally (return (values result
39
                                      remaining
40
                                      examined
41
                                      (and (not found)
42
                                           (or (null end)
43
                                               (= end examined)))))))))
44
 
45
 (defun count-while (predicate list end)
46
   "Count the number of elements satisfying PREDICATE at the beginning of LIST.
47
 
48
   At most END elements will be counted. If END is null, all elements will be examined."
49
   (if end
50
       (loop :for value :in list
51
             :for i :below end
52
             :while (funcall predicate value)
53
             :summing 1)
54
       (loop :for value :in list
55
             :while (funcall predicate value)
56
             :summing 1)))
57
 
58
 (defun split-list-internal (predicate list start end count remove-empty-subseqs)
59
   (let ((count count)
60
         (done nil)
61
         (index start)
62
         (end (when end (- end start)))
63
         (list (nthcdr start list)))
64
     (flet ((should-collect-p (chunk)
65
              (unless (and remove-empty-subseqs (null chunk))
66
                (when (numberp count) (decf count))
67
                t))
68
            (gather-chunk ()
69
              (multiple-value-bind (chunk remaining examined ran-off-end)
70
                  (collect-until predicate list end)
71
                (incf index examined)
72
                (when end (decf end examined))
73
                (setf list remaining
74
                      done ran-off-end)
75
                chunk)))
76
       (values (loop :with chunk
77
                     :until (or done (eql 0 count))
78
                     :do (setf chunk (gather-chunk))
79
                     :when (should-collect-p chunk)
80
                       :collect chunk)
81
               (+ index
82
                  (if remove-empty-subseqs
83
                      (count-while predicate list end) ; chew off remaining empty seqs
84
                      0))))))
85
 
86
 (defun split-list-from-end (predicate list start end count remove-empty-subseqs)
87
   (let ((length (length list)))
88
     (multiple-value-bind (result index)
89
         (split-list-internal predicate (reverse list)
90
                              (if end (- length end) 0)
91
                              (- length start) count remove-empty-subseqs)
92
       (loop :for cons on result
93
             :for car := (car cons)
94
             :do (setf (car cons) (nreverse car)))
95
       (values (nreverse result) (- length index)))))
96
 
97
 (defun split-list-from-start (predicate list start end count remove-empty-subseqs)
98
   (split-list-internal predicate list start end count remove-empty-subseqs))
99
 
100
 (defun split-list-if (predicate list start end from-end count remove-empty-subseqs key)
101
   (let ((predicate (lambda (x) (funcall predicate (funcall key x)))))
102
     (if from-end
103
         (split-list-from-end predicate list start end count remove-empty-subseqs)
104
         (split-list-from-start predicate list start end count remove-empty-subseqs))))
105
 
106
 (defun split-list-if-not (predicate list start end from-end count remove-empty-subseqs key)
107
   (split-list-if (complement predicate) list start end from-end count remove-empty-subseqs key))
108
 
109
 (defun split-list
110
     (delimiter list start end from-end count remove-empty-subseqs test test-not key)
111
   (let ((predicate (if test-not
112
                        (lambda (x) (not (funcall test-not delimiter (funcall key x))))
113
                        (lambda (x) (funcall test delimiter (funcall key x))))))
114
     (if from-end
115
         (split-list-from-end predicate list start end count remove-empty-subseqs)
116
         (split-list-from-start predicate list start end count remove-empty-subseqs))))