1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package fulmine.util.collection;
17
18 import java.util.Collection;
19 import java.util.Iterator;
20 import java.util.Map;
21 import java.util.Set;
22
23 import fulmine.util.reference.IReferenceCounter;
24 import fulmine.util.reference.ReferenceCounter;
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 public final class TtlSet<COMPONENT> implements Set<COMPONENT>
41 {
42
43
44
45
46
47
48
49
50
51 private final class DelegateIterator implements Iterator<COMPONENT>
52 {
53
54 private final Iterator<COMPONENT> delegate;
55
56 private COMPONENT next;
57
58 private DelegateIterator(Iterator<COMPONENT> delegate)
59 {
60 super();
61 this.delegate = delegate;
62 }
63
64 public boolean hasNext()
65 {
66 return this.delegate.hasNext();
67 }
68
69 public COMPONENT next()
70 {
71 this.next = this.delegate.next();
72 return this.next;
73 }
74
75 public void remove()
76 {
77 if (this.next != null)
78 {
79 if (TtlSet.this.decrementTtl(this.next))
80 {
81 this.delegate.remove();
82 }
83 }
84 }
85 }
86
87
88 public static final int DEFAULT_TTL = 3;
89
90
91 private final IReferenceCounter<COMPONENT> ttl;
92
93
94 private final Set<COMPONENT> inner;
95
96
97 private final int startingTtl;
98
99
100
101
102
103 public TtlSet()
104 {
105 this(TtlSet.DEFAULT_TTL);
106 }
107
108
109
110
111
112
113
114
115 public TtlSet(int ttl)
116 {
117 super();
118 this.inner = CollectionFactory.newSet();
119 this.ttl = new ReferenceCounter<COMPONENT>();
120 this.startingTtl = ttl;
121 }
122
123 public boolean add(COMPONENT o)
124 {
125 final boolean added = this.inner.add(o);
126 if (added)
127 {
128 ttl.adjustCount(o, startingTtl);
129 }
130 return added;
131 }
132
133 public boolean addAll(Collection<? extends COMPONENT> c)
134 {
135 boolean added = false;
136 for (COMPONENT component : c)
137 {
138 added |= add(component);
139 }
140 return added;
141 }
142
143
144
145
146
147 public void clear()
148 {
149 final Iterator<COMPONENT> iterator = this.iterator();
150 while (iterator.hasNext())
151 {
152 iterator.next();
153 iterator.remove();
154 }
155 }
156
157 public boolean contains(Object o)
158 {
159 return this.inner.contains(o);
160 }
161
162 public boolean containsAll(Collection<?> c)
163 {
164 return this.inner.containsAll(c);
165 }
166
167 public boolean isEmpty()
168 {
169 return this.inner.isEmpty();
170 }
171
172 public Iterator<COMPONENT> iterator()
173 {
174 return this.new DelegateIterator(this.inner.iterator());
175 }
176
177
178
179
180
181
182
183
184
185 public boolean remove(Object o)
186 {
187 if (decrementTtl(o))
188 {
189 return this.inner.remove(o);
190 }
191 return false;
192 }
193
194
195
196
197
198
199
200
201
202
203 @SuppressWarnings("unchecked")
204 private boolean decrementTtl(Object o)
205 {
206 this.ttl.adjustCount((COMPONENT) o, -1);
207 return (this.ttl.getCount((COMPONENT) o) == 0);
208 }
209
210
211
212
213
214
215
216
217
218 public boolean removeAll(Collection<?> c)
219 {
220 boolean changed = false;
221 if (c != null)
222 {
223
224 Set<?> other = CollectionFactory.newSet(c);
225 for (Object object : other)
226 {
227 changed |= remove(object);
228 }
229 }
230 return changed;
231 }
232
233
234
235
236
237
238 public boolean retainAll(Collection<?> c)
239 {
240 throw new UnsupportedOperationException();
241 }
242
243 public int size()
244 {
245 return this.inner.size();
246 }
247
248 public Object[] toArray()
249 {
250 return this.inner.toArray();
251 }
252
253 public <T> T[] toArray(T[] a)
254 {
255 return this.inner.toArray(a);
256 }
257
258 @SuppressWarnings("boxing")
259 @Override
260 public String toString()
261 {
262 Map<COMPONENT, Integer> stringValue =
263 CollectionFactory.newMap(this.inner.size());
264 for (COMPONENT element : this.inner)
265 {
266 stringValue.put(element, this.ttl.getCount(element));
267 }
268 return this.getClass().getSimpleName()
269 + CollectionUtils.toFormattedString(stringValue);
270 }
271
272 @Override
273 public boolean equals(Object o)
274 {
275 return this.inner.equals(o);
276 }
277
278 @Override
279 public int hashCode()
280 {
281 return this.inner.hashCode();
282 }
283 }