com.yahoo.collections.LazyMap Maven / Gradle / Ivy
// 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 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 m) {
switch (m.size()) {
case 0:
break;
case 1:
Entry 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 m) {
switch (m.size()) {
case 0:
break;
case 1:
Entry 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<>();
}
};
}
}