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.
7 ;;;; This software is part of the SBCL system. See the README file for
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.
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)
24 (number nil :type (or index null)))
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))
33 (elements :prin1 (cdr elements)))
35 ;;; Iterate over the elements in SSET, binding VAR to each element in
37 (defmacro do-sset-elements ((var sset &optional result) &body body)
38 `(dolist (,var (cdr (sset-elements ,sset)) ,result) ,@body))
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)))
49 (setf (cdr prev) (list element))
51 (let ((el (car current)))
52 (when (>= (sset-element-number el) number)
55 (setf (cdr prev) (cons element current))
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)))
66 (when (eq (car current) element)
67 (setf (cdr prev) (cdr current))
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))))
76 (declaim (ftype (function (sset sset) boolean) sset=))
77 (defun sset= (set1 set2)
78 (equal (sset-elements set1) (sset-elements set2)))
80 ;;; Return true if SET contains no elements, false otherwise.
81 (declaim (ftype (function (sset) boolean) sset-empty))
82 (defun sset-empty (set)
83 (null (cdr (sset-elements set))))
85 ;;; Return a new copy of SET.
86 (declaim (ftype (function (sset) sset) copy-sset))
87 (defun copy-sset (set)
88 (make-sset :elements (copy-list (sset-elements set))))
90 ;;; Perform the appropriate set operation on SET1 and SET2 by
91 ;;; destructively modifying SET1. We return true if SET1 was modified,
93 (declaim (ftype (function (sset sset) boolean) sset-union sset-intersection
95 (defun sset-union (set1 set2)
96 (let* ((prev-el1 (sset-elements set1))
99 (do ((el2 (cdr (sset-elements set2)) (cdr el2)))
102 (num2 (sset-element-number e)))
105 (setf (cdr prev-el1) (copy-list el2))
106 (return-from sset-union t))
107 (let ((num1 (sset-element-number (car el1))))
110 (let ((new (cons e el1)))
111 (setf (cdr prev-el1) new)
114 (shiftf prev-el1 el1 (cdr el1)))
116 (shiftf prev-el1 el1 (cdr el1))))))))
117 (defun sset-intersection (set1 set2)
118 (let* ((prev-el1 (sset-elements set1))
121 (do ((el2 (cdr (sset-elements set2)) (cdr el2)))
124 (setf (cdr prev-el1) nil)
127 (let ((num2 (sset-element-number (car el2))))
130 (return-from sset-intersection changed))
131 (let ((num1 (sset-element-number (car el1))))
134 (shiftf prev-el1 el1 (cdr el1)))
137 (setf (cdr prev-el1) el1)
138 (setq changed t)))))))
139 (defun sset-difference (set1 set2)
140 (let* ((prev-el1 (sset-elements set1))
143 (do ((el2 (cdr (sset-elements set2)) (cdr el2)))
145 (let ((num2 (sset-element-number (car el2))))
148 (return-from sset-difference changed))
149 (let ((num1 (sset-element-number (car el1))))
153 (setf (cdr prev-el1) el1)
156 (shiftf prev-el1 el1 (cdr el1))))))))
158 ;;; Destructively modify SET1 to include its union with the difference
159 ;;; of SET2 and SET3. We return true if SET1 was modified, false
161 (declaim (ftype (function (sset sset sset) boolean) sset-union-of-difference))
162 (defun sset-union-of-difference (set1 set2 set3)
163 (let* ((prev-el1 (sset-elements set1))
165 (el3 (cdr (sset-elements set3)))
167 (do ((el2 (cdr (sset-elements set2)) (cdr el2)))
170 (num2 (sset-element-number e)))
175 (setf (cdr prev-el1) (copy-list el2))
176 (return-from sset-union-of-difference t))
177 (let ((num1 (sset-element-number (car el1))))
180 (let ((new (cons e el1)))
181 (setf (cdr prev-el1) new)
182 (setq prev-el1 new changed t))
183 (shiftf prev-el1 el1 (cdr el1)))
185 (shiftf prev-el1 el1 (cdr el1))))
187 (let ((num3 (sset-element-number (car el3))))
189 (unless (= num2 num3)
192 (do ((el2 el2 (cdr el2)))
194 (return-from sset-union-of-difference changed))
196 (num2 (sset-element-number e)))
199 (setf (cdr prev-el1) (copy-list el2))
200 (return-from sset-union-of-difference t))
201 (setq num3 (sset-element-number (car el3)))
203 (unless (= num2 num3)
204 (let ((new (cons e el1)))
205 (setf (cdr prev-el1) new)
206 (setq prev-el1 new changed t)))
209 (let ((num1 (sset-element-number (car el1))))
212 (let ((new (cons e el1)))
213 (setf (cdr prev-el1) new)
214 (setq prev-el1 new changed t))
215 (shiftf prev-el1 el1 (cdr el1)))
217 (shiftf prev-el1 el1 (cdr el1)))))