![JAR search and dependency download from the Maven repository](/logo.png)
aQute.bnd.unmodifiable.ImmutableMap Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of biz.aQute.bnd Show documentation
Show all versions of biz.aQute.bnd Show documentation
This command line utility is the Swiss army knife of OSGi. It provides you with a breadth of tools to understand and manage OSGi based systems. This project basically uses bndlib.
package aQute.bnd.unmodifiable;
import static java.util.Objects.requireNonNull;
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.AbstractCollection;
import java.util.AbstractMap;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.Spliterator;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
final class ImmutableMap extends AbstractMap implements Map, Serializable {
final static ImmutableMap, ?> EMPTY = new ImmutableMap<>();
final Object[] entries;
final transient short[] hash_bucket;
ImmutableMap(Object... entries) {
this.entries = entries;
this.hash_bucket = hash(entries);
}
private static short[] hash(Object[] entries) {
if ((entries.length & 1) != 0) {
throw new IllegalArgumentException("entries is not even length");
}
int length = entries.length >>> 1;
if (length == 0) {
return new short[1];
}
if (length >= (1 << Short.SIZE)) {
throw new IllegalArgumentException("map too large: " + length);
}
short[] hash_bucket = new short[length * 2];
for (int slot = 0, index = 0; slot < length; index += 2) {
Object key = entries[index];
int hash = -1 - linear_probe(entries, hash_bucket, key);
if (hash < 0) {
throw new IllegalArgumentException("duplicate key: " + key);
}
hash_bucket[hash] = (short) ++slot;
requireNonNull(entries[index + 1]);
}
return hash_bucket;
}
// https://en.wikipedia.org/wiki/Linear_probing
private static int linear_probe(Object[] entries, short[] hash_bucket, Object key) {
int length = hash_bucket.length;
for (int hash = (key.hashCode() & 0x7FFF_FFFF) % length;; hash = (hash + 1) % length) {
int index = (Short.toUnsignedInt(hash_bucket[hash]) - 1) << 1;
if (index < 0) { // empty
return -1 - hash;
}
if (entries[index].equals(key)) { // found
return index;
}
}
}
private int linear_probe(Object key) {
return linear_probe(entries, hash_bucket, key);
}
@Override
public int size() {
return entries.length >>> 1;
}
@Override
public boolean containsKey(Object key) {
if (key != null) {
return linear_probe(key) >= 0;
}
return false;
}
@Override
public boolean containsValue(Object value) {
if (value != null) {
Object[] entries = this.entries;
for (int index = 1, end = entries.length; index < end; index += 2) {
if (value.equals(entries[index])) {
return true;
}
}
}
return false;
}
@SuppressWarnings("unchecked")
@Override
public V get(Object key) {
if (key != null) {
int index = linear_probe(key);
if (index >= 0) {
return (V) entries[index + 1];
}
}
return null;
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof Map, ?> other)) {
return false;
}
if (size() != other.size()) {
return false;
}
try {
Object[] entries = this.entries;
for (int index = 0, end = entries.length; index < end; index += 2) {
if (!entries[index + 1].equals(other.get(entries[index]))) {
return false;
}
}
} catch (ClassCastException checked) {
return false;
}
return true;
}
@Override
public int hashCode() {
Object[] entries = this.entries;
int hashCode = 0;
for (int index = 0, end = entries.length; index < end; index += 2) {
hashCode += entries[index].hashCode() ^ entries[index + 1].hashCode();
}
return hashCode;
}
@SuppressWarnings("unchecked")
@Override
public void forEach(BiConsumer super K, ? super V> action) {
requireNonNull(action);
Object[] entries = this.entries;
for (int index = 0, end = entries.length; index < end; index += 2) {
action.accept((K) entries[index], (V) entries[index + 1]);
}
}
@Override
public Set> entrySet() {
return new EntrySet<>(this);
}
@Override
public Set keySet() {
return new KeySet<>(this);
}
@Override
public Collection values() {
return new ValueCollection<>(this);
}
abstract static class ElementCollection extends AbstractCollection implements Collection {
final ImmutableMap, ?> map;
ElementCollection(ImmutableMap, ?> map) {
this.map = map;
}
abstract E element(int index);
@Override
abstract public boolean contains(Object o);
final class ElementIterator implements Iterator {
private int index;
private final int end;
ElementIterator(int index, int end) {
this.index = index;
this.end = end;
}
@Override
public boolean hasNext() {
return index < end;
}
@Override
public E next() {
if (hasNext()) {
E element = element(index);
index += 2;
return element;
}
throw new NoSuchElementException();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public void forEachRemaining(Consumer super E> action) {
requireNonNull(action);
while (index < end) {
E element = element(index);
index += 2;
action.accept(element);
}
}
}
@Override
public Iterator iterator() {
return new ElementIterator(0, map.entries.length);
}
final class ElementSpliterator implements Spliterator {
private int index;
private final int end;
ElementSpliterator(int index, int end) {
this.index = index;
this.end = end;
}
@Override
public boolean tryAdvance(Consumer super E> action) {
requireNonNull(action);
if (index < end) {
E element = element(index);
index += 2;
action.accept(element);
return true;
}
return false;
}
@Override
public void forEachRemaining(Consumer super E> action) {
requireNonNull(action);
while (index < end) {
E element = element(index);
index += 2;
action.accept(element);
}
}
@Override
public Spliterator trySplit() {
int split = ((index + end) >>> 2) << 1;
if (index < split) {
ElementSpliterator spliterator = new ElementSpliterator(index, split);
index = split;
return spliterator;
}
return null; // no split
}
@Override
public long estimateSize() {
return getExactSizeIfKnown();
}
@Override
public int characteristics() {
int characteristics = Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL
| Spliterator.SIZED | Spliterator.SUBSIZED;
if (ElementCollection.this instanceof Set) {
characteristics |= Spliterator.DISTINCT;
}
return characteristics;
}
@Override
public long getExactSizeIfKnown() {
return (end - index) >>> 1;
}
}
@Override
public Spliterator spliterator() {
return new ElementSpliterator(0, map.entries.length);
}
@Override
public void forEach(Consumer super E> action) {
requireNonNull(action);
for (int index = 0, end = map.entries.length; index < end; index += 2) {
action.accept(element(index));
}
}
@Override
public int size() {
return map.size();
}
}
abstract static class ElementSet extends ElementCollection implements Set {
ElementSet(ImmutableMap, ?> map) {
super(map);
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof Set> other)) {
return false;
}
if (size() != other.size()) {
return false;
}
try {
return containsAll(other);
} catch (ClassCastException checked) {
return false;
}
}
@Override
abstract public int hashCode();
}
final static class EntrySet extends ElementSet> {
EntrySet(ImmutableMap map) {
super(map);
}
@Override
@SuppressWarnings("unchecked")
Entry element(int index) {
Object[] entries = map.entries;
return new ImmutableEntry<>((K) entries[index], (V) entries[index + 1]);
}
@Override
public boolean contains(Object o) {
if (!(o instanceof Entry, ?> other)) {
return false;
}
Object v = map.get(other.getKey());
if (v == null) {
return false;
}
return v.equals(other.getValue());
}
@Override
public int hashCode() {
return map.hashCode();
}
}
final static class KeySet extends ElementSet {
KeySet(ImmutableMap map) {
super(map);
}
@Override
@SuppressWarnings("unchecked")
K element(int index) {
return (K) map.entries[index];
}
@Override
public boolean contains(Object o) {
return map.containsKey(o);
}
@Override
public int hashCode() {
Object[] entries = map.entries;
int hashCode = 0;
for (int index = 0, end = entries.length; index < end; index += 2) {
hashCode += entries[index].hashCode();
}
return hashCode;
}
}
final static class ValueCollection extends ElementCollection {
ValueCollection(ImmutableMap, V> map) {
super(map);
}
@Override
@SuppressWarnings("unchecked")
V element(int index) {
return (V) map.entries[index + 1];
}
@Override
public boolean contains(Object o) {
return map.containsValue(o);
}
}
@Override
public V put(K key, V value) {
throw new UnsupportedOperationException();
}
@Override
public V remove(Object key) {
throw new UnsupportedOperationException();
}
@Override
public void putAll(Map extends K, ? extends V> map) {
throw new UnsupportedOperationException();
}
@Override
public void clear() {
throw new UnsupportedOperationException();
}
@Override
public void replaceAll(BiFunction super K, ? super V, ? extends V> function) {
throw new UnsupportedOperationException();
}
@Override
public V putIfAbsent(K key, V value) {
throw new UnsupportedOperationException();
}
@Override
public boolean remove(Object key, Object value) {
throw new UnsupportedOperationException();
}
@Override
public boolean replace(K key, V oldValue, V newValue) {
throw new UnsupportedOperationException();
}
@Override
public V replace(K key, V value) {
throw new UnsupportedOperationException();
}
@Override
public V computeIfAbsent(K key, Function super K, ? extends V> mappingFunction) {
throw new UnsupportedOperationException();
}
@Override
public V computeIfPresent(K key, BiFunction super K, ? super V, ? extends V> remappingFunction) {
throw new UnsupportedOperationException();
}
@Override
public V compute(K key, BiFunction super K, ? super V, ? extends V> remappingFunction) {
throw new UnsupportedOperationException();
}
@Override
public V merge(K key, V value, BiFunction super V, ? super V, ? extends V> remappingFunction) {
throw new UnsupportedOperationException();
}
// Serialization support
private static final long serialVersionUID = 1L;
private void readObject(ObjectInputStream ois) throws InvalidObjectException {
throw new InvalidObjectException("proxy required");
}
private Object writeReplace() {
return new SerializationProxy(this);
}
private static final class SerializationProxy implements Serializable {
private static final long serialVersionUID = 1L;
private transient Object[] data;
SerializationProxy(ImmutableMap, ?> map) {
data = map.entries;
}
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject();
final Object[] local = data;
final int length = local.length;
oos.writeInt(length);
for (int i = 0; i < length; i++) {
oos.writeObject(local[i]);
}
}
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
ois.defaultReadObject();
final int length = ois.readInt();
if (length < 0) {
throw new InvalidObjectException("negative length");
}
if ((length & 1) != 0) {
throw new InvalidObjectException("odd length");
}
final Object[] local = new Object[length];
for (int i = 0; i < length; i++) {
local[i] = ois.readObject();
}
data = local;
}
private Object readResolve() throws InvalidObjectException {
try {
final Object[] local = data;
if (local.length == 0) {
return EMPTY;
}
return new ImmutableMap<>(local);
} catch (RuntimeException e) {
InvalidObjectException ioe = new InvalidObjectException("invalid");
ioe.initCause(e);
throw ioe;
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy