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