com.yahoo.collections.LazyMap Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of vespajlib Show documentation
Show all versions of vespajlib Show documentation
Library for use in Java components of Vespa. Shared code which do
not fit anywhere else.
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.collections;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
/**
* @author Simon Thoresen Hult
*/
public abstract class LazyMap implements Map {
private Map delegate = newEmpty();
@Override
public final int size() {
return delegate.size();
}
@Override
public final boolean isEmpty() {
return delegate.isEmpty();
}
@Override
public final boolean containsKey(Object key) {
return delegate.containsKey(key);
}
@Override
public final boolean containsValue(Object value) {
return delegate.containsValue(value);
}
@Override
public final V get(Object key) {
return delegate.get(key);
}
@Override
public final V put(K key, V value) {
return delegate.put(key, value);
}
@Override
public final V remove(Object key) {
return delegate.remove(key);
}
@Override
public final void putAll(Map extends K, ? extends V> m) {
delegate.putAll(m);
}
@Override
public final void clear() {
delegate.clear();
}
@Override
public final Set keySet() {
return delegate.keySet();
}
@Override
public final Collection values() {
return delegate.values();
}
@Override
public final Set> entrySet() {
return delegate.entrySet();
}
@Override
public final int hashCode() {
return delegate.hashCode();
}
@Override
public final boolean equals(Object obj) {
return obj == this || (obj instanceof Map && delegate.equals(obj));
}
private Map newEmpty() {
return new EmptyMap();
}
private Map newSingleton(K key, V value) {
return new SingletonMap(key, value);
}
protected abstract Map newDelegate();
final Map getDelegate() {
return delegate;
}
class EmptyMap extends AbstractMap {
@Override
public V put(K key, V value) {
delegate = newSingleton(key, value);
return null;
}
@Override
public void putAll(Map extends K, ? extends V> m) {
switch (m.size()) {
case 0:
break;
case 1:
Entry extends K, ? extends V> entry = m.entrySet().iterator().next();
put(entry.getKey(), entry.getValue());
break;
default:
delegate = newDelegate();
delegate.putAll(m);
break;
}
}
@Override
public Set> entrySet() {
return Collections.emptySet();
}
}
class SingletonMap extends AbstractMap {
final K key;
V value;
SingletonMap(K key, V value) {
this.key = key;
this.value = value;
}
@Override
public V put(K key, V value) {
if (containsKey(key)) {
V oldValue = this.value;
this.value = value;
return oldValue;
} else {
delegate = newDelegate();
delegate.put(this.key, this.value);
return delegate.put(key, value);
}
}
@Override
public void putAll(Map extends K, ? extends V> m) {
switch (m.size()) {
case 0:
break;
case 1:
Entry extends K, ? extends V> entry = m.entrySet().iterator().next();
put(entry.getKey(), entry.getValue());
break;
default:
delegate = newDelegate();
delegate.put(this.key, this.value);
delegate.putAll(m);
break;
}
}
@Override
public Set> entrySet() {
return new AbstractSet>() {
@Override
public Iterator> iterator() {
return new Iterator>() {
boolean hasNext = true;
@Override
public boolean hasNext() {
return hasNext;
}
@Override
public Entry next() {
if (hasNext) {
hasNext = false;
return new Entry() {
@Override
public K getKey() {
return key;
}
@Override
public V getValue() {
return value;
}
@Override
public V setValue(V value) {
V oldValue = SingletonMap.this.value;
SingletonMap.this.value = value;
return oldValue;
}
@Override
public int hashCode() {
return Objects.hashCode(key) + Objects.hashCode(value) * 31;
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof Entry)) {
return false;
}
@SuppressWarnings("unchecked")
Entry rhs = (Entry)obj;
if (!Objects.equals(key, rhs.getKey())) {
return false;
}
if (!Objects.equals(value, rhs.getValue())) {
return false;
}
return true;
}
};
} else {
throw new NoSuchElementException();
}
}
@Override
public void remove() {
if (hasNext) {
throw new IllegalStateException();
} else {
delegate = newEmpty();
}
}
};
}
@Override
public int size() {
return 1;
}
};
}
}
public static LazyMap newHashMap() {
return new LazyMap() {
@Override
protected Map newDelegate() {
return new HashMap<>();
}
};
}
}