package org.inferred.freebuilder.processor.excerpt;
import static org.inferred.freebuilder.processor.util.StaticExcerpt.Type.TYPE;
import static org.inferred.freebuilder.processor.util.feature.FunctionPackage.FUNCTION_PACKAGE;
import com.google.common.collect.ImmutableSet;
import org.inferred.freebuilder.processor.util.ParameterizedType;
import org.inferred.freebuilder.processor.util.PreconditionExcerpts;
import org.inferred.freebuilder.processor.util.SourceBuilder;
import org.inferred.freebuilder.processor.util.StaticExcerpt;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* Excerpts defining a map implementation that delegates to a provided put method to perform entry
* validation and insertion into a backing map.
*/
public class CheckedMap {
public static final Set<StaticExcerpt> excerpts() {
return ImmutableSet.of(CHECKED_ENTRY, CHECKED_ENTRY_ITERATOR, CHECKED_ENTRY_SET, CHECKED_MAP);
}
private static final StaticExcerpt CHECKED_ENTRY = new StaticExcerpt(TYPE, "CheckedEntry") {
@Override
public void addTo(SourceBuilder code) {
ParameterizedType biConsumer = code.feature(FUNCTION_PACKAGE).biConsumer().orNull();
if (biConsumer == null) {
return;
}
code.addLine("")
.addLine("private static class CheckedEntry<K, V> implements %s<K, V> {",
Map.Entry.class)
.addLine("")
.addLine(" private final %s<K, V> entry;", Map.Entry.class)
.addLine(" private final %s<K, V> put;", biConsumer.getQualifiedName())
.addLine("")
.addLine(" CheckedEntry(%s<K, V> entry, %s<K, V> put) {",
Map.Entry.class, biConsumer.getQualifiedName())
.addLine(" this.entry = entry;")
.addLine(" this.put = put;")
.addLine(" }")
.addLine("")
.addLine(" @Override public K getKey() {")
.addLine(" return entry.getKey();")
.addLine(" }")
.addLine("")
.addLine(" @Override public V getValue() {")
.addLine(" return entry.getValue();")
.addLine(" }")
.addLine("")
.addLine(" @Override public V setValue(V value) {")
.add(PreconditionExcerpts.checkNotNull("value"))
.addLine(" V oldValue = entry.getValue();")
.addLine(" put.accept(entry.getKey(), value);")
.addLine(" return oldValue;")
.addLine(" }")
.addLine("")
.addLine(" @Override public boolean equals(Object o) {")
.addLine(" return entry.equals(o);")
.addLine(" }")
.addLine("")
.addLine(" @Override public int hashCode() {")
.addLine(" return entry.hashCode();")
.addLine(" }")
.addLine("}");
}
};
private static final StaticExcerpt CHECKED_ENTRY_ITERATOR =
new StaticExcerpt(TYPE, "CheckedEntryIterator") {
@Override
public void addTo(SourceBuilder code) {
ParameterizedType biConsumer = code.feature(FUNCTION_PACKAGE).biConsumer().orNull();
if (biConsumer == null) {
return;
}
code.addLine("")
.addLine("private static class CheckedEntryIterator<K, V> implements %s<%s<K, V>> {",
Iterator.class, Map.Entry.class)
.addLine("")
.addLine(" private final %s<%s<K, V>> iterator;", Iterator.class, Map.Entry.class)
.addLine(" private final %s<K, V> put;", biConsumer.getQualifiedName())
.addLine("")
.addLine(" CheckedEntryIterator(")
.addLine(" %s<%s<K, V>> iterator,", Iterator.class, Map.Entry.class)
.addLine(" %s<K, V> put) {", biConsumer.getQualifiedName())
.addLine(" this.iterator = iterator;")
.addLine(" this.put = put;")
.addLine(" }")
.addLine("")
.addLine(" @Override public boolean hasNext() {")
.addLine(" return iterator.hasNext();")
.addLine(" }")
.addLine("")
.addLine(" @Override public %s<K, V> next() {", Map.Entry.class)
.addLine(" return new CheckedEntry<K, V>(iterator.next(), put);")
.addLine(" }")
.addLine("")
.addLine(" @Override public void remove() {")
.addLine(" iterator.remove();")
.addLine(" }")
.addLine("}");
}
};
private static final StaticExcerpt CHECKED_ENTRY_SET =
new StaticExcerpt(TYPE, "CheckedEntrySet") {
@Override
public void addTo(SourceBuilder code) {
ParameterizedType biConsumer = code.feature(FUNCTION_PACKAGE).biConsumer().orNull();
if (biConsumer == null) {
return;
}
code.addLine("")
.addLine("private static class CheckedEntrySet<K, V> extends %s<%s<K, V>> {",
AbstractSet.class, Map.Entry.class)
.addLine("")
.addLine(" private final %s<%s<K, V>> set;", Set.class, Map.Entry.class)
.addLine(" private final %s<K, V> put;", biConsumer.getQualifiedName())
.addLine("")
.addLine(" CheckedEntrySet(%s<%s<K, V>> set, %s<K, V> put) {",
Set.class, Map.Entry.class, biConsumer.getQualifiedName())
.addLine(" this.set = set;")
.addLine(" this.put = put;")
.addLine(" }")
.addLine("")
.addLine(" @Override public int size() {")
.addLine(" return set.size();")
.addLine(" }")
.addLine("")
.addLine(" @Override public %s<%s<K, V>> iterator() {",
Iterator.class, Map.Entry.class)
.addLine(" return new CheckedEntryIterator<K, V>(set.iterator(), put);")
.addLine(" }")
.addLine("")
.addLine(" @Override public boolean contains(Object o) {")
.addLine(" return set.contains(o);")
.addLine(" }")
.addLine("")
.addLine(" @Override public boolean remove(Object o) {")
.addLine(" return set.remove(o);")
.addLine(" }")
.addLine("")
.addLine(" @Override public void clear() {")
.addLine(" set.clear();")
.addLine(" }")
.addLine("}");
}
};
private static final StaticExcerpt CHECKED_MAP = new StaticExcerpt(TYPE, "CheckedMap") {
@Override
public void addTo(SourceBuilder code) {
ParameterizedType biConsumer = code.feature(FUNCTION_PACKAGE).biConsumer().orNull();
if (biConsumer == null) {
return;
}
code.addLine("")
.addLine("/**")
.addLine(" * A map implementation that delegates to a provided put method")
.addLine(" * to perform entry validation and insertion into a backing map.")
.addLine(" */")
.addLine("private static class CheckedMap<K, V> extends %s<K, V> {",
AbstractMap.class)
.addLine("")
.addLine(" private final %s<K, V> map;", Map.class)
.addLine(" private final %s<K, V> put;", biConsumer.getQualifiedName())
.addLine("")
.addLine(" CheckedMap(%s<K, V> map, %s<K, V> put) {",
Map.class, biConsumer.getQualifiedName())
.addLine(" this.map = map;")
.addLine(" this.put = put;")
.addLine(" }")
.addLine("")
.addLine(" @Override public V get(Object key) {")
.addLine(" return map.get(key);")
.addLine(" }")
.addLine("")
.addLine(" @Override public boolean containsKey(Object key) {")
.addLine(" return map.containsKey(key);")
.addLine(" }")
.addLine("")
.addLine(" @Override public V put(K key, V value) {")
.addLine(" V oldValue = map.get(key);")
.addLine(" put.accept(key, value);")
.addLine(" return oldValue;")
.addLine(" }")
.addLine("")
.addLine(" @Override public V remove(Object key) {")
.addLine(" return map.remove(key);")
.addLine(" }")
.addLine("")
.addLine(" @Override public void clear() {")
.addLine(" map.clear();")
.addLine(" }")
.addLine("")
.addLine(" @Override public %s<%s<K, V>> entrySet() {",
Set.class, Map.Entry.class)
.addLine(" return new CheckedEntrySet<>(map.entrySet(), put);")
.addLine(" }")
.addLine("}");
}
};
}