/*
Реализация среды исполнения языка программирования
Объектно-ориентированный продвинутый векторный транслятор
Copyright © 2021, 2024, 2026 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package avt.lang.util;
public class KeyValueTable(Object)
{
private long fldLength;
private KeyValueEntry[] fldTable;
public () { fldTable = new KeyValueEntry[0x0f]; }
public boolean contains(Object key) {
if(key == null) return false;
for(long2 hash = key.hashCodeAsLong2(), KeyValueEntry[] table = fldTable, KeyValueEntry entry = table[Entry.getIndex(hash, table.length)]; entry != null; entry = entry.next)
{
if(hash == entry.hash && key.equals(entry.key)) return true;
}
return false;
}
public void operator []=(Object key, Object value) {
if(key == null)
{
throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "key" }));
}
if(value == null)
{
remove(key);
return;
}
put(key, value);
}
public Object operator [](Object key) {
if(key == null)
{
throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "key" }));
}
for(long2 hash = key.hashCodeAsLong2(), KeyValueEntry[] table = fldTable, KeyValueEntry entry = table[Entry.getIndex(hash, table.length)]; entry != null; entry = entry.next)
{
if(hash == entry.hash && key.equals(entry.key)) return entry.value;
}
return null;
}
private void rehash() {
KeyValueEntry[] oldTable = fldTable;
int oldCapacity = oldTable.length;
int newCapacity = oldCapacity << 1 | 1;
KeyValueEntry[] newTable = fldTable = new KeyValueEntry[newCapacity];
for(int oldIndex = oldCapacity; oldIndex-- > 0; ) for(KeyValueEntry oldEntry = oldTable[oldIndex]; oldEntry != null; )
{
int newIndex = Entry.getIndex(oldEntry.hash, newCapacity);
KeyValueEntry newEntry = oldEntry;
oldEntry = oldEntry.next;
newEntry.next = newTable[newIndex];
newTable[newIndex] = newEntry;
}
}
private void remove(Object key) {
long2 hash = key.hashCodeAsLong2();
for(KeyValueEntry[] table = fldTable, int index = Entry.getIndex(hash, table.length), KeyValueEntry prev = null, KeyValueEntry entry = table[index]; entry != null; entry = (prev = entry).next)
{
if(hash == entry.hash && key.equals(entry.key))
{
if(prev != null)
{
prev.next = entry.next;
} else
{
table[index] = entry.next;
}
fldLength--;
break;
}
}
}
private void put(Object key, Object value) {
KeyValueEntry[] table = fldTable;
long2 hash = key.hashCodeAsLong2();
long length = fldLength + 1;
int capacity = table.length;
int index = Entry.getIndex(hash, capacity);
if(length > capacity && length <= Int.MAX_VALUE)
{
rehash();
index = Entry.getIndex(hash, (table = fldTable).length);
}
table[index] = new KeyValueEntry(hash, key, value, table[index]);
fldLength = length;
}
}
class KeyValueEntry(Entry)
{
private KeyValueEntry fldNext;
private final Object fldKey;
public (long2 hash, Object key, Object value, KeyValueEntry next): super(hash, value) {
fldNext = next;
fldKey = key;
}
public Object key { read = fldKey }
public KeyValueEntry next { read = fldNext, write = fldNext }
}