org.infinispan.commons.util.ArrayMap Maven / Gradle / Ivy
package org.infinispan.commons.util;
import java.util.AbstractCollection;
import java.util.AbstractSet;
import java.util.Arrays;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
import java.util.function.IntFunction;
/**
* Base for classes that implement hash map by storing keys in one array and values in another.
* It assumes that all keys that are in the array are contained in the map and that values
* are on corresponding indices in the map.
*
* Does not support null keys nor values.
*
* Forces implementation of methods {@link #get(Object)}, {@link #put(Object, Object)}, {@link #remove(Object)}
*/
public abstract class ArrayMap extends java.util.AbstractMap {
protected int size;
protected Object[] keys;
protected Object[] values;
protected int modCount;
private Set keySet;
private Collection valueCollection;
private Set> entrySet;
@Override
public abstract V get(Object key);
@Override
public abstract V put(K key, V value);
@Override
public abstract V remove(Object key);
@Override
public int size() {
return size;
}
@Override
public boolean containsValue(Object value) {
Objects.requireNonNull(value);
for (Object v : values) {
if (v != null && v.equals(value)) return true;
}
return false;
}
@Override
public Set keySet() {
if (keySet == null) {
keySet = new KeySet();
}
return keySet;
}
@Override
public Collection values() {
if (valueCollection == null) {
valueCollection = new Values();
}
return valueCollection;
}
@Override
public Set> entrySet() {
if (entrySet == null) {
entrySet = new EntrySet();
}
return entrySet;
}
@Override
public boolean containsKey(Object key) {
return get(key) != null;
}
@Override
public void clear() {
size = 0;
++modCount;
Arrays.fill(keys, null);
Arrays.fill(values, null);
}
private class KeySet extends AbstractSet {
@Override
public Iterator iterator() {
return new It<>(i -> (K) keys[i], keys.length, modCount);
}
@Override
public int size() {
return ArrayMap.this.size();
}
@Override
public void clear() {
ArrayMap.this.clear();
}
@Override
public boolean contains(Object o) {
return containsKey(o);
}
@Override
public boolean remove(Object o) {
return ArrayMap.this.remove(o) != null;
}
}
private class Values extends AbstractCollection {
@Override
public Iterator iterator() {
return new It<>(i -> (V) values[i], values.length, modCount);
}
@Override
public int size() {
return ArrayMap.this.size();
}
@Override
public void clear() {
ArrayMap.this.clear();
}
}
private class EntrySet extends AbstractSet> {
@Override
public Iterator> iterator() {
return new It<>(i -> {
Object key = keys[i];
return key == null ? null : new SimpleEntry((K) key, (V) values[i]);
}, keys.length, modCount);
}
@Override
public int size() {
return ArrayMap.this.size();
}
@Override
public void clear() {
ArrayMap.this.clear();
}
}
private class It implements Iterator {
private final IntFunction retriever;
private final int length;
private final int initialModCount;
private int last = -1, pos = 0;
private T next;
public It(IntFunction retriever, int length, int initialModCount) {
this.retriever = retriever;
this.length = length;
this.initialModCount = initialModCount;
}
@Override
public boolean hasNext() {
if (initialModCount != modCount) {
throw new ConcurrentModificationException();
}
if (next != null) {
return true;
}
while (pos < length) {
next = retriever.apply(pos);
++pos;
if (next != null) {
last = pos -1;
return true;
}
}
return false;
}
@Override
public T next() {
if (hasNext()) {
T tmp = next;
next = null;
return tmp;
} else {
throw new NoSuchElementException();
}
}
@Override
public void remove() {
if (initialModCount != modCount) {
throw new ConcurrentModificationException();
}
keys[last] = null;
values[last] = null;
}
}
}