001    /*******************************************************************************
002     * Portions created by Sebastian Thomschke are copyright (c) 2005-2011 Sebastian
003     * Thomschke.
004     * 
005     * All Rights Reserved. This program and the accompanying materials
006     * are made available under the terms of the Eclipse Public License v1.0
007     * which accompanies this distribution, and is available at
008     * http://www.eclipse.org/legal/epl-v10.html
009     * 
010     * Contributors:
011     *     Sebastian Thomschke - initial implementation.
012     *******************************************************************************/
013    package net.sf.oval.internal.util;
014    
015    import static java.lang.Boolean.TRUE;
016    
017    import java.io.ObjectInputStream;
018    import java.io.ObjectOutputStream;
019    import java.io.Serializable;
020    import java.util.Collection;
021    import java.util.Iterator;
022    import java.util.Set;
023    import java.util.WeakHashMap;
024    
025    /**
026     * @author Sebastian Thomschke
027     */
028    public final class WeakHashSet<E> implements Set<E>, Serializable
029    {
030            private static final long serialVersionUID = 1L;
031    
032            private transient WeakHashMap<E, Object> map;
033    
034            /**
035             * Constructs a new, empty <tt>WeakHashSet</tt>; the backing <tt>WeakHashMap</tt> instance has
036             * default initial capacity (16) and load factor (0.75).
037             */
038            public WeakHashSet()
039            {
040                    map = new WeakHashMap<E, Object>();
041            }
042    
043            /**
044             * Constructs a new, empty <tt>WeakHashSet</tt>; the backing <tt>WeakHashMap</tt> instance has
045             * the given initial capacity and the default load factor (0.75).
046             */
047            public WeakHashSet(final int initialCapacity)
048            {
049                    map = new WeakHashMap<E, Object>(initialCapacity);
050            }
051    
052            /**
053             * {@inheritDoc}
054             */
055            public boolean add(final E o)
056            {
057                    return map.put(o, TRUE) == null;
058            }
059    
060            /**
061             * {@inheritDoc}
062             */
063            public boolean addAll(final Collection< ? extends E> c)
064            {
065                    int count = 0;
066                    for (final E e : c)
067                            if (add(e)) count++;
068                    return count > 0;
069            }
070    
071            public void clear()
072            {
073                    map.clear();
074            }
075    
076            /**
077             * {@inheritDoc}
078             */
079            public boolean contains(final Object o)
080            {
081                    return map.containsKey(o);
082            }
083    
084            /**
085             * {@inheritDoc}
086             */
087            public boolean containsAll(final Collection< ? > c)
088            {
089                    return map.keySet().containsAll(c);
090            }
091    
092            /**
093             * {@inheritDoc}
094             */
095            @Override
096            public boolean equals(final Object o)
097            {
098                    if (o == this) return true;
099    
100                    if (!(o instanceof Set< ? >)) return false;
101    
102                    final Set< ? > set = (Set< ? >) o;
103    
104                    if (set.size() != size()) return false;
105    
106                    return containsAll(set);
107            }
108    
109            /**
110             * {@inheritDoc}
111             */
112            @Override
113            public int hashCode()
114            {
115                    int hash = 0;
116                    for (final E e : map.keySet())
117                            if (e != null) hash += e.hashCode();
118                    return hash;
119            }
120    
121            /**
122             * {@inheritDoc}
123             */
124            public boolean isEmpty()
125            {
126                    return map.isEmpty();
127            }
128    
129            /**
130             * {@inheritDoc}
131             */
132            public Iterator<E> iterator()
133            {
134                    return map.keySet().iterator();
135            }
136    
137            /**
138             * Reads the <tt>WeakHashSet</tt> instance from a stream.
139             */
140            @SuppressWarnings("unchecked")
141            private void readObject(final ObjectInputStream ois) throws java.io.IOException, ClassNotFoundException
142            {
143                    // materialize any hidden serialization magic
144                    ois.defaultReadObject();
145    
146                    // materialize the size
147                    final int size = ois.readInt();
148    
149                    // materialize the elements
150                    map = new WeakHashMap<E, Object>(size);
151                    for (int i = 0; i < size; i++)
152                            map.put((E) ois.readObject(), TRUE);
153            }
154    
155            /**
156             * {@inheritDoc}
157             */
158            public boolean remove(final Object o)
159            {
160                    return map.remove(o) == TRUE;
161            }
162    
163            /**
164             * {@inheritDoc}
165             */
166            public boolean removeAll(final Collection< ? > c)
167            {
168                    return map.keySet().removeAll(c);
169            }
170    
171            /**
172             * {@inheritDoc}
173             */
174            public boolean retainAll(final Collection< ? > c)
175            {
176                    return map.keySet().retainAll(c);
177            }
178    
179            /**
180             * {@inheritDoc}
181             */
182            public int size()
183            {
184                    return map.size();
185            }
186    
187            /**
188             * {@inheritDoc}
189             */
190            public Object[] toArray()
191            {
192                    return map.keySet().toArray();
193            }
194    
195            /**
196             * {@inheritDoc}
197             */
198            public <T> T[] toArray(final T[] a)
199            {
200                    return map.keySet().toArray(a);
201            }
202    
203            /**
204             * Writes the state of this <tt>WeakHashSet</tt> instance to a stream.
205             */
206            private void writeObject(final ObjectOutputStream oos) throws java.io.IOException
207            {
208                    // serialize any hidden serialization magic
209                    oos.defaultWriteObject();
210    
211                    // serialize the set's size
212                    oos.writeInt(map.size());
213    
214                    // serialize the set's elements
215                    for (final E e : map.keySet())
216                            oos.writeObject(e);
217            }
218    }