0.7.8.28:
[sbcl.git] / src / compiler / sset.lisp
1 ;;;; This file implements a sparse set abstraction, represented as a
2 ;;;; sorted linked list. We don't use bit-vectors to represent sets in
3 ;;;; flow analysis, since the universe may be quite large but the
4 ;;;; average number of elements is small. We keep the list sorted so
5 ;;;; that we can do union and intersection in linear time.
6
7 ;;;; This software is part of the SBCL system. See the README file for
8 ;;;; more information.
9 ;;;;
10 ;;;; This software is derived from the CMU CL system, which was
11 ;;;; written at Carnegie Mellon University and released into the
12 ;;;; public domain. The software is in the public domain and is
13 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
14 ;;;; files for more information.
15
16 (in-package "SB!C")
17
18 ;;; Each structure that may be placed in a SSET must include the
19 ;;; SSET-ELEMENT structure. We allow an initial value of NIL to mean
20 ;;; that no ordering has been assigned yet (although an ordering must
21 ;;; be assigned before doing set operations.)
22 (defstruct (sset-element (:constructor nil)
23                          (:copier nil))
24   (number nil :type (or index null)))
25
26 (defstruct (sset (:copier nil))
27   ;; The element at the head of the list here seems always to be
28   ;; ignored. I think this idea is that the extra level of indirection
29   ;; it provides is handy to allow various destructive operations on
30   ;; SSETs to be expressed more easily. -- WHN
31   (elements (list nil) :type cons))
32 (defprinter (sset)
33   (elements :prin1 (cdr elements)))
34
35 ;;; Iterate over the elements in SSET, binding VAR to each element in
36 ;;; turn.
37 (defmacro do-sset-elements ((var sset &optional result) &body body)
38   `(dolist (,var (cdr (sset-elements ,sset)) ,result) ,@body))
39
40 ;;; Destructively add ELEMENT to SET. If ELEMENT was not in the set,
41 ;;; then we return true, otherwise we return false.
42 (declaim (ftype (function (sset-element sset) boolean) sset-adjoin))
43 (defun sset-adjoin (element set)
44   (let ((number (sset-element-number element))
45         (elements (sset-elements set)))
46     (do ((prev elements current)
47          (current (cdr elements) (cdr current)))
48         ((null current)
49          (setf (cdr prev) (list element))
50          t)
51       (let ((el (car current)))
52         (when (>= (sset-element-number el) number)
53           (when (eq el element)
54             (return nil))
55           (setf (cdr prev) (cons element current))
56           (return t))))))
57
58 ;;; Destructively remove ELEMENT from SET. If element was in the set,
59 ;;; then return true, otherwise return false.
60 (declaim (ftype (function (sset-element sset) boolean) sset-delete))
61 (defun sset-delete (element set)
62   (let ((elements (sset-elements set)))
63     (do ((prev elements current)
64          (current (cdr elements) (cdr current)))
65         ((null current) nil)
66       (when (eq (car current) element)
67         (setf (cdr prev) (cdr current))
68         (return t)))))
69
70 ;;; Return true if ELEMENT is in SET, false otherwise.
71 (declaim (ftype (function (sset-element sset) boolean) sset-member))
72 (defun sset-member (element set)
73   (declare (inline member))
74   (not (null (member element (cdr (sset-elements set)) :test #'eq))))
75
76 ;;; Return true if SET contains no elements, false otherwise.
77 (declaim (ftype (function (sset) boolean) sset-empty))
78 (defun sset-empty (set)
79   (null (cdr (sset-elements set))))
80
81 ;;; Return a new copy of SET.
82 (declaim (ftype (function (sset) sset) copy-sset))
83 (defun copy-sset (set)
84   (make-sset :elements (copy-list (sset-elements set))))
85
86 ;;; Perform the appropriate set operation on SET1 and SET2 by
87 ;;; destructively modifying SET1. We return true if SET1 was modified,
88 ;;; false otherwise.
89 (declaim (ftype (function (sset sset) boolean) sset-union sset-intersection
90                 sset-difference))
91 (defun sset-union (set1 set2)
92   (let* ((prev-el1 (sset-elements set1))
93          (el1 (cdr prev-el1))
94          (changed nil))
95     (do ((el2 (cdr (sset-elements set2)) (cdr el2)))
96         ((null el2) changed)
97       (let* ((e (car el2))
98              (num2 (sset-element-number e)))
99         (loop
100           (when (null el1)
101             (setf (cdr prev-el1) (copy-list el2))
102             (return-from sset-union t))
103           (let ((num1 (sset-element-number (car el1))))
104             (when (>= num1 num2)
105               (if (> num1 num2)
106                   (let ((new (cons e el1)))
107                     (setf (cdr prev-el1) new)
108                     (setq prev-el1 new
109                           changed t))
110                   (shiftf prev-el1 el1 (cdr el1)))
111               (return))
112             (shiftf prev-el1 el1 (cdr el1))))))))
113 (defun sset-intersection (set1 set2)
114   (let* ((prev-el1 (sset-elements set1))
115          (el1 (cdr prev-el1))
116          (changed nil))
117     (do ((el2 (cdr (sset-elements set2)) (cdr el2)))
118         ((null el2)
119          (cond (el1
120                 (setf (cdr prev-el1) nil)
121                 t)
122                (t changed)))
123       (let ((num2 (sset-element-number (car el2))))
124         (loop
125           (when (null el1)
126             (return-from sset-intersection changed))
127           (let ((num1 (sset-element-number (car el1))))
128             (when (>= num1 num2)
129               (when (= num1 num2)
130                 (shiftf prev-el1 el1 (cdr el1)))
131               (return))
132             (pop el1)
133             (setf (cdr prev-el1) el1)
134             (setq changed t)))))))
135 (defun sset-difference (set1 set2)
136   (let* ((prev-el1 (sset-elements set1))
137          (el1 (cdr prev-el1))
138          (changed nil))
139     (do ((el2 (cdr (sset-elements set2)) (cdr el2)))
140         ((null el2) changed)
141       (let ((num2 (sset-element-number (car el2))))
142         (loop
143           (when (null el1)
144             (return-from sset-difference changed))
145           (let ((num1 (sset-element-number (car el1))))
146             (when (>= num1 num2)
147               (when (= num1 num2)
148                 (pop el1)
149                 (setf (cdr prev-el1) el1)
150                 (setq changed t))
151               (return))
152             (shiftf prev-el1 el1 (cdr el1))))))))
153
154 ;;; Destructively modify SET1 to include its union with the difference
155 ;;; of SET2 and SET3. We return true if Set1 was modified, false
156 ;;; otherwise.
157 (declaim (ftype (function (sset sset sset) boolean) sset-union-of-difference))
158 (defun sset-union-of-difference (set1 set2 set3)
159   (let* ((prev-el1 (sset-elements set1))
160          (el1 (cdr prev-el1))
161          (el3 (cdr (sset-elements set3)))
162          (changed nil))
163     (do ((el2 (cdr (sset-elements set2)) (cdr el2)))
164         ((null el2) changed)
165       (let* ((e (car el2))
166              (num2 (sset-element-number e)))
167         (loop
168           (when (null el3)
169             (loop
170               (when (null el1)
171                 (setf (cdr prev-el1) (copy-list el2))
172                 (return-from sset-union-of-difference t))
173               (let ((num1 (sset-element-number (car el1))))
174                 (when (>= num1 num2)
175                   (if (> num1 num2)
176                       (let ((new (cons e el1)))
177                         (setf (cdr prev-el1) new)
178                         (setq prev-el1 new  changed t))
179                       (shiftf prev-el1 el1 (cdr el1)))
180                   (return))
181                 (shiftf prev-el1 el1 (cdr el1))))
182             (return))
183           (let ((num3 (sset-element-number (car el3))))
184             (when (<= num2 num3)
185               (unless (= num2 num3)
186                 (loop
187                   (when (null el1)
188                     (do ((el2 el2 (cdr el2)))
189                         ((null el2)
190                          (return-from sset-union-of-difference changed))
191                       (let* ((e (car el2))
192                              (num2 (sset-element-number e)))
193                         (loop
194                           (when (null el3)
195                             (setf (cdr prev-el1) (copy-list el2))
196                             (return-from sset-union-of-difference t))
197                           (setq num3 (sset-element-number (car el3)))
198                           (when (<= num2 num3)
199                             (unless (= num2 num3)
200                               (let ((new (cons e el1)))
201                                 (setf (cdr prev-el1) new)
202                                 (setq prev-el1 new  changed t)))
203                             (return))
204                           (pop el3)))))
205                   (let ((num1 (sset-element-number (car el1))))
206                     (when (>= num1 num2)
207                       (if (> num1 num2)
208                           (let ((new (cons e el1)))
209                             (setf (cdr prev-el1) new)
210                             (setq prev-el1 new  changed t))
211                           (shiftf prev-el1 el1 (cdr el1)))
212                       (return))
213                     (shiftf prev-el1 el1 (cdr el1)))))
214               (return)))
215           (pop el3))))))