001: /*
002: * file: WeakHashSet.java
003: * package: oreilly.hcj.references
004: *
005: * This software is granted under the terms of the Common Public License,
006: * CPL, which may be found at the following URL:
007: * http://www-124.ibm.com/developerworks/oss/CPLv1.0.htm
008: *
009: * Copyright(c) 2003-2005 by the authors indicated in the @author tags.
010: * All Rights are Reserved by the various authors.
011: *
012: ########## DO NOT EDIT ABOVE THIS LINE ########## */
013:
014: package oreilly.hcj.references;
015:
016: import java.util.AbstractSet;
017: import java.util.Collection;
018: import java.util.Iterator;
019: import java.util.Set;
020: import java.util.WeakHashMap;
021:
022: /**
023: * Implements a HashSet where the objects given are stored in weak references.
024: *
025: * <p>
026: * Uses the WeakHashMap class as a backing store to implement a set of objects that are
027: * stored as weak references. All information concerning using keys in the WeakHashMap
028: * class pertain to this class and it is reccomended that the user of this class review
029: * that material before using the class.
030: * </p>
031: *
032: * <p>
033: * Because this set contains only weak references, it is not serializable. If one tried
034: * to serialize a weak reference, the results would be highly unpredictable as the
035: * object could likely vanish from memory before the proces was even completed. Users of
036: * this class must use transient when the containing class uses this set.
037: * </p>
038: *
039: * <p>
040: * Because of the semantics of the weak references, the value null is not allowed in this
041: * set.
042: * </p>
043: *
044: * <p>
045: * This collection is not identity based but equality based. This can cause some
046: * confusion as you cannot put in two objects whose <tt>equals()</tt> methods return
047: * true. It also means that an object being held is not necessarily the same one that
048: * the user is holding. For example, you could have a String with the value 'fred' at
049: * memory location X and ther could be another String with the value 'fred' at memory
050: * location Y. The first instance is in the set but the second isn't.
051: * </p>
052: *
053: * @author <a href="mailto:worderisor@yahoo.com">Robert Simmons jr.</a>
054: * @version $Revision: 1.1 $
055: *
056: * @see java.lang.util.WeakHashMap
057: * @see java.lang.ref.WeakReference
058: */
059: public class WeakHashSet extends AbstractSet implements Set {
060: /** Dummy value used as a value object. */
061: private static final Object DUMMY = new String("DUMMY"); //$NON-NLS-1$
062:
063: /** Holds the backing store. */
064: WeakHashMap backingStore = new WeakHashMap();
065:
066: /**
067: * Constructs a new empty WeakHashSet with default values passed the the backing
068: * store.
069: *
070: * @see java.util.WeakHashMap#WeakHashMap()
071: */
072: public WeakHashSet() {
073: backingStore = new WeakHashMap();
074: }
075:
076: /**
077: * Constructs a new WeakHashSet with default values passed the the backing store and
078: * fills it with the given collection. Note that duplicates in the collection will
079: * merely be overwritten
080: *
081: * @see java.util.WeakHashMap#WeakHashMap(Collection)
082: */
083: public WeakHashSet(final Collection c) {
084: backingStore = new WeakHashMap(Math.max(
085: (int) (c.size() / .75f) + 1, 16));
086: addAll(c);
087: }
088:
089: /**
090: * Constructs a new WeakHashSet with the values given passed the the backing store.
091: *
092: * @see java.util.WeakHashMap#WeakHashMap(int, float)
093: */
094: public WeakHashSet(final int initialCapacity, final float loadFactor) {
095: backingStore = new WeakHashMap(initialCapacity, loadFactor);
096: }
097:
098: /**
099: * Constructs a new WeakHashSet with the values given passed the the backing store.
100: *
101: * @see java.util.WeakHashMap#WeakHashMap(int)
102: */
103: public WeakHashSet(final int initialCapacity) {
104: backingStore = new WeakHashMap(initialCapacity);
105: }
106:
107: /**
108: * {@inheritDoc}
109: */
110: public boolean isEmpty() {
111: return backingStore.keySet().isEmpty();
112: }
113:
114: /**
115: * {@inheritDoc}
116: *
117: * @throws NullPointerException If the user tries to add null to the set.
118: */
119: public boolean add(final Object o) {
120: if (o == null) {
121: throw new NullPointerException();
122: }
123:
124: return backingStore.put(o, DUMMY) == null;
125: }
126:
127: /**
128: * {@inheritDoc}
129: *
130: * @see #add(Object)
131: */
132: public boolean addAll(final Collection c) {
133: boolean changed = false;
134: Iterator iter = c.iterator();
135:
136: while (iter.hasNext()) {
137: changed = (changed | (backingStore.put(iter.next(), DUMMY) != DUMMY));
138: }
139:
140: return changed;
141: }
142:
143: /**
144: * {@inheritDoc}
145: */
146: public void clear() {
147: backingStore.clear();
148: }
149:
150: /**
151: * {@inheritDoc}
152: */
153: public boolean contains(final Object o) {
154: return backingStore.containsKey(o);
155: }
156:
157: /**
158: * {@inheritDoc}
159: */
160: public boolean containsAll(final Collection c) {
161: return backingStore.keySet().containsAll(c);
162: }
163:
164: /**
165: * {@inheritDoc}
166: */
167: public boolean equals(final Object o) {
168: return backingStore.equals(o);
169: }
170:
171: /**
172: * Returns the hash code value for this set.
173: *
174: * <p>
175: * Gives back the hashCode for the backing store key set. The user should be aware,
176: * however, that this hash code can change without user intervention as the objects
177: * in the collection can easily be collected microseconds after completetion of the
178: * method. It is not reccomended that the user rely on this hash code for
179: * consistency
180: * </p>
181: *
182: * @return The hashcode for this object.
183: */
184: public int hashCode() {
185: return backingStore.keySet().hashCode();
186: }
187:
188: /**
189: * Returns an iterator over the elements contained in this collection.
190: *
191: * <p>
192: * Note that this iterator is extremely volatile because the user may iterate over an
193: * element in the set and find seconds later that it has been removed. This is
194: * because of the semantics of weak references which act like a second thread is
195: * silently modifying the collection. For this reason, it is advisable that if the
196: * user wants to do something with the set that they maintain a strong reference to
197: * the object and not rely on it being in the collection for them.
198: * </p>
199: *
200: * <p>
201: * This iterator is fail fast and WeakReference transparrent. By this we mean that
202: * the iterator simply ignores objects pending in the reference queue for cleanup.
203: * </p>
204: *
205: * @return The iterator.
206: */
207: public Iterator iterator() {
208: return backingStore.keySet().iterator();
209: }
210:
211: /**
212: * {@inheritDoc}
213: */
214: public boolean remove(final Object o) {
215: return backingStore.keySet().remove(o);
216: }
217:
218: /**
219: * {@inheritDoc}
220: */
221: public boolean removeAll(final Collection c) {
222: return backingStore.keySet().removeAll(c);
223: }
224:
225: /**
226: * {@inheritDoc}
227: */
228: public boolean retainAll(final Collection c) {
229: return backingStore.keySet().retainAll(c);
230: }
231:
232: /**
233: * {@inheritDoc}
234: */
235: public int size() {
236: return backingStore.keySet().size();
237: }
238:
239: /**
240: * {@inheritDoc}
241: */
242: public Object[] toArray() {
243: return backingStore.keySet().toArray();
244: }
245:
246: /**
247: * {@inheritDoc}
248: */
249: public Object[] toArray(final Object[] a) {
250: return backingStore.keySet().toArray(a);
251: }
252:
253: /**
254: * {@inheritDoc}
255: */
256: public String toString() {
257: return backingStore.keySet().toString();
258: }
259:
260: /**
261: * {@inheritDoc}
262: */
263: protected Object clone() throws CloneNotSupportedException {
264: throw new CloneNotSupportedException();
265: }
266: }
267:
268: /* ########## End of File ########## */
|