deep-c-rsc/JCGO/jtrsrc/com/ivmaisoft/jcgo/ObjHashtable.java
2021-07-16 17:12:20 -05:00

338 lines
9.6 KiB
Java

/*
* @(#) $(JCGO)/jtrsrc/com/ivmaisoft/jcgo/ObjHashtable.java --
* a part of JCGO translator.
**
* Project: JCGO (http://www.ivmaisoft.com/jcgo/)
* Copyright (C) 2001-2012 Ivan Maidanski <ivmai@mail.ru>
* All rights reserved.
*/
/*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
**
* This software is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License (GPL) for more details.
**
* Linking this library statically or dynamically with other modules is
* making a combined work based on this library. Thus, the terms and
* conditions of the GNU General Public License cover the whole
* combination.
**
* As a special exception, the copyright holders of this library give you
* permission to link this library with independent modules to produce an
* executable, regardless of the license terms of these independent
* modules, and to copy and distribute the resulting executable under
* terms of your choice, provided that you also meet, for each linked
* independent module, the terms and conditions of the license of that
* module. An independent module is a module which is not derived from
* or based on this library. If you modify this library, you may extend
* this exception to your version of the library, but you are not
* obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
package com.ivmaisoft.jcgo;
import java.util.Enumeration;
import java.util.NoSuchElementException;
/**
* An unordered map (hash table of objects).
*/
final class ObjHashtable {
private ObjHashtableRoots roots = new ObjHashtableRoots();
ObjHashtable() {
}
int size() {
return roots.size();
}
Object get(Object key) {
ObjHashtableEntry entry = roots.getEntry(key, hashOfKey(key));
return entry != null ? entry.value : null;
}
private static int hashOfKey(Object key) {
Term.assertCond(key != null);
int hash = key.hashCode();
hash += ~(hash << 9);
hash ^= hash >>> 14;
hash += hash << 4;
return (hash >>> 10) ^ hash;
}
Object remove(Object key) {
return roots.removeEntry(key, hashOfKey(key), null);
}
Object put(Object key, Object value) {
int hash = hashOfKey(key);
ObjHashtableRoots roots = this.roots;
int index = roots.hashToIndexAtRoot(hash);
ObjHashtableEntry entry = roots.getEntryAtRoot(key, hash, index);
if (entry != null) {
Object obj = entry.value;
entry.value = value;
return obj;
}
ObjHashtableRoots last = roots;
if (roots.needsGrow()) {
this.roots = roots = new ObjHashtableRoots(roots);
index = roots.hashToIndexAtRoot(hash);
}
roots.addEntryAtRoot(key, value, index);
ObjHashtableRoots prev = last.prev();
return prev != null ? prev.removeEntry(key, hash, last) : null;
}
void clear() {
roots.clear();
}
Enumeration keys() {
return new ObjHashtableEnumerator(roots, true);
}
Enumeration elements() {
return new ObjHashtableEnumerator(roots, false);
}
}
final class ObjHashtableRoots {
private static final int[] PRIMES = {
0xd, 0x1f, 0x3d, 0x7f, 0xfb, 0x1fd, 0x3fd, 0x7f7, 0xffd, 0x1fff,
0x3ffd, 0x7fed };
private/* final */ObjHashtableEntry[] entries;
private ObjHashtableRoots prev;
private int elementCount;
ObjHashtableRoots() {
entries = new ObjHashtableEntry[PRIMES[0]];
}
ObjHashtableRoots(ObjHashtableRoots roots) {
entries = new ObjHashtableEntry[nextCapacity(roots.entries.length)];
prev = roots;
}
private static int nextCapacity(int capacity) {
int last = PRIMES.length - 1;
if (PRIMES[last] > capacity) {
for (int i = 0; i < last; i++) {
if (PRIMES[i] >= capacity)
return PRIMES[i + 1];
}
}
return (capacity << 1) + 1;
}
ObjHashtableRoots prev() {
return prev;
}
int size() {
int size = elementCount;
ObjHashtableRoots roots = this;
while ((roots = roots.prev) != null) {
size += roots.elementCount;
}
return size;
}
ObjHashtableEntry getEntry(Object key, int hash) {
ObjHashtableEntry entry;
ObjHashtableRoots roots = this;
while ((entry = hashToEntry(hash, roots.entries)) == null
|| (entry = entry.findEntry(key)) == null) {
if ((roots = roots.prev) == null)
break;
}
return entry;
}
private static ObjHashtableEntry hashToEntry(int hash,
ObjHashtableEntry[] entries) {
return entries[hashToIndex(hash, entries)];
}
private static int hashToIndex(int hash, ObjHashtableEntry[] entries) {
return (hash & (-1 >>> 1)) % entries.length;
}
int hashToIndexAtRoot(int hash) {
return hashToIndex(hash, entries);
}
boolean needsGrow() {
int len = entries.length;
return len - len / 5 < elementCount;
}
ObjHashtableEntry getEntryAtRoot(Object key, int hash, int index) {
ObjHashtableEntry entry = entries[index];
return entry != null ? entry.findEntry(key) : null;
}
void addEntryAtRoot(Object key, Object value, int index) {
ObjHashtableEntry[] entries = this.entries;
entries[index] = new ObjHashtableEntry(key, value, entries[index]);
elementCount++;
}
Object removeEntry(Object key, int hash, ObjHashtableRoots last) {
ObjHashtableRoots roots = this;
do {
ObjHashtableEntry[] rootEntries = roots.entries;
int index = hashToIndex(hash, rootEntries);
ObjHashtableEntry rootEntry = rootEntries[index];
ObjHashtableEntry entry;
if (rootEntry != null
&& (entry = rootEntry.findAndRemoveEntry(key)) != null) {
if (entry == rootEntry) {
rootEntries[index] = rootEntry.next();
}
if (--roots.elementCount == 0 && last != null) {
last.prev = roots.prev;
}
return entry.value;
}
} while ((roots = (last = roots).prev) != null);
return null;
}
void clear() {
prev = null;
if (elementCount != 0) {
ObjHashtableEntry[] entries = this.entries;
int len = entries.length;
while (len-- > 0) {
entries[len] = null;
}
elementCount = 0;
}
}
ObjHashtableEntry[] getEntries() {
return elementCount != 0 ? entries : null;
}
}
final class ObjHashtableEntry {
private/* final */Object key;
private ObjHashtableEntry next;
Object value;
ObjHashtableEntry(Object key, Object value, ObjHashtableEntry next) {
this.key = key;
this.value = value;
this.next = next;
}
ObjHashtableEntry next() {
return next;
}
ObjHashtableEntry findEntry(Object key) {
ObjHashtableEntry entry = this;
while (!entry.key.equals(key)) {
if ((entry = entry.next) == null)
break;
}
return entry;
}
ObjHashtableEntry findAndRemoveEntry(Object key) {
ObjHashtableEntry entry = this;
ObjHashtableEntry last = null;
while (!entry.key.equals(key)) {
if ((entry = (last = entry).next) == null)
break;
}
if (last != null && entry != null) {
last.next = entry.next;
}
return entry;
}
Object key() {
return key;
}
}
final class ObjHashtableEnumerator implements Enumeration {
private ObjHashtableRoots roots;
private/* final */boolean keys;
private ObjHashtableEntry entry;
private int index;
private boolean filled;
ObjHashtableEnumerator(ObjHashtableRoots roots, boolean keys) {
this.roots = roots;
this.keys = keys;
}
private void nextFill() {
ObjHashtableEntry entry;
if ((entry = this.entry) == null || (entry = entry.next()) == null)
do {
ObjHashtableEntry[] entries = roots.getEntries();
if (entries != null) {
int index = this.index;
int len = entries.length;
while (index < len) {
if ((entry = entries[index++]) != null)
break;
}
this.index = index;
if (entry != null)
break;
}
ObjHashtableRoots prev = roots.prev();
if (prev == null)
break;
roots = prev;
this.index = 0;
} while (true);
this.entry = entry;
filled = true;
}
public boolean hasMoreElements() {
if (!filled) {
nextFill();
}
return entry != null;
}
public Object nextElement() {
if (!filled) {
nextFill();
}
if (entry == null)
throw new NoSuchElementException();
filled = false;
return keys ? entry.key() : entry.value;
}
}