-
Notifications
You must be signed in to change notification settings - Fork 9
/
api.lisp
80 lines (70 loc) · 3.81 KB
/
api.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
;;;; -*- Mode: Lisp; indent-tabs-mode: nil -*-
(in-package :split-sequence)
(defun list-long-enough-p (list length)
(or (zerop length)
(not (null (nthcdr (1- length) list)))))
(defun check-bounds (sequence start end)
(progn
(check-type start unsigned-byte "a non-negative integer")
(check-type end (or null unsigned-byte) "a non-negative integer or NIL")
(typecase sequence
(list
(when end
(unless (<= start end)
(error "Wrong sequence bounds. START: ~S END: ~S" start end))
(unless (list-long-enough-p sequence end)
(error "The list is too short: END was ~S but the list is ~S elements long."
end (length sequence)))))
(t
(let ((length (length sequence)))
(unless end (setf end length))
(unless (<= start end length)
(error "Wrong sequence bounds. START: ~S END: ~S" start end)))))))
(define-condition simple-program-error (program-error simple-condition) ())
(defmacro check-tests (test test-p test-not test-not-p)
`(if ,test-p
(if ,test-not-p
(error (make-condition 'simple-program-error
:format-control "Cannot specify both TEST and TEST-NOT."))
(check-type ,test (or function (and symbol (not null)))))
(when ,test-not-p
(check-type ,test-not (or function (and symbol (not null)))))))
(declaim (ftype (function (&rest t) (values list unsigned-byte))
split-sequence split-sequence-if split-sequence-if-not))
(defun split-sequence (delimiter sequence &key (start 0) (end nil) (from-end nil)
(count nil) (remove-empty-subseqs nil)
(test #'eql test-p) (test-not nil test-not-p)
(key #'identity))
(check-bounds sequence start end)
(check-tests test test-p test-not test-not-p)
(etypecase sequence
(list (split-list delimiter sequence start end from-end count
remove-empty-subseqs test test-not key))
(vector (split-vector delimiter sequence start end from-end count
remove-empty-subseqs test test-not key))
#+(or abcl sbcl)
(extended-sequence (split-extended-sequence delimiter sequence start end from-end count
remove-empty-subseqs test test-not key))))
(defun split-sequence-if (predicate sequence &key (start 0) (end nil) (from-end nil)
(count nil) (remove-empty-subseqs nil) (key #'identity))
(check-bounds sequence start end)
(etypecase sequence
(list (split-list-if predicate sequence start end from-end count
remove-empty-subseqs key))
(vector (split-vector-if predicate sequence start end from-end count
remove-empty-subseqs key))
#+(or abcl sbcl)
(extended-sequence (split-extended-sequence-if predicate sequence start end from-end count
remove-empty-subseqs key))))
(defun split-sequence-if-not (predicate sequence &key (start 0) (end nil) (from-end nil)
(count nil) (remove-empty-subseqs nil) (key #'identity))
(check-bounds sequence start end)
(etypecase sequence
(list (split-list-if-not predicate sequence start end from-end count
remove-empty-subseqs key))
(vector (split-vector-if-not predicate sequence start end from-end count
remove-empty-subseqs key))
#+(or abcl sbcl)
(extended-sequence (split-extended-sequence-if-not predicate sequence start end from-end count
remove-empty-subseqs key))))
(pushnew :split-sequence *features*)