run-program: support I/O redirection to binary streams on win32.
[sbcl.git] / src / code / xset.lisp
blob408f6c1dd2d587fd3cab0c4643e4f504e7f3ebad
1 ;;;; This software is part of the SBCL system. See the README file for
2 ;;;; more information.
3 ;;;;
4 ;;;; This software is derived from the CMU CL system, which was
5 ;;;; written at Carnegie Mellon University and released into the
6 ;;;; public domain. The software is in the public domain and is
7 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
8 ;;;; files for more information.
10 ;;;; XSET
11 ;;;;
12 ;;;; A somewhat efficient set implementation that can store arbitrary
13 ;;;; objects. For small sets the data is stored in a list, but when
14 ;;;; the amount of elements grows beyond +XSET-LIST-SIZE-LIMIT+, we
15 ;;;; switch to a hash-table instead.
16 ;;;;
17 ;;;; ALLOC-XSET allocates an empty XSET. ADD-TO-XSET adds an element
18 ;;;; to an XSET: it should be used only on freshly allocated XSETs.
19 ;;;;
20 ;;;; XSET-EMPTY-P, XSET-INTERSECTION, XSET-SUBSET-P, and XSET-MEMBER-P
21 ;;;; do the obvious things. MAP-XSET maps over the element, but
22 ;;;; requires a function as the first argument -- not a function
23 ;;;; designator.
24 ;;;;
25 ;;;; XSET-LIST-SIZE is true only for XSETs whose data is stored into a
26 ;;;; list -- XSET-COUNT returns the real value.
28 (in-package "SB!KERNEL")
30 (defstruct (xset (:constructor alloc-xset) (:copier nil) (:predicate nil))
31 (list-size 0 :type index)
32 (data nil :type (or list hash-table)))
34 (defun xset-count (xset)
35 (let ((data (xset-data xset)))
36 (if (listp data)
37 (xset-list-size xset)
38 (hash-table-count data))))
40 (defun map-xset (function xset)
41 (declare (function function))
42 (let ((data (xset-data xset)))
43 (if (listp data)
44 (dolist (elt data)
45 (funcall function elt))
46 (maphash (lambda (k v)
47 (declare (ignore v))
48 (funcall function k))
49 data)))
50 nil)
52 (defconstant +xset-list-size-limit+ 24)
54 ;;; Checks that the element is not in the set yet.
55 (defun add-to-xset (elt xset)
56 (let ((data (xset-data xset))
57 (size (xset-list-size xset)))
58 (if (listp data)
59 (if (< size +xset-list-size-limit+)
60 (unless (member elt data :test #'eql)
61 (setf (xset-list-size xset) (1+ size)
62 (xset-data xset) (cons elt data)))
63 (let ((table (make-hash-table :size (* 2 size) :test #'eql)))
64 (setf (gethash elt table) t)
65 (dolist (x data)
66 (setf (gethash x table) t))
67 (setf (xset-data xset) table)))
68 (setf (gethash elt data) t))))
70 ;; items must be canonical - no duplicates - and few in number.
71 (defun xset-from-list (items)
72 (let ((n (length items)))
73 (aver (<= n +xset-list-size-limit+))
74 (let ((xset (alloc-xset)))
75 (setf (xset-list-size xset) n (xset-data xset) items)
76 xset)))
78 (defun xset-union (a b)
79 (let ((xset (alloc-xset)))
80 (map-xset (lambda (x)
81 (add-to-xset x xset))
83 (map-xset (lambda (y)
84 (add-to-xset y xset))
86 xset))
88 (defun xset-member-p (elt xset)
89 (let ((data (xset-data xset)))
90 (if (listp data)
91 (member elt data :test #'eql)
92 (gethash elt data))))
94 (defun xset-members (xset)
95 (let ((data (xset-data xset)))
96 (if (listp data)
97 data
98 (let (members)
99 (maphash (lambda (k v)
100 (declare (ignore v))
101 (push k members))
102 data)
103 members))))
105 (defun xset-intersection (a b)
106 (let ((intersection (alloc-xset)))
107 (multiple-value-bind (source lookup)
108 (if (< (xset-list-size a) (xset-list-size b))
109 (values b a)
110 (values a b))
111 (let ((data (xset-data lookup)))
112 (map-xset (if (listp data)
113 (lambda (elt)
114 (when (member elt data :test #'eql)
115 (add-to-xset elt intersection)))
116 (lambda (elt)
117 (when (gethash elt data)
118 (add-to-xset elt intersection))))
119 source)))
120 intersection))
122 (defun xset-subset-p (xset1 xset2)
123 (when (<= (xset-count xset1) (xset-count xset2))
124 (let ((data (xset-data xset2)))
125 (map-xset
126 (if (listp data)
127 (lambda (elt)
128 (unless (member elt data :test #'eql)
129 (return-from xset-subset-p nil)))
130 (lambda (elt)
131 (unless (gethash elt data)
132 (return-from xset-subset-p nil))))
133 xset1))
136 #!-sb-fluid (declaim (inline xset-empty-p))
137 (defun xset-empty-p (xset)
138 (not (xset-data xset)))