/*
Реализация спецификаций CLDC версии 1.1 (JSR-139), MIDP версии 2.1 (JSR-118)
и других спецификаций для функционирования компактных приложений на языке
Java (мидлетов) в среде программного обеспечения Малик Эмулятор.
Copyright © 2016–2017, 2019–2023 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package java.util;
import malik.emulator.fileformats.*;
import malik.emulator.util.*;
public class Hashtable extends Object implements DataHolder
{
private static final class Entry extends Object
{
public final int hash;
public final Object key;
public Object value;
public Entry next;
public Entry(int hash, Object key, Object value, Entry next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
}
private static class Enumerator extends Object implements Enumeration
{
private final boolean keys;
private int index;
private final Entry[] table;
private Entry next;
protected Entry current;
public Enumerator(boolean keys, Entry[] table) {
this.keys = keys;
this.index = table.length;
this.table = table;
}
public boolean hasMoreElements() {
int i;
Entry[] t;
if(next != null) return true;
for(t = table, i = index; i-- > 0; ) if((next = t[i]) != null)
{
index = i;
return true;
}
index = -1;
return false;
}
public Object nextElement() {
Entry e;
if((e = next) == null)
{
int i = index;
Entry[] t = table;
while(i-- > 0 && (e = t[i]) == null);
next = e;
index = i < 0 ? -1 : i;
}
if(e == null)
{
current = null;
throw new NoSuchElementException("Enumeration.nextElement: элементов больше не осталось.");
}
next = (current = e).next;
return keys ? e.key : e.value;
}
}
private static class KeyEnumerator extends Enumerator implements MapEnumeration
{
public KeyEnumerator(Entry[] table) {
super(true, table);
}
public Object value() {
Entry e;
if((e = current) == null)
{
throw new NoSuchElementException("Hashtable.keys: элементов больше не осталось.");
}
return e.value;
}
}
private int factor;
private int length;
private Entry[] table;
private final Object monitor;
public Hashtable() {
this(15);
}
public Hashtable(int initialCapacity) {
if(initialCapacity < 0)
{
throw new IllegalArgumentException("Hashtable: аргумент initialCapacity не может быть отрицательным.");
}
if(initialCapacity == 0) initialCapacity = 1;
this.factor = initialCapacity - (initialCapacity >> 2);
this.table = new Entry[initialCapacity];
this.monitor = new Object();
}
public String toString() {
StringBuilder result = (new StringBuilder()).append('{');
synchronized(monitor)
{
KeyEnumerator e = new KeyEnumerator(table);
for(int i = length; i-- > 0; )
{
result.append(e.nextElement().toString()).append('=').append(e.value().toString());
if(i > 0) result.append(",\u0020");
}
}
return result.append('}').toString();
}
public void clear() {
synchronized(monitor)
{
Object[] t;
Array.fill(t = table, 0, t.length, null);
length = 0;
}
}
public boolean isEmpty() {
return length <= 0;
}
public boolean contains(Object value) {
boolean result;
if(value == null)
{
throw new NullPointerException("Hashtable.contains: аргумент value равен нулевой ссылке.");
}
synchronized(monitor)
{
Entry[] t;
result = false;
label0: for(int i = (t = table).length; i-- > 0; ) for(Entry e = t[i]; e != null; e = e.next) if(value.equals(e.value))
{
result = true;
break label0;
}
}
return result;
}
public boolean containsKey(Object key) {
boolean result;
if(key == null) return false;
synchronized(monitor)
{
int h;
Entry[] t;
result = false;
for(Entry e = (t = table)[((h = key.hashCode()) & Integer.MAX_VALUE) % t.length]; e != null; e = e.next) if(h == e.hash && key.equals(e.key))
{
result = true;
break;
}
}
return result;
}
public int size() {
return length;
}
public Object put(Object key, Object value) {
Object result;
if(key == null)
{
throw new NullPointerException("Hashtable.put: аргумент key равен нулевой ссылке.");
}
if(value == null)
{
throw new NullPointerException("Hashtable.put: аргумент value равен нулевой ссылке.");
}
synchronized(monitor)
{
label0:
{
int i;
int h;
int len;
Entry[] t;
for(Entry e = (t = table)[i = ((h = key.hashCode()) & Integer.MAX_VALUE) % t.length]; e != null; e = e.next) if(h == e.hash && key.equals(e.key))
{
result = e.value;
e.value = value;
break label0;
}
if((len = length) >= factor)
{
rehash();
i = (h & Integer.MAX_VALUE) % (t = table).length;
}
t[i] = new Entry(h, key, value, t[i]);
length = len + 1;
result = null;
}
}
return result;
}
public Object remove(Object key) {
Object result;
if(key == null) return null;
synchronized(monitor)
{
int i;
int h;
Entry[] t;
result = null;
for(Entry f = null, e = (t = table)[i = ((h = key.hashCode()) & Integer.MAX_VALUE) % t.length]; e != null; f = e, e = e.next)
{
if(h != e.hash || !key.equals(e.key)) continue;
if(f != null)
{
f.next = e.next;
} else
{
t[i] = e.next;
}
length--;
result = e.value;
break;
}
}
return result;
}
public Object get(Object key) {
Object result;
if(key == null) return null;
synchronized(monitor)
{
int h;
Entry[] t;
result = null;
for(Entry e = (t = table)[((h = key.hashCode()) & Integer.MAX_VALUE) % t.length]; e != null; e = e.next) if(h == e.hash && key.equals(e.key))
{
result = e.value;
break;
}
}
return result;
}
public Enumeration elements() {
return new Enumerator(false, table);
}
public Enumeration keys() {
return new KeyEnumerator(table);
}
protected void rehash() {
int nc;
int oc;
Entry[] nt;
Entry[] ot;
table = nt = new Entry[nc = ((oc = (ot = table).length) << 1) + 1];
factor = nc - (nc >> 2);
for(int i = oc; i-- > 0; ) for(Entry f = ot[i]; f != null; )
{
int j;
Entry e;
j = ((e = f).hash & Integer.MAX_VALUE) % nc;
f = f.next;
e.next = nt[j];
nt[j] = e;
}
}
}