1 /* IdentityHashMap.java -- a class providing a hashtable data structure,
2 mapping Object --> Object, which uses object identity for hashing.
3 Copyright (C) 2001 Free Software Foundation, Inc.
5 This file is part of GNU Classpath.
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING. If not, write to the
19 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
22 As a special exception, if you link this library with other files to
23 produce an executable, this library does not by itself cause the
24 resulting executable to be covered by the GNU General Public License.
25 This exception does not however invalidate any other reasons why the
26 executable file might be covered by the GNU General Public License. */
33 * This class provides a hashtable-backed implementation of the
34 * Map interface. Unlike HashMap, it uses object identity to
35 * do its hashing. Also, it uses a linear-probe hash table.
37 * @author Tom Tromey <tromey@redhat.com>
40 public class IdentityHashMap extends AbstractMap
41 implements Map, Serializable, Cloneable
43 private static final int DEFAULT_CAPACITY = 21;
45 /** Create a new IdentityHashMap with the default capacity (21
48 public IdentityHashMap ()
50 this (DEFAULT_CAPACITY);
53 /** Create a new IdentityHashMap with the indicated number of
54 * entries. If the number of elements added to this hash map
55 * exceeds this maximum, the map will grow itself; however, that
56 * incurs a performance penalty.
57 * @param max Initial size
59 public IdentityHashMap (int max)
62 throw new IllegalArgumentException ();
63 table = new Object[2 * max];
64 Arrays.fill (table, emptyslot);
68 /** Create a new IdentityHashMap whose contents are taken from the
70 * @param m The map whose elements are to be put in this map.
72 public IdentityHashMap (Map m)
74 int len = 2 * Math.max (m.size (), DEFAULT_CAPACITY);
75 table = new Object[len];
76 Arrays.fill (table, emptyslot);
82 Arrays.fill (table, emptyslot);
87 * Creates a shallow copy where keys and values are not cloned.
89 public Object clone ()
93 IdentityHashMap copy = (IdentityHashMap) super.clone ();
94 copy.table = (Object[]) table.clone ();
97 catch (CloneNotSupportedException e)
104 public boolean containsKey (Object key)
106 int h = Math.abs (2 * System.identityHashCode (key) % table.length);
112 if (table[h] == emptyslot)
115 if (h > table.length)
122 public boolean containsValue (Object value)
124 for (int i = 1; i < table.length; i += 2)
125 if (table[i] == value)
130 public Set entrySet ()
132 return new AbstractSet ()
139 public Iterator iterator ()
141 return new IdentityIterator (IdentityIterator.ENTRIES);
146 IdentityHashMap.this.clear ();
149 public boolean contains (Object o)
151 if (! (o instanceof Map.Entry))
153 Map.Entry m = (Map.Entry) o;
154 return (IdentityHashMap.this.containsKey (m.getKey ())
155 && IdentityHashMap.this.get (m.getKey ()) == m.getValue ());
158 public boolean remove (Object o)
160 if (! (o instanceof Map.Entry))
162 Map.Entry m = (Map.Entry) o;
163 if (IdentityHashMap.this.containsKey (m.getKey ())
164 && IdentityHashMap.this.get (m.getKey ()) == m.getValue ())
167 IdentityHashMap.this.remove (m.getKey ());
168 return oldsize != size;
175 public Object get (Object key)
177 int h = Math.abs (2 * System.identityHashCode (key) % table.length);
183 if (table[h] == emptyslot)
186 if (h >= table.length)
193 public boolean isEmpty ()
200 return new AbstractSet ()
207 public Iterator iterator ()
209 return new IdentityIterator (IdentityIterator.KEYS);
214 IdentityHashMap.this.clear ();
217 public boolean contains (Object o)
219 return IdentityHashMap.this.containsKey (o);
222 public boolean remove (Object o)
225 IdentityHashMap.this.remove (o);
226 return oldsize != size;
231 public Object put (Object key, Object value)
233 // Rehash is the load factor is too high.
234 if (size * 3 / 2 > table.length)
236 Object[] old = table;
237 table = new Object[old.length * 2];
238 Arrays.fill (table, emptyslot);
240 for (int i = 0; i < old.length; ++i)
242 if (old[i] != tombstone && old[i] != emptyslot)
244 // Just use put. This isn't very efficient, but it is
246 put (old[i], old[i + 1]);
251 int h = Math.abs (2 * System.identityHashCode (key) % table.length);
258 Object r = table[h + 1];
259 table[h + 1] = value;
262 else if (table[h] == tombstone && del == -1)
264 else if (table[h] == emptyslot)
271 if (h >= table.length)
280 table[del + 1] = value;
289 public Object remove (Object key)
291 int h = Math.abs (2 * System.identityHashCode (key) % table.length);
297 Object r = table[h + 1];
298 table[h] = tombstone;
299 table[h + 1] = tombstone;
304 if (h > table.length)
318 public Collection values ()
320 return new AbstractCollection ()
327 public Iterator iterator ()
329 return new IdentityIterator (IdentityIterator.VALUES);
334 IdentityHashMap.this.clear ();
339 private class IdentityIterator implements Iterator
341 static final int KEYS = 0;
342 static final int VALUES = 1;
343 static final int ENTRIES = 2;
347 // Location in the table.
349 // How many items we've seen.
352 IdentityIterator (int type)
359 public boolean hasNext ()
364 public Object next ()
369 if (loc >= table.length)
370 throw new NoSuchElementException ();
371 if (table[loc] != tombstone && table[loc] != emptyslot)
379 public void remove ()
381 if (loc >= table.length
382 || table[loc] == tombstone
383 || table[loc] == emptyslot)
384 throw new IllegalStateException ();
385 table[loc] = tombstone;
386 table[loc + 1] = tombstone;
391 private void readObject (ObjectInputStream s)
392 throws IOException, ClassNotFoundException
394 int num = s.readInt ();
395 for (int i = 0; i < num; ++i)
397 Object key = s.readObject ();
398 Object value = s.readObject ();
403 private void writeObject (ObjectOutputStream s)
407 Iterator it = entrySet ().iterator ();
408 while (it.hasNext ())
410 Map.Entry entry = (Map.Entry) it.next ();
411 s.writeObject (entry.getKey ());
412 s.writeObject (entry.getValue ());
416 // Number of items in hash table.
419 private Object[] table;
421 // This object is used to mark deleted items.
422 private Object tombstone = new Object ();
423 // This object is used to mark empty slots. We need this because
424 // using null is ambiguous.
425 private Object emptyslot = new Object ();