KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > util > WeakSet


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.openide.util;
21
22 import java.io.IOException JavaDoc;
23 import java.io.ObjectInputStream JavaDoc;
24 import java.io.ObjectOutputStream JavaDoc;
25 import java.io.Serializable JavaDoc;
26 import java.lang.ref.ReferenceQueue JavaDoc;
27 import java.lang.ref.WeakReference JavaDoc;
28 import java.util.AbstractSet JavaDoc;
29 import java.util.ArrayList JavaDoc;
30 import java.util.Collection JavaDoc;
31 import java.util.ConcurrentModificationException JavaDoc;
32 import java.util.Iterator JavaDoc;
33
34 /** Set which holds its members by using of WeakReferences.
35 * MT level: unsafe.
36  * <p><strong>Note:</strong> as of JDK 6.0 (b51), you can instead use
37  * <pre>
38  * Set&lt;T&gt; s = Collections.newSetFromMap(new WeakHashMap&lt;T, Boolean&gt;());
39  * </pre>
40 *
41 * @author Ales Novak
42 */

43 public class WeakSet<E> extends AbstractSet JavaDoc<E> implements Cloneable JavaDoc, Serializable JavaDoc {
44     static final long serialVersionUID = 3062376055928236721L;
45
46     /** load factor */
47     private float loadFactor;
48
49     /** Number of items. */
50     private int size;
51
52     /** Modification count */
53     private long modcount;
54
55     /** Reference queue of collected weak refs */
56     private transient ReferenceQueue JavaDoc<E> refq;
57
58     /** Count of <tt>null</tt> in this set */
59     long nullCount;
60
61     /** An array of Entries */
62     private transient Entry<E>[] entries;
63     transient Entry<E> iterChain;
64
65     /** Constructs a new set. */
66     public WeakSet() {
67         this(11, 0.75f);
68     }
69
70     /** Constructs a new set containing the elements in the specified collection.
71     * @param c a collection to add
72     */

73     public WeakSet(Collection JavaDoc<? extends E> c) {
74         this();
75         addAll(c);
76     }
77
78     /** Constructs a new, empty set;
79     * @param initialCapacity initial capacity
80     */

81     public WeakSet(int initialCapacity) {
82         this(initialCapacity, 0.75f);
83     }
84
85     /** Constructs a new, empty set;
86     *
87     * @param initialCapacity initial capacity
88     * @param loadFactor load factor
89     */

90     public WeakSet(int initialCapacity, float loadFactor) {
91         if ((initialCapacity <= 0) || (loadFactor <= 0)) {
92             throw new IllegalArgumentException JavaDoc();
93         }
94
95         size = 0;
96         modcount = 0;
97         this.loadFactor = loadFactor;
98         nullCount = 0;
99         refq = new ReferenceQueue JavaDoc<E>();
100         entries = Entry.createArray(initialCapacity);
101         iterChain = null;
102     }
103
104     /** Adds the specified element to this set if it is not already present.
105     *
106     * @param o an Object to add
107     */

108     public boolean add(E o) {
109         if (o == null) {
110             size++;
111             nullCount++;
112             modcount++;
113
114             return true;
115         }
116
117         Entry e = object2Entry(o);
118
119         if (e != null) {
120             return false;
121         }
122
123         modcount++;
124         size++;
125
126         int hash = hashIt(o);
127         Entry<E> next = entries[hash];
128         iterChain = entries[hash] = new Entry<E>(this, o, refq, next, iterChain);
129         rehash();
130
131         return true;
132     }
133
134     /** Removes all of the elements from this set. */
135     public void clear() {
136         for (int i = 0; i < entries.length; i++) {
137             entries[i] = null;
138         }
139
140         nullCount = 0;
141         modcount++;
142         size = 0;
143         iterChain = null;
144     }
145
146     /** Returns a shallow copy of this WeakSet instance: the elements themselves are not cloned. */
147     public Object JavaDoc clone() {
148         WeakSet<E> nws = new WeakSet<E>(1, loadFactor);
149         nws.size = size;
150         nws.nullCount = nullCount;
151
152         Entry<E>[] cloned = Entry.createArray(entries.length);
153         nws.entries = cloned;
154
155         for (int i = 0; i < cloned.length; i++) {
156             Object JavaDoc ref;
157
158             if ((entries[i] == null) || ((ref = entries[i].get()) == null)) {
159                 cloned[i] = null;
160             } else {
161                 cloned[i] = ((entries[i] == null) ? null : entries[i].clone(nws.refq));
162                 ref = null;
163             }
164
165             // chains into nws iterator chain
166
Entry<E> entry = cloned[i];
167
168             while (entry != null) {
169                 entry.chainIntoIter(nws.iterChain);
170                 nws.iterChain = entry;
171                 entry = entry.next;
172             }
173         }
174
175         return nws;
176     }
177
178     /** Returns true if this set contains the specified element.
179     *
180     * @param o an Object to examine
181     */

182     public boolean contains(Object JavaDoc o) {
183         if (o == null) {
184             return nullCount > 0;
185         }
186
187         return object2Entry(o) != null;
188     }
189
190     /** Returns true if this set contains no elements.
191     */

192     public boolean isEmpty() {
193         return ((nullCount == 0) && (size() == 0));
194     }
195
196     /** Returns an iterator over the elements in this set. */
197     public Iterator JavaDoc<E> iterator() {
198         return new WeakSetIterator();
199     }
200
201     /** Removes the given element from this set if it is present.
202     *
203     * @param o an Object to remove
204     * @return <tt>true</tt> if and only if the Object was successfuly removed.
205     */

206     public boolean remove(Object JavaDoc o) {
207         if (o == null) {
208             if (nullCount > 0) {
209                 nullCount--;
210                 modcount++;
211                 size--;
212             }
213
214             return true;
215         }
216
217         Entry e = object2Entry(o);
218
219         if (e != null) {
220             modcount++;
221             size--;
222             e.remove();
223             rehash();
224
225             return true;
226         }
227
228         return false;
229     }
230
231     /** @return the number of elements in this set (its cardinality). */
232     public int size() {
233         checkRefQueue();
234
235         return size;
236     }
237
238     public <T> T[] toArray(T[] array) {
239         ArrayList JavaDoc<E> list = new ArrayList JavaDoc<E>(array.length);
240         Iterator JavaDoc<E> it = iterator();
241
242         while (it.hasNext()) {
243             list.add(it.next());
244         }
245
246         return list.toArray(array);
247     }
248
249     public Object JavaDoc[] toArray() {
250         ArrayList JavaDoc<E> list = new ArrayList JavaDoc<E>();
251         Iterator JavaDoc<E> it = iterator();
252
253         while (it.hasNext()) {
254             list.add(it.next());
255         }
256
257         return list.toArray();
258     }
259
260     // #14772
261
public String JavaDoc toString() {
262         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
263         Iterator JavaDoc e = iterator();
264         buf.append("[");
265
266         while (e.hasNext()) {
267             buf.append(String.valueOf(e.next()));
268
269             if (e.hasNext()) {
270                 buf.append(", ");
271             }
272         }
273
274         buf.append("]");
275
276         return buf.toString();
277     }
278
279     /** Checks if the queue is empty if not pending weak refs are removed. */
280     void checkRefQueue() {
281         for (;;) {
282             Entry entry = Entry.class.cast(refq.poll());
283
284             if (entry == null) {
285                 break;
286             }
287
288             entry.remove();
289             size--;
290         }
291     }
292
293     /** @return modcount */
294     long modCount() {
295         return modcount;
296     }
297
298     /** @return an index to entries array */
299     int hashIt(Object JavaDoc o) {
300         return (o.hashCode() & 0x7fffffff) % entries.length;
301     }
302
303     /** rehashes this Set */
304     void rehash() {
305         /*
306         float currentLF = ((float) size) / ((float) entries.length);
307         if (currentLF < loadFactor) {
308           return;
309         }
310         */

311     }
312
313     /** @return an Entry with given object */
314     private Entry object2Entry(Object JavaDoc o) {
315         checkRefQueue(); // clear ref q
316

317         int hash = hashIt(o);
318         Entry e = entries[hash];
319
320         if (e == null) {
321             return null;
322         }
323
324         while ((e != null) && !e.equals(o)) {
325             e = e.next;
326         }
327
328         return e;
329     }
330
331     private void writeObject(ObjectOutputStream JavaDoc obtos)
332     throws IOException JavaDoc {
333         obtos.defaultWriteObject();
334         obtos.writeObject(toArray());
335     }
336
337     @SuppressWarnings JavaDoc("unchecked")
338     private void readObject(ObjectInputStream JavaDoc obtis) throws IOException JavaDoc, ClassNotFoundException JavaDoc {
339         obtis.defaultReadObject();
340
341         Object JavaDoc[] arr = (Object JavaDoc[]) obtis.readObject();
342         entries = new Entry[(int) (size * 1.5)];
343         refq = new ReferenceQueue JavaDoc<E>();
344
345         for (int i = 0; i < arr.length; i++) {
346             add((E)arr[i]);
347         }
348     }
349
350     class WeakSetIterator implements Iterator JavaDoc<E> {
351         Entry<E> current;
352         Entry<E> next;
353         E currentObj;
354         E nextObj;
355         final long myModcount;
356         long myNullCount;
357
358         WeakSetIterator() {
359             myModcount = modCount();
360             myNullCount = nullCount;
361             current = null;
362             next = null;
363
364             Entry<E> ee = iterChain;
365
366             if (ee == null) {
367                 return;
368             }
369
370             E o = ee.get();
371
372             while (ee.isEnqueued()) {
373                 ee = ee.iterChainNext;
374
375                 if (ee == null) {
376                     return;
377                 }
378
379                 o = ee.get();
380             }
381
382             nextObj = o;
383             next = ee;
384         }
385
386         public boolean hasNext() {
387             checkModcount();
388
389             return ((myNullCount > 0) || (next != null));
390         }
391
392         public E next() {
393             checkModcount();
394             checkRefQueue();
395
396             if (myNullCount > 0) {
397                 myNullCount--;
398
399                 return null;
400             } else {
401                 if (next == null) {
402                     throw new java.util.NoSuchElementException JavaDoc();
403                 }
404
405                 current = next;
406                 currentObj = nextObj;
407
408                 // move to next requested
409
do {
410                     next = next.iterChainNext;
411
412                     if (next == null) {
413                         break;
414                     }
415
416                     nextObj = next.get();
417                 } while (next.isEnqueued());
418
419                 return currentObj;
420             }
421         }
422
423         public void remove() {
424             checkModcount();
425
426             if (current == null) {
427                 throw new IllegalStateException JavaDoc();
428             }
429
430             current.remove();
431             size--;
432         }
433
434         void checkModcount() {
435             if (myModcount != modCount()) {
436                 throw new ConcurrentModificationException JavaDoc();
437             }
438         }
439     }
440
441     /** Entries of this set */
442     static class Entry<E> extends WeakReference JavaDoc<E> {
443         /** reference to outer WeakSet */
444         private WeakSet<E> set;
445
446         // double linked list
447
Entry<E> prev;
448         Entry<E> next;
449         private final int hashcode;
450         Entry<E> iterChainNext;
451         Entry<E> iterChainPrev;
452
453         Entry(WeakSet<E> set, E referenced, ReferenceQueue JavaDoc<E> q, Entry<E> next, Entry<E> nextInIter) {
454             super(referenced, q);
455             this.set = set;
456
457             this.next = next;
458             this.prev = null;
459
460             if (next != null) {
461                 next.prev = this;
462             }
463
464             if (referenced != null) {
465                 hashcode = set.hashIt(referenced);
466             } else {
467                 hashcode = 0;
468             }
469
470             chainIntoIter(nextInIter);
471         }
472
473         @SuppressWarnings JavaDoc("unchecked")
474         static final <E> Entry<E>[] createArray(int size) {
475             return new Entry[size];
476         }
477
478         void chainIntoIter(Entry<E> nextInIter) {
479             iterChainNext = nextInIter;
480
481             if (nextInIter != null) {
482                 nextInIter.iterChainPrev = this;
483
484                 Object JavaDoc ref = nextInIter.get();
485
486                 if (ref == null) {
487                     nextInIter.remove();
488                 }
489             }
490         }
491
492         /** deques itself */
493         void remove() {
494             if (prev != null) {
495                 prev.next = next;
496             }
497
498             if (next != null) {
499                 next.prev = prev;
500             }
501
502             if (iterChainNext != null) {
503                 iterChainNext.iterChainPrev = iterChainPrev;
504             }
505
506             if (iterChainPrev != null) {
507                 iterChainPrev.iterChainNext = iterChainNext;
508             } else { // root
509
set.iterChain = iterChainNext;
510             }
511
512             if (set.entries[hashcode] == this) {
513                 set.entries[hashcode] = next;
514             }
515
516             prev = null;
517             next = null;
518             iterChainNext = null;
519             iterChainPrev = null;
520         }
521
522         public int hashCode() {
523             return hashcode;
524         }
525
526         public boolean equals(Object JavaDoc o) {
527             Object JavaDoc oo = get();
528
529             if (oo == null) {
530                 return false;
531             } else {
532                 return oo.equals(o);
533             }
534         }
535
536         public Entry<E> clone(ReferenceQueue JavaDoc<E> q) {
537             return new Entry<E>(set, get(), q, next != null ? next.clone(q) : null, null);
538         }
539     }
540 }
541
Popular Tags