File: bags-and-sets.lisp

package info (click to toggle)
cl-containers 20170403-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 1,072 kB
  • ctags: 1,387
  • sloc: lisp: 8,341; makefile: 14
file content (175 lines) | stat: -rw-r--r-- 5,425 bytes parent folder | download | duplicates (4)
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
(in-package #:containers)

;;; Bags
;;;
;;; Support: insert-item, delete-item, search-for-item, size, empty-p, empty!
;;; iterate-nodes

(defclass* abstract-bag/set-container (uses-contents-mixin 
                                         findable-container-mixin
                                         unordered-container-mixin
                                         iteratable-container-mixin
                                         initial-contents-mixin)
  ())


(defmethod make-container-for-contents ((container abstract-bag/set-container)
                                        &rest args)
  (apply #'make-container 'bag/set-container args))


(defclass* bag-container (abstract-bag/set-container
                          concrete-container)
  ((contents :reader contents)))


(defmethod insert-item ((container bag-container) item)
  (insert-item (contents container) item))

(defmethod size ((container abstract-bag/set-container))
  (size (contents container)))

(defmethod empty-p ((container abstract-bag/set-container))
  (empty-p (contents container)))

(defmethod empty! ((container abstract-bag/set-container))
  (empty! (contents container))
  (values))

(defmethod search-for-item ((container abstract-bag/set-container) item &key 
                            (test #'eq) (key #'identity))
  (search-for-item (contents container) item :test test :key key))

(defmethod search-for-match ((container abstract-bag/set-container) predicate &key 
                             (key 'identity))
  (search-for-match (contents container) predicate :key key))


(defmethod delete-item ((container abstract-bag/set-container) item)
  (when (delete-item (contents container) item)
    item))


(defmethod find-item ((container abstract-bag/set-container) item)
  (find-item (contents container) item))


;;; Sets
;;; Support: insert-item, delete-item, search-for-item, size, empty-p, empty!
;;; iterate-nodes

(defclass* set-container (abstract-bag/set-container
                          concrete-container)
  ((contents :reader contents)))


(defmethod insert-item ((container set-container) item)
  (unless (find-item (contents container) item)
    (insert-item (contents container) item))
  item)

;;; bag/set-container container

(defclass* bag/set-container (contents-as-hashtable-mixin
                                unordered-container-mixin
                                concrete-container)
  ((set-or-bag :set ir)))


(defmethod insert-item ((container bag/set-container) item)
  (multiple-value-bind (value found?)
                       (gethash item (contents container))
    (if found?
      (setf (gethash item (contents container)) 
            (if (eq (set-or-bag container) :set) 1 (incf value)))
      (setf (gethash item (contents container)) 1)))
  (values item))


(defmethod delete-item ((container bag/set-container) item)
  (multiple-value-bind (value found?)
                       (gethash item (contents container))
    (when found?
      (if (= value 1)
        (remhash item (contents container))
        (setf (gethash item (contents container)) (decf value)))
      item)))


(defmethod size ((container bag/set-container))
  (let ((result 0))
    (maphash (lambda (k v)
               (declare (ignore k))
               (incf result v))
             (contents container))
    result))


(defmethod search-for-item ((container bag/set-container) item &key 
                            (test 'eq) (key 'identity))
  (maphash (lambda (k v)
             (declare (ignore v))
             (when (funcall test item (funcall key k))
               (return-from search-for-item (values k t))))
           (contents container))
  (values nil nil))


(defmethod iterate-nodes ((container bag/set-container) fn)
  (maphash (lambda (k v)
             (loop repeat v do
                   (funcall fn k)))
           (contents container)))


(defmethod find-item ((container bag/set-container) item)
  (multiple-value-bind (value found?)
                       (gethash item (contents container))
    (declare (ignore value))
    (when found?
      item)))


(defmethod find-value ((container bag/set-container) item)
  (multiple-value-bind (value found?)
                       (gethash item (contents container))
    (when found?
      value)))

;;; keyed-bag/set-container
;;;
;;; when a hash table just won't do

(defclass* keyed-bag/set-container (bag/set-container)
  ((key-map nil r))
  (:export-p t))


(defmethod initialize-instance :after ((object keyed-bag/set-container) &key)
  (setf (slot-value object 'key-map)
        (make-hash-table :test (test object))))


(defmethod insert-item ((container keyed-bag/set-container) item)
  (let ((key (funcall (key container) item)))
    (setf (gethash key (key-map container)) item)
    (call-next-method container key))
  (values item))


(defmethod delete-item ((container keyed-bag/set-container) item)
  (call-next-method container (funcall (key container) item)))


;; weird, won't necessary find the item we ask for...
(defmethod find-item ((container keyed-bag/set-container) item)
  (let ((key (funcall (key container) item)))
    (call-next-method container key)))


(defmethod iterate-nodes ((container keyed-bag/set-container) fn)
  (maphash (lambda (k v)
             (let ((item (gethash k (key-map container))))
               (loop repeat v do
                     (funcall fn item))))
           (contents container)))