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 net.sf.oval.Validator.getCollectionFactory;
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.Map;
023    import java.util.Set;
024    
025    /**
026     * @author Sebastian Thomschke
027     */
028    public final class IdentitySet<E> implements Set<E>, Serializable
029    {
030            private static final long serialVersionUID = 1L;
031    
032            private transient Map<Integer, E> map;
033    
034            /**
035             * Constructs a new, empty <tt>IdentitySet</tt>; the backing <tt>Map</tt> instance has
036             * default initial capacity (16) and load factor (0.75).
037             */
038            public IdentitySet()
039            {
040                    map = getCollectionFactory().createMap();
041            }
042    
043            /**
044             * Constructs a new, empty <tt>IdentitySet</tt>; the backing <tt>Map</tt> instance has
045             * the given initial capacity and the default load factor (0.75).
046             */
047            public IdentitySet(final int initialCapacity)
048            {
049                    map = getCollectionFactory().createMap(initialCapacity);
050            }
051    
052            /**
053             * {@inheritDoc}
054             */
055            public boolean add(final E o)
056            {
057                    final int hash = System.identityHashCode(o);
058                    return map.put(hash, o) == null;
059            }
060    
061            /**
062             * {@inheritDoc}
063             */
064            public boolean addAll(final Collection< ? extends E> c)
065            {
066                    int count = 0;
067                    for (final E e : c)
068                            if (add(e)) count++;
069                    return count > 0;
070            }
071    
072            /**
073             * {@inheritDoc}
074             */
075            public void clear()
076            {
077                    map.clear();
078            }
079    
080            /**
081             * {@inheritDoc}
082             */
083            public boolean contains(final Object o)
084            {
085                    final int hash = System.identityHashCode(o);
086                    return map.containsKey(hash);
087            }
088    
089            /**
090             * {@inheritDoc}
091             */
092            public boolean containsAll(final Collection< ? > c)
093            {
094                    throw new UnsupportedOperationException();
095            }
096    
097            /**
098             * {@inheritDoc}
099             */
100            public boolean isEmpty()
101            {
102                    return map.isEmpty();
103            }
104    
105            /**
106             * {@inheritDoc}
107             */
108            public Iterator<E> iterator()
109            {
110                    return map.values().iterator();
111            }
112    
113            /**
114             * Reads the <tt>IdentitySet</tt> instance from a stream.
115             */
116            @SuppressWarnings("unchecked")
117            private void readObject(final ObjectInputStream ois) throws java.io.IOException, ClassNotFoundException
118            {
119                    // materialize any hidden serialization magic
120                    ois.defaultReadObject();
121    
122                    // materialize the size
123                    final int size = ois.readInt();
124    
125                    // materialize the elements
126                    map = getCollectionFactory().createMap(size);
127                    for (int i = 0; i < size; i++)
128                    {
129                            final E o = (E) ois.readObject();
130                            final int hash = System.identityHashCode(o);
131                            map.put(hash, o);
132                    }
133            }
134    
135            /**
136             * {@inheritDoc}
137             */
138            public boolean remove(final Object o)
139            {
140                    final int hash = System.identityHashCode(o);
141                    return map.remove(hash) != null;
142            }
143    
144            /**
145             * {@inheritDoc}
146             */
147            public boolean removeAll(final Collection< ? > c)
148            {
149                    boolean modified = false;
150                    for (final Object e : c)
151                            if (remove(e)) modified = true;
152                    return modified;
153            }
154    
155            /**
156             * {@inheritDoc}
157             */
158            public boolean retainAll(final Collection< ? > c)
159            {
160                    throw new UnsupportedOperationException();
161            }
162    
163            /**
164             * {@inheritDoc}
165             */
166            public int size()
167            {
168                    return map.size();
169            }
170    
171            /**
172             * {@inheritDoc}
173             */
174            public Object[] toArray()
175            {
176                    return map.values().toArray();
177            }
178    
179            /**
180             * {@inheritDoc}
181             */
182            public <T> T[] toArray(final T[] a)
183            {
184                    return map.values().toArray(a);
185            }
186    
187            /**
188             * Writes state of this <tt>IdentitySet</tt> instance to a stream.
189             */
190            private void writeObject(final ObjectOutputStream oos) throws java.io.IOException
191            {
192                    // serialize any hidden serialization magic
193                    oos.defaultWriteObject();
194    
195                    // serialize the set's size
196                    oos.writeInt(map.size());
197    
198                    // serialize the set's elements
199                    for (final E e : map.values())
200                            oos.writeObject(e);
201            }
202    }