1 package org.simantics.databoard.util;
3 import java.util.AbstractSet;
4 import java.util.Collection;
5 import java.util.ConcurrentModificationException;
6 import java.util.IdentityHashMap;
7 import java.util.Iterator;
10 public class IdentityHashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable
12 static final long serialVersionUID = -5024744406713321676L;
14 private transient IdentityHashMap<E,Object> map;
16 // Dummy value to associate with an Object in the backing Map
17 private static final Object PRESENT = new Object();
20 * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
21 * default initial capacity (16) and load factor (0.75).
23 public IdentityHashSet() {
24 map = new IdentityHashMap<E,Object>();
28 * Constructs a new set containing the elements in the specified
29 * collection. The <tt>HashMap</tt> is created with default load factor
30 * (0.75) and an initial capacity sufficient to contain the elements in
31 * the specified collection.
33 * @param c the collection whose elements are to be placed into this set
34 * @throws NullPointerException if the specified collection is null
36 public IdentityHashSet(Collection<? extends E> c) {
37 map = new IdentityHashMap<E,Object>(Math.max((int) (c.size()/.75f) + 1, 16));
43 * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
44 * the specified initial capacity and default load factor (0.75).
46 * @param initialCapacity the initial capacity of the hash table
47 * @throws IllegalArgumentException if the initial capacity is less
50 public IdentityHashSet(int initialCapacity) {
51 map = new IdentityHashMap<E,Object>(initialCapacity);
55 * Returns an iterator over the elements in this set. The elements
56 * are returned in no particular order.
58 * @return an Iterator over the elements in this set
59 * @see ConcurrentModificationException
61 public Iterator<E> iterator() {
62 return map.keySet().iterator();
66 * Returns the number of elements in this set (its cardinality).
68 * @return the number of elements in this set (its cardinality)
75 * Returns <tt>true</tt> if this set contains no elements.
77 * @return <tt>true</tt> if this set contains no elements
79 public boolean isEmpty() {
84 * Returns <tt>true</tt> if this set contains the specified element.
85 * More formally, returns <tt>true</tt> if and only if this set
86 * contains an element <tt>e</tt> such that
87 * <tt>(o==null ? e==null : o.equals(e))</tt>.
89 * @param o element whose presence in this set is to be tested
90 * @return <tt>true</tt> if this set contains the specified element
92 public boolean contains(Object o) {
93 return map.containsKey(o);
97 * Adds the specified element to this set if it is not already present.
98 * More formally, adds the specified element <tt>e</tt> to this set if
99 * this set contains no element <tt>e2</tt> such that
100 * <tt>(e==null ? e2==null : e.equals(e2))</tt>.
101 * If this set already contains the element, the call leaves the set
102 * unchanged and returns <tt>false</tt>.
104 * @param e element to be added to this set
105 * @return <tt>true</tt> if this set did not already contain the specified
108 public boolean add(E e) {
109 return map.put(e, PRESENT)==null;
113 * Removes the specified element from this set if it is present.
114 * More formally, removes an element <tt>e</tt> such that
115 * <tt>(o==null ? e==null : o.equals(e))</tt>,
116 * if this set contains such an element. Returns <tt>true</tt> if
117 * this set contained the element (or equivalently, if this set
118 * changed as a result of the call). (This set will not contain the
119 * element once the call returns.)
121 * @param o object to be removed from this set, if present
122 * @return <tt>true</tt> if the set contained the specified element
124 public boolean remove(Object o) {
125 return map.remove(o)==PRESENT;
129 * Removes all of the elements from this set.
130 * The set will be empty after this call returns.
132 public void clear() {
137 * Returns a shallow copy of this <tt>HashSet</tt> instance: the elements
138 * themselves are not cloned.
140 * @return a shallow copy of this set
142 @SuppressWarnings("unchecked")
143 public Object clone() {
145 IdentityHashSet<E> newSet = (IdentityHashSet<E>) super.clone();
146 newSet.map = (IdentityHashMap<E, Object>) map.clone();
148 } catch (CloneNotSupportedException e) {
149 throw new InternalError();
154 * Save the state of this <tt>HashSet</tt> instance to a stream (that is,
157 * @serialData The capacity of the backing <tt>HashMap</tt> instance
158 * (int), and its load factor (float) are emitted, followed by
159 * the size of the set (the number of elements it contains)
160 * (int), followed by all of its elements (each an Object) in
161 * no particular order.
163 private void writeObject(java.io.ObjectOutputStream s)
164 throws java.io.IOException {
165 // Write out any hidden serialization magic
166 s.defaultWriteObject();
169 s.writeInt(map.size());
171 // Write out all elements in the proper order.
172 for (Iterator<E> i=map.keySet().iterator(); i.hasNext(); )
173 s.writeObject(i.next());
177 * Reconstitute the <tt>HashSet</tt> instance from a stream (that is,
180 @SuppressWarnings("unchecked")
181 private void readObject(java.io.ObjectInputStream s)
182 throws java.io.IOException, ClassNotFoundException {
183 // Read in any hidden serialization magic
184 s.defaultReadObject();
187 int size = s.readInt();
189 // Read in HashMap capacity and load factor and create backing HashMap
190 map = new IdentityHashMap<E,Object>(size);
193 // Read in all elements in the proper order.
194 for (int i=0; i<size; i++) {
195 E e = (E) s.readObject();