[armedbear-cvs] r12965 - trunk/abcl/src/org/armedbear/lisp

Erik Huelsmann ehuelsmann at common-lisp.net
Sat Oct 9 20:50:41 UTC 2010


Author: ehuelsmann
Date: Sat Oct  9 16:50:41 2010
New Revision: 12965

Log:
Reduce our number of hash table implementations to 1 (from 4)
by abstracting out the concept of "key equality" and "hash code
retrieval" into a Comparator class.

The other classes are left in place for now, but have been reduced
to simple wrappers around the HashTable class.

While at it, reformat HashTable.java (sorry about that - 
  it obfuscates the functional changes).

Modified:
   trunk/abcl/src/org/armedbear/lisp/EqHashTable.java
   trunk/abcl/src/org/armedbear/lisp/EqlHashTable.java
   trunk/abcl/src/org/armedbear/lisp/EqualHashTable.java
   trunk/abcl/src/org/armedbear/lisp/EqualpHashTable.java
   trunk/abcl/src/org/armedbear/lisp/HashTable.java

Modified: trunk/abcl/src/org/armedbear/lisp/EqHashTable.java
==============================================================================
--- trunk/abcl/src/org/armedbear/lisp/EqHashTable.java	(original)
+++ trunk/abcl/src/org/armedbear/lisp/EqHashTable.java	Sat Oct  9 16:50:41 2010
@@ -35,128 +35,10 @@
 
 public final class EqHashTable extends HashTable
 {
-    private LispObject cachedKey;
-    private int cachedIndex;
-
-    private int mask;
-
     public EqHashTable(int size, LispObject rehashSize,
                        LispObject rehashThreshold)
     {
-        super(calculateInitialCapacity(size), rehashSize, rehashThreshold);
-        mask = buckets.length - 1;
-    }
-
-    @Override
-    public Symbol getTest()
-    {
-        return Symbol.EQ;
-    }
-
-    @Override
-    public synchronized LispObject get(LispObject key)
-    {
-        final int index;
-        if (key == cachedKey) {
-            index = cachedIndex;
-        } else {
-            index = key.sxhash() & mask;
-            cachedKey = key;
-            cachedIndex = index;
-        }
-        HashEntry e = buckets[index];
-        while (e != null) {
-            if (key == e.key)
-                return e.value;
-            e = e.next;
-        }
-        return null;
-    }
-
-    @Override
-    public synchronized void put(LispObject key, LispObject value)
-    {
-        int index;
-        if (key == cachedKey) {
-            index = cachedIndex;
-        } else {
-            index = key.sxhash() & mask;
-            cachedKey = key;
-            cachedIndex = index;
-        }
-        HashEntry e = buckets[index];
-        while (e != null) {
-            if (key == e.key) {
-                e.value = value;
-                return;
-            }
-            e = e.next;
-        }
-        // Not found. We need to add a new entry.
-        if (++count > threshold) {
-            rehash();
-            // Need a new hash value to suit the bigger table.
-            index = key.sxhash() & mask;
-            cachedKey = key;
-            cachedIndex = index;
-        }
-        e = new HashEntry(key, value);
-        e.next = buckets[index];
-        buckets[index] = e;
-    }
-
-    @Override
-    public LispObject remove(LispObject key)
-    {
-        final int index;
-        if (key == cachedKey) {
-            index = cachedIndex;
-        } else {
-            index = key.sxhash() & mask;
-            cachedKey = key;
-            cachedIndex = index;
-        }
-        HashEntry e = buckets[index];
-        HashEntry last = null;
-        while (e != null) {
-            if (key == e.key) {
-                if (last == null)
-                    buckets[index] = e.next;
-                else
-                    last.next = e.next;
-                --count;
-                return e.value;
-            }
-            last = e;
-            e = e.next;
-        }
-        return null;
-    }
-
-    @Override
-    protected void rehash()
-    {
-        cachedKey = null; // Invalidate the cache!
-        HashEntry[] oldBuckets = buckets;
-        final int newCapacity = buckets.length * 2;
-        threshold = (int) (newCapacity * loadFactor);
-        buckets = new HashEntry[newCapacity];
-        mask = buckets.length - 1;
-        for (int i = oldBuckets.length; i-- > 0;) {
-            HashEntry e = oldBuckets[i];
-            while (e != null) {
-                final int index = e.key.sxhash() & mask;
-                HashEntry dest = buckets[index];
-                if (dest != null) {
-                    while (dest.next != null)
-                        dest = dest.next;
-                    dest.next = e;
-                } else
-                    buckets[index] = e;
-                HashEntry next = e.next;
-                e.next = null;
-                e = next;
-            }
-        }
+        super(new Comparator(), calculateInitialCapacity(size),
+                rehashSize, rehashThreshold);
     }
 }

Modified: trunk/abcl/src/org/armedbear/lisp/EqlHashTable.java
==============================================================================
--- trunk/abcl/src/org/armedbear/lisp/EqlHashTable.java	(original)
+++ trunk/abcl/src/org/armedbear/lisp/EqlHashTable.java	Sat Oct  9 16:50:41 2010
@@ -35,110 +35,10 @@
 
 public final class EqlHashTable extends HashTable
 {
-  private int mask;
-
   public EqlHashTable(int size, LispObject rehashSize,
                       LispObject rehashThreshold)
   {
-    super(calculateInitialCapacity(size), rehashSize, rehashThreshold);
-    mask = buckets.length - 1;
-  }
-
-  @Override
-  public Symbol getTest()
-  {
-    return Symbol.EQL;
-  }
-
-  @Override
-  public synchronized LispObject get(LispObject key)
-  {
-    HashEntry e = buckets[key.sxhash() & mask];
-    while (e != null)
-      {
-        if (key.eql(e.key))
-          return e.value;
-        e = e.next;
-      }
-    return null;
-  }
-
-  @Override
-  public synchronized void put(LispObject key, LispObject value)
-  {
-    int index = key.sxhash() & mask;
-    HashEntry e = buckets[index];
-    while (e != null)
-      {
-        if (key.eql(e.key))
-          {
-            e.value = value;
-            return;
-          }
-        e = e.next;
-      }
-    // Not found. We need to add a new entry.
-    if (++count > threshold)
-      {
-        rehash();
-        // Need a new hash value to suit the bigger table.
-        index = key.sxhash() & mask;
-      }
-    e = new HashEntry(key, value);
-    e.next = buckets[index];
-    buckets[index] = e;
-  }
-
-  @Override
-  public LispObject remove(LispObject key)
-  {
-    final int index = key.sxhash() & mask;
-    HashEntry e = buckets[index];
-    HashEntry last = null;
-    while (e != null)
-      {
-        if (key.eql(e.key))
-          {
-            if (last == null)
-              buckets[index] = e.next;
-            else
-              last.next = e.next;
-            --count;
-            return e.value;
-          }
-        last = e;
-        e = e.next;
-      }
-    return null;
-  }
-
-  @Override
-  protected void rehash()
-  {
-    HashEntry[] oldBuckets = buckets;
-    int newCapacity = buckets.length * 2;
-    threshold = (int) (newCapacity * loadFactor);
-    buckets = new HashEntry[newCapacity];
-    mask = buckets.length - 1;
-    for (int i = oldBuckets.length; i-- > 0;)
-      {
-        HashEntry e = oldBuckets[i];
-        while (e != null)
-          {
-            final int index = e.key.sxhash() & mask;
-            HashEntry dest = buckets[index];
-            if (dest != null)
-              {
-                while (dest.next != null)
-                  dest = dest.next;
-                dest.next = e;
-              }
-            else
-              buckets[index] = e;
-            HashEntry next = e.next;
-            e.next = null;
-            e = next;
-          }
-      }
+    super(new EqlComparator(), calculateInitialCapacity(size),
+            rehashSize, rehashThreshold);
   }
 }

Modified: trunk/abcl/src/org/armedbear/lisp/EqualHashTable.java
==============================================================================
--- trunk/abcl/src/org/armedbear/lisp/EqualHashTable.java	(original)
+++ trunk/abcl/src/org/armedbear/lisp/EqualHashTable.java	Sat Oct  9 16:50:41 2010
@@ -35,110 +35,10 @@
 
 public final class EqualHashTable extends HashTable
 {
-  private int mask;
-
   public EqualHashTable(int size, LispObject rehashSize,
                         LispObject rehashThreshold)
   {
-    super(calculateInitialCapacity(size), rehashSize, rehashThreshold);
-    mask = buckets.length - 1;
-  }
-
-  @Override
-  public Symbol getTest()
-  {
-    return Symbol.EQUAL;
-  }
-
-  @Override
-  public synchronized LispObject get(LispObject key)
-  {
-    HashEntry e = buckets[key.sxhash() & mask];
-    while (e != null)
-      {
-        if (key == e.key || key.equal(e.key))
-          return e.value;
-        e = e.next;
-      }
-    return null;
-  }
-
-  @Override
-  public synchronized void put(LispObject key, LispObject value)
-  {
-    int index = key.sxhash() & mask;
-    HashEntry e = buckets[index];
-    while (e != null)
-      {
-        if (key == e.key || key.equal(e.key))
-          {
-            e.value = value;
-            return;
-          }
-        e = e.next;
-      }
-    // Not found. We need to add a new entry.
-    if (++count > threshold)
-      {
-        rehash();
-        // Need a new hash value to suit the bigger table.
-        index = key.sxhash() & mask;
-      }
-    e = new HashEntry(key, value);
-    e.next = buckets[index];
-    buckets[index] = e;
-  }
-
-  @Override
-  public LispObject remove(LispObject key)
-  {
-    final int index = key.sxhash() & mask;
-    HashEntry e = buckets[index];
-    HashEntry last = null;
-    while (e != null)
-      {
-        if (key == e.key || key.equal(e.key))
-          {
-            if (last == null)
-              buckets[index] = e.next;
-            else
-              last.next = e.next;
-            --count;
-            return e.value;
-          }
-        last = e;
-        e = e.next;
-      }
-    return null;
-  }
-
-  @Override
-  protected void rehash()
-  {
-    HashEntry[] oldBuckets = buckets;
-    int newCapacity = buckets.length * 2;
-    threshold = (int) (newCapacity * loadFactor);
-    buckets = new HashEntry[newCapacity];
-    mask = buckets.length - 1;
-    for (int i = oldBuckets.length; i-- > 0;)
-      {
-        HashEntry e = oldBuckets[i];
-        while (e != null)
-          {
-            final int index = e.key.sxhash() & mask;
-            HashEntry dest = buckets[index];
-            if (dest != null)
-              {
-                while (dest.next != null)
-                  dest = dest.next;
-                dest.next = e;
-              }
-            else
-              buckets[index] = e;
-            HashEntry next = e.next;
-            e.next = null;
-            e = next;
-          }
-      }
+    super(new EqualComparator(), calculateInitialCapacity(size),
+            rehashSize, rehashThreshold);
   }
 }

Modified: trunk/abcl/src/org/armedbear/lisp/EqualpHashTable.java
==============================================================================
--- trunk/abcl/src/org/armedbear/lisp/EqualpHashTable.java	(original)
+++ trunk/abcl/src/org/armedbear/lisp/EqualpHashTable.java	Sat Oct  9 16:50:41 2010
@@ -38,104 +38,6 @@
   public EqualpHashTable(int size, LispObject rehashSize,
                          LispObject rehashThreshold)
   {
-    super(size, rehashSize, rehashThreshold);
-  }
-
-  @Override
-  public Symbol getTest()
-  {
-    return Symbol.EQUALP;
-  }
-
-  @Override
-  public synchronized LispObject get(LispObject key)
-  {
-    final int index = key.psxhash() % buckets.length;
-    HashEntry e = buckets[index];
-    while (e != null)
-      {
-        if (key.equalp(e.key))
-          return e.value;
-        e = e.next;
-      }
-    return null;
-  }
-
-  @Override
-  public synchronized void put(LispObject key, LispObject value)
-  {
-    int index = key.psxhash() % buckets.length;
-    HashEntry e = buckets[index];
-    while (e != null)
-      {
-        if (key.equalp(e.key))
-          {
-            e.value = value;
-            return;
-          }
-        e = e.next;
-      }
-    // Not found. We need to add a new entry.
-    if (++count > threshold)
-      {
-        rehash();
-        // Need a new hash value to suit the bigger table.
-        index = key.psxhash() % buckets.length;
-      }
-    e = new HashEntry(key, value);
-    e.next = buckets[index];
-    buckets[index] = e;
-  }
-
-  @Override
-  public LispObject remove(LispObject key)
-  {
-    final int index = key.psxhash() % buckets.length;
-    HashEntry e = buckets[index];
-    HashEntry last = null;
-    while (e != null)
-      {
-        if (key.equalp(e.key))
-          {
-            if (last == null)
-              buckets[index] = e.next;
-            else
-              last.next = e.next;
-            --count;
-            return e.value;
-          }
-        last = e;
-        e = e.next;
-      }
-    return null;
-  }
-
-  @Override
-  protected void rehash()
-  {
-    HashEntry[] oldBuckets = buckets;
-    int newCapacity = buckets.length * 2 + 1;
-    threshold = (int) (newCapacity * loadFactor);
-    buckets = new HashEntry[newCapacity];
-    for (int i = oldBuckets.length; i-- > 0;)
-      {
-        HashEntry e = oldBuckets[i];
-        while (e != null)
-          {
-            final int index = e.key.psxhash() % buckets.length;
-            HashEntry dest = buckets[index];
-            if (dest != null)
-              {
-                while (dest.next != null)
-                  dest = dest.next;
-                dest.next = e;
-              }
-            else
-              buckets[index] = e;
-            HashEntry next = e.next;
-            e.next = null;
-            e = next;
-          }
-      }
+    super(new EqualpComparator(), size, rehashSize, rehashThreshold);
   }
 }

Modified: trunk/abcl/src/org/armedbear/lisp/HashTable.java
==============================================================================
--- trunk/abcl/src/org/armedbear/lisp/HashTable.java	(original)
+++ trunk/abcl/src/org/armedbear/lisp/HashTable.java	Sat Oct  9 16:50:41 2010
@@ -30,276 +30,366 @@
  * obligated to do so.  If you do not wish to do so, delete this
  * exception statement from your version.
  */
-
 package org.armedbear.lisp;
 
 import static org.armedbear.lisp.Lisp.*;
 
-public abstract class HashTable extends LispObject
-{
-  private static final int DEFAULT_SIZE = 16;
+public abstract class HashTable extends LispObject {
 
-  protected static final float loadFactor = 0.75f;
+    private static final int DEFAULT_SIZE = 16;
+    protected static final float loadFactor = 0.75f;
+    protected final LispObject rehashSize;
+    protected final LispObject rehashThreshold;
+    // The rounded product of the capacity and the load factor. When the number
+    // of elements exceeds the threshold, the implementation calls rehash().
+    protected int threshold;
+    // Array containing the actual key-value mappings.
+    protected HashEntry[] buckets;
+    // The number of key-value pairs.
+    protected int count;
+    private int mask;
+    final Comparator comparator;
 
-  protected final LispObject rehashSize;
-  protected final LispObject rehashThreshold;
+  protected HashTable(int size, LispObject rehashSize,
+                      LispObject rehashThreshold)
+  {
+    protected HashTable(Comparator c, int size, LispObject rehashSize,
+            LispObject rehashThreshold) {
+        this.rehashSize = rehashSize;
+        this.rehashThreshold = rehashThreshold;
+        buckets = new HashEntry[size];
+        threshold = (int) (size * loadFactor);
+        comparator = c;
+        mask = buckets.length - 1;
+    }
 
-  // The rounded product of the capacity and the load factor. When the number
-  // of elements exceeds the threshold, the implementation calls rehash().
-  protected int threshold;
+    protected static int calculateInitialCapacity(int size) {
+        int capacity = 1;
+        while (capacity < size) {
+            capacity <<= 1;
+        }
+        return capacity;
+    }
 
-  // Array containing the actual key-value mappings.
-  protected HashEntry[] buckets;
+    public final LispObject getRehashSize() {
+        return rehashSize;
+    }
 
-  // The number of key-value pairs.
-  protected int count;
+    public final LispObject getRehashThreshold() {
+        return rehashThreshold;
+    }
 
-  protected HashTable(int size, LispObject rehashSize,
-                      LispObject rehashThreshold)
-  {
-    this.rehashSize = rehashSize;
-    this.rehashThreshold = rehashThreshold;
-    buckets = new HashEntry[size];
-    threshold = (int) (size * loadFactor);
-  }
+    public int getSize() {
+        return buckets.length;
+    }
 
-  protected static int calculateInitialCapacity(int size)
-  {
-    int capacity = 1;
-    while (capacity < size)
-      capacity <<= 1;
-    return capacity;
-  }
+    public int getCount() {
+        return count;
+    }
 
-  public final LispObject getRehashSize()
-  {
-    return rehashSize;
-  }
+    @Override
+    public LispObject typeOf() {
+        return Symbol.HASH_TABLE;
+    }
 
-  public final LispObject getRehashThreshold()
-  {
-    return rehashThreshold;
-  }
+    @Override
+    public LispObject classOf() {
+        return BuiltInClass.HASH_TABLE;
+    }
 
-  public int getSize()
-  {
-    return buckets.length;
-  }
+    @Override
+    public LispObject typep(LispObject type) {
+        if (type == Symbol.HASH_TABLE) {
+            return T;
+        }
+        if (type == BuiltInClass.HASH_TABLE) {
+            return T;
+        }
+        return super.typep(type);
+    }
 
-  public int getCount()
-  {
-    return count;
-  }
+    @Override
+    public boolean equalp(LispObject obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof HashTable) {
+            HashTable ht = (HashTable) obj;
+            if (count != ht.count) {
+                return false;
+            }
+            if (getTest() != ht.getTest()) {
+                return false;
+            }
+            LispObject entries = ENTRIES();
+            while (entries != NIL) {
+                LispObject entry = entries.car();
+                LispObject key = entry.car();
+                LispObject value = entry.cdr();
+                if (!value.equalp(ht.get(key))) {
+                    return false;
+                }
+                entries = entries.cdr();
+            }
+            return true;
+        }
+        return false;
+    }
 
-  public abstract Symbol getTest();
+    @Override
+    public LispObject getParts() {
+        LispObject parts = NIL;
+        for (int i = 0; i < buckets.length; i++) {
+            HashEntry e = buckets[i];
+            while (e != null) {
+                parts = parts.push(new Cons("KEY [bucket " + i + "]", e.key));
+                parts = parts.push(new Cons("VALUE", e.value));
+                e = e.next;
+            }
+        }
+        return parts.nreverse();
+    }
 
-  @Override
-  public LispObject typeOf()
-  {
-    return Symbol.HASH_TABLE;
-  }
+    public synchronized void clear() {
+        for (int i = buckets.length; i-- > 0;) {
+            buckets[i] = null;
+        }
+        count = 0;
+    }
 
-  @Override
-  public LispObject classOf()
-  {
-    return BuiltInClass.HASH_TABLE;
-  }
+    // gethash key hash-table &optional default => value, present-p
+    public synchronized LispObject gethash(LispObject key) {
+        LispObject value = get(key);
+        final LispObject presentp;
+        if (value == null) {
+            value = presentp = NIL;
+        } else {
+            presentp = T;
+        }
+        return LispThread.currentThread().setValues(value, presentp);
+    }
 
-  @Override
-  public LispObject typep(LispObject type)
-  {
-    if (type == Symbol.HASH_TABLE)
-      return T;
-    if (type == BuiltInClass.HASH_TABLE)
-      return T;
-    return super.typep(type);
-  }
+    // gethash key hash-table &optional default => value, present-p
+    public synchronized LispObject gethash(LispObject key,
+            LispObject defaultValue) {
+        LispObject value = get(key);
+        final LispObject presentp;
+        if (value == null) {
+            value = defaultValue;
+            presentp = NIL;
+        } else {
+            presentp = T;
+        }
+        return LispThread.currentThread().setValues(value, presentp);
+    }
 
-  @Override
-  public boolean equalp(LispObject obj)
-  {
-    if (this == obj)
-      return true;
-    if (obj instanceof HashTable)
-      {
-        HashTable ht = (HashTable) obj;
-        if (count != ht.count)
-          return false;
-        if (getTest() != ht.getTest())
-          return false;
-        LispObject entries = ENTRIES();
-        while (entries != NIL)
-          {
-            LispObject entry = entries.car();
-            LispObject key = entry.car();
-            LispObject value = entry.cdr();
-            if (!value.equalp(ht.get(key)))
-              return false;
-            entries = entries.cdr();
-          }
-        return true;
-      }
-    return false;
-  }
+    public synchronized LispObject gethash1(LispObject key) {
+        final LispObject value = get(key);
+        return value != null ? value : NIL;
+    }
 
-  @Override
-  public LispObject getParts()
-  {
-    LispObject parts = NIL;
-    for (int i = 0; i < buckets.length; i++)
-      {
-        HashEntry e = buckets[i];
-        while (e != null)
-          {
-            parts = parts.push(new Cons("KEY [bucket " + i + "]", e.key));
-            parts = parts.push(new Cons("VALUE", e.value));
-            e = e.next;
-          }
-      }
-    return parts.nreverse();
-  }
+    public synchronized LispObject puthash(LispObject key, LispObject newValue) {
+        put(key, newValue);
+        return newValue;
+    }
 
-  public synchronized void clear()
-  {
-    for (int i = buckets.length; i-- > 0;)
-      buckets[i] = null;
-    count = 0;
-  }
+    // remhash key hash-table => generalized-boolean
+    public synchronized LispObject remhash(LispObject key) {
+        // A value in a Lisp hash table can never be null, so...
+        return remove(key) != null ? T : NIL;
+    }
 
-  // gethash key hash-table &optional default => value, present-p
-  public synchronized LispObject gethash(LispObject key)
+    @Override
+    public String writeToString() {
+        if (Symbol.PRINT_READABLY.symbolValue(LispThread.currentThread()) != NIL) {
+            error(new PrintNotReadable(list(Keyword.OBJECT, this)));
+            return null; // Not reached.
+        }
+        StringBuilder sb = new StringBuilder(getTest().writeToString());
+        sb.append(' ');
+        sb.append(Symbol.HASH_TABLE.writeToString());
+        sb.append(' ');
+        sb.append(count);
+        if (count == 1) {
+            sb.append(" entry");
+        } else {
+            sb.append(" entries");
+        }
+        sb.append(", ");
+        sb.append(buckets.length);
+        sb.append(" buckets");
+        return unreadableString(sb.toString());
+    }
 
-  {
-    LispObject value = get(key);
-    final LispObject presentp;
-    if (value == null)
-      value = presentp = NIL;
-    else
-      presentp = T;
-    return LispThread.currentThread().setValues(value, presentp);
-  }
-
-  // gethash key hash-table &optional default => value, present-p
-  public synchronized LispObject gethash(LispObject key,
-                                         LispObject defaultValue)
+    public Symbol getTest() {
+        return comparator.getTest();
+    }
 
-  {
-    LispObject value = get(key);
-    final LispObject presentp;
-    if (value == null)
-      {
-        value = defaultValue;
-        presentp = NIL;
-      }
-    else
-      presentp = T;
-    return LispThread.currentThread().setValues(value, presentp);
-  }
+    synchronized public LispObject get(LispObject key) {
+        int index = comparator.hash(key) & mask;
+        HashEntry e = buckets[index];
+        while (e != null) {
+            if (comparator.keysEqual(key, e.key)) {
+                return e.value;
+            }
+            e = e.next;
+        }
+        return null;
+    }
+
+    synchronized public void put(LispObject key, LispObject value) {
+        int index = comparator.hash(key) & mask;
+        for (HashEntry e = buckets[index]; e != null; e = e.next) {
+            if (comparator.keysEqual(key, e.key)) {
+                e.value = value;
+                return;
+            }
+        }
+        // Not found. We need to add a new entry.
+        if (++count > threshold) {
+            rehash();
+            // Need a new hash value to suit the bigger table.
+            index = comparator.hash(key) & mask;
+        }
+        buckets[index] = new HashEntry(key, value, buckets[index]);
+    }
 
-  public synchronized LispObject gethash1(LispObject key)
+    synchronized public LispObject remove(LispObject key) {
+        int index = comparator.hash(key) & mask;
 
-  {
-    final LispObject value = get(key);
-    return value != null ? value : NIL;
-  }
+        HashEntry e = buckets[index];
+        HashEntry last = null;
+        while (e != null) {
+            if (comparator.keysEqual(key, e.key)) {
+                if (last == null) {
+                    buckets[index] = e.next;
+                } else {
+                    last.next = e.next;
+                }
+                --count;
+                return e.value;
+            }
+            last = e;
+            e = e.next;
+        }
+        return null;
+    }
 
-  public synchronized LispObject puthash(LispObject key, LispObject newValue)
+    synchronized protected void rehash() {
+        final int newCapacity = buckets.length * 2;
+        threshold = (int) (newCapacity * loadFactor);
+        mask = newCapacity - 1;
+        HashEntry[] newBuckets = new HashEntry[newCapacity];
+
+        for (int i = buckets.length; i-- > 0;) {
+            HashEntry e = buckets[i];
+            while (e != null) {
+                final int index = comparator.hash(e.key) & mask;
+                newBuckets[index] = new HashEntry(e.key,e.value, newBuckets[index]);
+                e = e.next;
+            }
+        }
+        buckets = newBuckets;
+    }
 
-  {
-    put(key, newValue);
-    return newValue;
-  }
+    // Returns a list of (key . value) pairs.
+    public LispObject ENTRIES() {
+        LispObject list = NIL;
+        for (int i = buckets.length; i-- > 0;) {
+            HashEntry e = buckets[i];
+            while (e != null) {
+                list = new Cons(new Cons(e.key, e.value), list);
+                e = e.next;
+            }
+        }
+        return list;
+    }
 
-  // remhash key hash-table => generalized-boolean
-  public synchronized LispObject remhash(LispObject key)
+    public LispObject MAPHASH(LispObject function) {
+        for (int i = buckets.length; i-- > 0;) {
+            HashEntry e = buckets[i];
+            while (e != null) {
+                function.execute(e.key, e.value);
+                e = e.next;
+            }
+        }
+        return NIL;
+    }
 
-  {
-    // A value in a Lisp hash table can never be null, so...
-    return remove(key) != null ? T : NIL;
-  }
+    protected static class Comparator {
+        Symbol getTest() {
+            return Symbol.EQ;
+        }
+
+        boolean keysEqual(LispObject key1, LispObject key2) {
+            return key1 == key2;
+        }
+
+        int hash(LispObject key) {
+            return key.sxhash();
+        }
+    }
 
-  @Override
-  public String writeToString()
-  {
-    if (Symbol.PRINT_READABLY.symbolValue(LispThread.currentThread()) != NIL)
-      {
-        error(new PrintNotReadable(list(Keyword.OBJECT, this)));
-        return null; // Not reached.
-      }
-    StringBuilder sb = new StringBuilder(getTest().writeToString());
-    sb.append(' ');
-    sb.append(Symbol.HASH_TABLE.writeToString());
-    sb.append(' ');
-    sb.append(count);
-    if (count == 1)
-      sb.append(" entry");
-    else
-      sb.append(" entries");
-    sb.append(", ");
-    sb.append(buckets.length);
-    sb.append(" buckets");
-    return unreadableString(sb.toString());
-  }
-
-  public abstract LispObject get(LispObject key);
-
-  public abstract void put(LispObject key, LispObject value)
-   ;
+    protected static class EqlComparator extends Comparator {
+        @Override
+        Symbol getTest() {
+            return Symbol.EQL;
+        }
+
+        @Override
+        boolean keysEqual(LispObject key1, LispObject key2) {
+            return key1.eql(key2);
+        }
+    }
 
-  public abstract LispObject remove(LispObject key);
+    protected static class EqualComparator extends Comparator {
+        @Override
+        Symbol getTest() {
+            return Symbol.EQUAL;
+        }
+
+        @Override
+        boolean keysEqual(LispObject key1, LispObject key2) {
+            return key1.equal(key2);
+        }
+    }
 
-  protected abstract void rehash();
+    protected static class EqualpComparator extends Comparator {
+        @Override
+        Symbol getTest() {
+            return Symbol.EQUALP;
+        }
+
+        @Override
+        boolean keysEqual(LispObject key1, LispObject key2) {
+            return key1.equalp(key2);
+        }
+
+        @Override
+        int hash(LispObject key) {
+            return key.psxhash();
+        }
+    }
 
-  // Returns a list of (key . value) pairs.
-  public LispObject ENTRIES()
-  {
-    LispObject list = NIL;
-    for (int i = buckets.length; i-- > 0;)
-      {
-        HashEntry e = buckets[i];
-        while (e != null)
-          {
-            list = new Cons(new Cons(e.key, e.value), list);
-            e = e.next;
-          }
-      }
-    return list;
-  }
+    protected static class HashEntry {
 
-  public LispObject MAPHASH(LispObject function)
-  {
-    for (int i = buckets.length; i-- > 0;)
-      {
-        HashEntry e = buckets[i];
-        while (e != null)
-          {
-            function.execute(e.key, e.value);
-            e = e.next;
-          }
-      }
-    return NIL;
-  }
+        LispObject key;
+        LispObject value;
+        HashEntry next;
+
+        HashEntry(LispObject key, LispObject value, HashEntry next) {
+            this.key = key;
+            this.value = value;
+            this.next = next;
+        }
+    }
 
-  protected static class HashEntry
-  {
-    LispObject key;
-    LispObject value;
-    HashEntry next;
-
-    HashEntry(LispObject key, LispObject value)
-    {
-      this.key = key;
-      this.value = value;
-    }
-  }
-
-  // For EQUALP hash tables.
-  @Override
-  public int psxhash()
-  {
-    long result = 2062775257; // Chosen at random.
-    result = mix(result, count);
-    result = mix(result, getTest().sxhash());
-    return (int) (result & 0x7fffffff);
-  }
+    // For EQUALP hash tables.
+    @Override
+    public int psxhash() {
+        long result = 2062775257; // Chosen at random.
+        result = mix(result, count);
+        result = mix(result, getTest().sxhash());
+        return (int) (result & 0x7fffffff);
+    }
 }




More information about the armedbear-cvs mailing list