001    /*--------------------------------------------------------------------------+
002    $Id: IdentityHashSet.java 26283 2010-02-18 11:18:57Z juergens $
003    |                                                                          |
004    | Copyright 2005-2010 Technische Universitaet Muenchen                     |
005    |                                                                          |
006    | Licensed under the Apache License, Version 2.0 (the "License");          |
007    | you may not use this file except in compliance with the License.         |
008    | You may obtain a copy of the License at                                  |
009    |                                                                          |
010    |    http://www.apache.org/licenses/LICENSE-2.0                            |
011    |                                                                          |
012    | Unless required by applicable law or agreed to in writing, software      |
013    | distributed under the License is distributed on an "AS IS" BASIS,        |
014    | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
015    | See the License for the specific language governing permissions and      |
016    | limitations under the License.                                           |
017    +--------------------------------------------------------------------------*/
018    package edu.tum.cs.commons.collections;
019    
020    import java.util.AbstractSet;
021    import java.util.Collection;
022    import java.util.IdentityHashMap;
023    import java.util.Iterator;
024    
025    /**
026     * This class implements a set based on referential equality similar to JDK
027     * class {@link IdentityHashMap}. This class can be e.g. used to implement
028     * listener lists that should not rely on the listeners <code>equals()</code>-methods.
029     * <p>
030     * The implementation is based on class {@link java.util.HashSet} that also uses
031     * an underlying hash map.
032     * 
033     * 
034     * @author Florian Deissenboeck
035     * @author $Author: juergens $
036     * @version $Rev: 26283 $
037     * @levd.rating GREEN Hash: A3753EB461A1466EFCA699DCE847468B
038     */
039    public class IdentityHashSet<E> extends AbstractSet<E> {
040    
041            /** Dummy object for the map. */
042            private static final Object PRESENT = new Object();
043    
044            /** The map that actually stores the values. */
045            private final IdentityHashMap<E, Object> map;
046    
047            /** Create new identity hash set. */
048            public IdentityHashSet() {
049                    map = new IdentityHashMap<E, Object>();
050            }
051    
052            /** Create new identity hash set from an existing collection. */
053            public IdentityHashSet(Collection<? extends E> collection) {
054                    this(collection.size());
055    
056                    for (E e : collection) {
057                            add(e);
058                    }
059            }
060    
061            /** Create new identity hash set with an expected maximum size. */
062            public IdentityHashSet(int expectedMaxSize) {
063                    map = new IdentityHashMap<E, Object>(expectedMaxSize);
064            }
065    
066            /**
067             * Adds the specified element to this set if it is not already present.
068             * 
069             * @param o
070             *            element to be added to this set.
071             * @return <tt>true</tt> if the set did not already contain the specified
072             *         element.
073             */
074            @Override
075            public boolean add(E o) {
076                    return map.put(o, PRESENT) == null;
077            }
078    
079            /**
080             * Removes all of the elements from this set.
081             */
082            @Override
083            public void clear() {
084                    map.clear();
085            }
086    
087            /**
088             * Returns a shallow copy of this <tt>IdentityHashSet</tt> instance: the
089             * elements themselves are not cloned.
090             * 
091             * @return a shallow copy of this set.
092             */
093            @Override
094            public IdentityHashSet<E> clone() {
095                    return new IdentityHashSet<E>(this);
096            }
097    
098            /**
099             * Returns <tt>true</tt> if this set contains the specified element.
100             * 
101             * @param o
102             *            element whose presence in this set is to be tested.
103             * @return <tt>true</tt> if this set contains the specified element.
104             */
105            @Override
106            public boolean contains(Object o) {
107                    return map.containsKey(o);
108            }
109    
110            /**
111             * Returns <tt>true</tt> if this set contains no elements.
112             * 
113             * @return <tt>true</tt> if this set contains no elements.
114             */
115            @Override
116            public boolean isEmpty() {
117                    return map.isEmpty();
118            }
119    
120            /** Return iterator over the set. */
121            @Override
122            public Iterator<E> iterator() {
123                    return map.keySet().iterator();
124            }
125    
126            /**
127             * Removes the specified element from this set if it is present.
128             * 
129             * @param o
130             *            object to be removed from this set, if present.
131             * @return <tt>true</tt> if the set contained the specified element.
132             */
133            @Override
134            public boolean remove(Object o) {
135                    return map.remove(o) == PRESENT;
136            }
137    
138            /**
139             * Get set size.
140             */
141            @Override
142            public int size() {
143                    return map.size();
144            }
145    
146    }