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 ;;; 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))))
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))))
86 ;;; Perform the appropriate set operation on SET1 and SET2 by
87 ;;; destructively modifying SET1. We return true if SET1 was modified,
89 (declaim (ftype (function (sset sset) boolean) sset-union sset-intersection
91 (defun sset-union (set1 set2)
92 (let* ((prev-el1 (sset-elements set1))
95 (do ((el2 (cdr (sset-elements set2)) (cdr el2)))
98 (num2 (sset-element-number e)))
101 (setf (cdr prev-el1) (copy-list el2))
102 (return-from sset-union t))
103 (let ((num1 (sset-element-number (car el1))))
106 (let ((new (cons e el1)))
107 (setf (cdr prev-el1) new)
110 (shiftf prev-el1 el1 (cdr el1)))
112 (shiftf prev-el1 el1 (cdr el1))))))))
113 (defun sset-intersection (set1 set2)
114 (let* ((prev-el1 (sset-elements set1))
117 (do ((el2 (cdr (sset-elements set2)) (cdr el2)))
120 (setf (cdr prev-el1) nil)
123 (let ((num2 (sset-element-number (car el2))))
126 (return-from sset-intersection changed))
127 (let ((num1 (sset-element-number (car el1))))
130 (shiftf prev-el1 el1 (cdr el1)))
133 (setf (cdr prev-el1) el1)
134 (setq changed t)))))))
135 (defun sset-difference (set1 set2)
136 (let* ((prev-el1 (sset-elements set1))
139 (do ((el2 (cdr (sset-elements set2)) (cdr el2)))
141 (let ((num2 (sset-element-number (car el2))))
144 (return-from sset-difference changed))
145 (let ((num1 (sset-element-number (car el1))))
149 (setf (cdr prev-el1) el1)
152 (shiftf prev-el1 el1 (cdr el1))))))))
154 ;;; Destructively modify SET1 to include its union with the difference
155 ;;; of SET2 and SET3. We return true if Set1 was modified, false
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))
161 (el3 (cdr (sset-elements set3)))
163 (do ((el2 (cdr (sset-elements set2)) (cdr el2)))
166 (num2 (sset-element-number e)))
171 (setf (cdr prev-el1) (copy-list el2))
172 (return-from sset-union-of-difference t))
173 (let ((num1 (sset-element-number (car el1))))
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)))
181 (shiftf prev-el1 el1 (cdr el1))))
183 (let ((num3 (sset-element-number (car el3))))
185 (unless (= num2 num3)
188 (do ((el2 el2 (cdr el2)))
190 (return-from sset-union-of-difference changed))
192 (num2 (sset-element-number e)))
195 (setf (cdr prev-el1) (copy-list el2))
196 (return-from sset-union-of-difference t))
197 (setq num3 (sset-element-number (car el3)))
199 (unless (= num2 num3)
200 (let ((new (cons e el1)))
201 (setf (cdr prev-el1) new)
202 (setq prev-el1 new changed t)))
205 (let ((num1 (sset-element-number (car el1))))
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)))
213 (shiftf prev-el1 el1 (cdr el1)))))