forked from franzinc/nfs
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathinterval.cl
91 lines (76 loc) · 2.58 KB
/
interval.cl
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
81
82
83
84
85
86
87
88
89
90
91
;; -*- mode: common-lisp -*-
;; See the file LICENSE for the full license governing this code.
(defpackage :interval
(:use :lisp :excl)
(:export
#:begins-before-p
#:begins-after-p
#:ends-after-p
#:begins-within-p
#:ends-within-p
#:overlaps-p
#:interval-subtract
#:interval-subtract-pairs))
(in-package :interval)
(defmacro begins-before-p (start1 end1 start2 end2)
(declare (ignore end1 end2))
`(< ,start2 ,start1))
(defmacro begins-after-p (start1 end1 start2 end2)
(declare (ignore start1 end2))
`(>= ,start2 ,end1))
;; interval2 ends after interval 1 ends
(defmacro ends-after-p (start1 end1 start2 end2)
(declare (ignore start1 start2))
`(> ,end2 ,end1))
(defmacro begins-within-p (start1 end1 start2 end2)
(declare (ignore end2))
`(and (>= ,start2 ,start1) (< ,start2 ,end1)))
(defmacro ends-within-p (start1 end1 start2 end2)
(declare (ignore start2))
`(and (> ,end2 ,start1) (<= ,end2 ,end1)))
(defmacro overlaps-p (start1 end1 start2 end2)
`(or (begins-within-p ,start1 ,end1 ,start2 ,end2)
(ends-within-p ,start1 ,end1 ,start2 ,end2)
(and (begins-before-p ,start1 ,end1 ,start2 ,end2)
(ends-after-p ,start1 ,end1 ,start2 ,end2))))
(defun interval-subtract-1 (start1 end1 start2 end2)
(cond
((not (overlaps-p start1 end1 start2 end2))
(values start1 end1))
((begins-before-p start1 end1 start2 end2)
(if* (ends-within-p start1 end1 start2 end2)
then (values end2 end1)
else nil))
(t ;; begins within
(if* (ends-within-p start1 end1 start2 end2)
then (values start1 start2 end2 end1)
else (values start1 start2)))))
(defun interval-subtract (start1 end1 start2 end2)
(declare (optimize (speed 3)))
(multiple-value-bind (a b c d)
(interval-subtract-1 start1 end1 start2 end2)
(if (null a)
(return-from interval-subtract))
(if* (and c (= c d))
then (setf c nil)
(setf d nil))
(if* (= a b)
then (setf a c)
(setf b d)
(setf c nil)
(setf d nil))
(values a b c d)))
;; Return a list of the remaining intervals (in cons form)
(defun interval-subtract-pairs (start end pairs)
(dolist (pair pairs)
(multiple-value-bind (nstart1 nend1 nstart2 nend2)
(interval-subtract start end (car pair) (cdr pair))
(if* nstart2
then (return-from interval-subtract-pairs
(nconc (interval-subtract-pairs nstart1 nend1 pairs)
(interval-subtract-pairs nstart2 nend2 pairs)))
elseif nstart1
then (setf start nstart1)
(setf end nend1)
else (return-from interval-subtract-pairs nil))))
(list (cons start end)))