OrderedTable.avt

Переключить прокрутку окна
Загрузить этот исходный код

/*
    Реализация среды исполнения языка программирования
    Объектно-ориентированный продвинутый векторный транслятор

    Copyright © 2021, 2024, 2026 Малик Разработчик

    Это свободная программа: вы можете перераспространять ее и/или изменять
    ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
    в каком она была опубликована Фондом свободного программного обеспечения;
    либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.

    Эта программа распространяется в надежде, что она будет полезной,
    но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
    или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
    общественной лицензии GNU.

    Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
    вместе с этой программой. Если это не так, см.
    <https://www.gnu.org/licenses/>.
*/

package platform.independent.util;

import avt.lang.array.*;
import avt.lang.math.*;
import platform.independent.streamformat.*;

public class OrderedTable(Object, MutableDataHolder, DataHolder, Measureable, ObjectArray)
{
    private int fldLength;
    private Entry[] fldTable;
    private Object[] fldKeys;

    public () {
        fldTable = new Entry[0x3f];
        fldKeys = new Object[0x3f];
    }

    public void clear() {
        Object[] data = fldTable;
        Array.fill(data, 0, data.length, null);
        data = fldKeys;
        Array.fill(data, 0, fldLength, null);
        fldLength = 0;
    }

    public boolean isEmpty() { return fldLength <= 0; }

    public boolean contains(Object key) {
        if(key == null) return false;
        Entry[] table = fldTable;
        long2 hash = key.hashCodeAsLong2();
        int index = Entry.getIndex(hash, table.length);
        for(Entry curr = table[index]; curr != null; curr = curr.next) if(curr.hash == hash && curr.key.equals(key)) return true;
        return false;
    }

    public int length { read = fldLength }

    public Object operator [](int index) {
        if(index < 0 || index >= fldLength)
        {
            throw new ArrayIndexOutOfBoundsException(avt.lang.package.getResourceString("out-of-bounds.array-index"));
        }
        return fldKeys[index];
    }

    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" }));
        }
        Entry[] table = fldTable;
        long2 hash = key.hashCodeAsLong2();
        int index = Entry.getIndex(hash, table.length);
        for(Entry curr = table[index]; curr != null; curr = curr.next) if(curr.hash == hash && curr.key.equals(key)) return curr.value;
        return null;
    }

    private void rehash() {
        Entry[] oldTable = fldTable;
        int oldCapacity = oldTable.length;
        int newCapacity = oldCapacity << 1 | 1;
        if(newCapacity < 0)
        {
            throw new BufferTooLargeError(avt.lang.package.getResourceString("!error.buffer-too-large"));
        }
        Entry[] newTable = new Entry[newCapacity];
        for(int oldIndex = oldCapacity; oldIndex-- > 0; ) for(Entry oldEntry = oldTable[oldIndex]; oldEntry != null; )
        {
            int newIndex = Entry.getIndex(oldEntry.hash, newCapacity);
            Entry newEntry = oldEntry;
            oldEntry = oldEntry.next;
            newEntry.next = newTable[newIndex];
            newTable[newIndex] = newEntry;
        }
        Object[] newKeys = new Object[newCapacity];
        Array.copy(fldKeys, 0, newKeys, 0, oldCapacity);
        fldTable = newTable;
        fldKeys = newKeys;
    }

    private void remove(Object key) {
        Entry[] table = fldTable;
        long2 hash = key.hashCodeAsLong2();
        int index = Entry.getIndex(hash, table.length);
        for(Entry prev = null, Entry curr = table[index]; curr != null; curr = (prev = curr).next) if(curr.hash == hash && curr.key.equals(key))
        {
            if(prev != null)
            {
                prev.next = curr.next;
            } else
            {
                table[index] = curr.next;
            }
            index = curr.index;
            Object[] keys = fldKeys;
            int length = fldLength - 1;
            Array.copy(keys, index + 1, keys, index, length - index);
            keys[length] = null;
            fldLength = length;
            break;
        }
    }

    private void put(Object key, Object value) {
        Entry[] table = fldTable;
        int capacity = table.length;
        long2 hash = key.hashCodeAsLong2();
        int index = Entry.getIndex(hash, capacity);
        for(Entry curr = table[index]; curr != null; curr = curr.next) if(curr.hash == hash && curr.key.equals(key))
        {
            curr.value = value;
            return;
        }
        int length = fldLength;
        if(length >= capacity)
        {
            rehash();
            table = fldTable;
            index = Entry.getIndex(hash, table.length);
        }
        fldKeys[length] = key;
        table[index] = new Entry(length, hash, key, value, table[index]);
        fldLength = length + 1;
    }
}

final class Entry(Object)
{
    public static int getIndex(long2 hash, int length) { return (int) Int128.remUnsigned(hash, length); }

    private int fldIndex;
    private long2 fldHash;
    private Object fldKey;
    private Object fldValue;
    private Entry fldNext;

    public (int index, long2 hash, Object key, Object value, Entry next) {
        fldIndex = index;
        fldHash = hash;
        fldKey = key;
        fldValue = value;
        fldNext = next;
    }

    public int index { read = fldIndex }

    public long2 hash { read = fldHash }

    public Object key { read = fldKey }

    public Object value { read = fldValue, write = fldValue }

    public Entry next { read = fldNext, write = fldNext }
 }