list.lisp - clic - Clic is an command line interactive client for gopher written in Common LISP
 (HTM) git clone git://bitreich.org/clic/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/clic/
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Tags
 (DIR) README
 (DIR) LICENSE
       ---
       list.lisp (4980B)
       ---
            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))))