All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.pamirs.pradar.IdentityHashSet Maven / Gradle / Ivy

There is a newer version: 1.0.2
Show newest version
package com.pamirs.pradar;

import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;

final class IdentityHashSet implements Iterable {
    public final static float DEFAULT_LOAD_FACTOR = 0.75f;

    public final static int MIN_CAPACITY = 4;

    public Object[] keys;

    public int assigned;

    public final float loadFactor;

    private int resizeThreshold;

    public IdentityHashSet() {
        this(16, DEFAULT_LOAD_FACTOR);
    }

    public IdentityHashSet(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }

    public IdentityHashSet(int initialCapacity, float loadFactor) {
        initialCapacity = Math.max(MIN_CAPACITY, initialCapacity);

        assert initialCapacity > 0 : "Initial capacity must be between (0, "
                + Integer.MAX_VALUE + "].";
        assert loadFactor > 0 && loadFactor < 1 : "Load factor must be between (0, 1).";
        this.loadFactor = loadFactor;
        allocateBuffers(roundCapacity(initialCapacity));
    }

    public boolean add(KType e) {
        assert e != null : "Null keys not allowed.";

        if (assigned >= resizeThreshold) expandAndRehash();

        final int mask = keys.length - 1;
        int slot = rehash(e) & mask;
        Object existing;
        while ((existing = keys[slot]) != null) {
            if (e == existing) {
                return false; // already found.
            }
            slot = (slot + 1) & mask;
        }
        assigned++;
        keys[slot] = e;
        return true;
    }

    public boolean contains(KType e) {
        final int mask = keys.length - 1;
        int slot = rehash(e) & mask;
        Object existing;
        while ((existing = keys[slot]) != null) {
            if (e == existing) {
                return true;
            }
            slot = (slot + 1) & mask;
        }
        return false;
    }

    private static int rehash(Object o) {
        return MurmurHash3.hash(System.identityHashCode(o));
    }

    private void expandAndRehash() {
        final Object[] oldKeys = this.keys;

        assert assigned >= resizeThreshold;
        allocateBuffers(nextCapacity(keys.length));

        final int mask = keys.length - 1;
        for (int i = 0; i < oldKeys.length; i++) {
            final Object key = oldKeys[i];
            if (key != null) {
                int slot = rehash(key) & mask;
                while (keys[slot] != null) {
                    slot = (slot + 1) & mask;
                }
                keys[slot] = key;
            }
        }
        Arrays.fill(oldKeys, null);
    }

    private void allocateBuffers(int capacity) {
        this.keys = new Object[capacity];
        this.resizeThreshold = (int) (capacity * DEFAULT_LOAD_FACTOR);
    }

    protected int nextCapacity(int current) {
        assert current > 0 && Long.bitCount(current) == 1 : "Capacity must be a power of two.";
        assert ((current << 1) > 0) : "Maximum capacity exceeded ("
                + (0x80000000 >>> 1) + ").";

        if (current < MIN_CAPACITY / 2) current = MIN_CAPACITY / 2;
        return current << 1;
    }

    protected int roundCapacity(int requestedCapacity) {
        if (requestedCapacity > (0x80000000 >>> 1)) return (0x80000000 >>> 1);

        int capacity = MIN_CAPACITY;
        while (capacity < requestedCapacity) {
            capacity <<= 1;
        }

        return capacity;
    }

    public void clear() {
        assigned = 0;
        Arrays.fill(keys, null);
    }

    public int size() {
        return assigned;
    }

    public boolean isEmpty() {
        return size() == 0;
    }

    @Override
    public Iterator iterator() {
        return new Iterator() {
            int pos = -1;
            Object nextElement = fetchNext();

            @Override
            public boolean hasNext() {
                return nextElement != null;
            }

            @SuppressWarnings("unchecked")
            @Override
            public KType next() {
                Object r = this.nextElement;
                if (r == null) {
                    throw new NoSuchElementException();
                }
                this.nextElement = fetchNext();
                return (KType) r;
            }

            private Object fetchNext() {
                pos++;
                while (pos < keys.length && keys[pos] == null) {
                    pos++;
                }

                return (pos >= keys.length ? null : keys[pos]);
            }

            @Override
            public void remove() {
                throw new UnsupportedOperationException();
            }
        };
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy