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.base.Preconditions;
import com.google.common.collect.ForwardingSetMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.SetMultimap;
import org.inferred.freebuilder.processor.util.ParameterizedType;
import org.inferred.freebuilder.processor.util.SourceBuilder;
import org.inferred.freebuilder.processor.util.StaticExcerpt;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable;
/**
* Excerpts defining a multimap implementation that delegates to a provided put method to perform
* entry validation and insertion into a backing multimap.
*/
public class CheckedSetMultimap {
public static Set<StaticExcerpt> excerpts() {
return ImmutableSet.<StaticExcerpt>builder()
.addAll(CheckedSet.excerpts())
.add(CHECKED_SET_MULTIMAP)
.build();
}
private static final StaticExcerpt CHECKED_SET_MULTIMAP =
new StaticExcerpt(TYPE, "CheckedSetMultimap") {
@Override
public void addTo(SourceBuilder code) {
ParameterizedType biConsumer = code.feature(FUNCTION_PACKAGE).biConsumer().orNull();
if (biConsumer == null) {
return;
}
code.addLine("")
.addLine("/**")
.addLine(" * A multimap implementation that delegates to a provided put method")
.addLine(" * to perform entry validation and insertion into a backing multimap.")
.addLine(" */")
.addLine("private static class CheckedSetMultimap<K, V> extends %s<K, V> {",
ForwardingSetMultimap.class)
.addLine("")
.addLine(" private final %s<K, V> multimap;", SetMultimap.class)
.addLine(" private final %s<K, V> put;", biConsumer.getQualifiedName())
.addLine("")
.addLine(" CheckedSetMultimap(%s<K, V> multimap, %s<K, V> put) {",
SetMultimap.class, biConsumer.getQualifiedName())
.addLine(" this.multimap = multimap;")
.addLine(" this.put = put;")
.addLine(" }")
.addLine("")
.addLine(" @Override protected %s<K, V> delegate() {", SetMultimap.class)
.addLine(" return multimap;")
.addLine(" }")
.addLine("")
.addLine(" @Override public boolean put(@%1$s K key, @%1$s V value) {",
Nullable.class)
.addLine(" put.accept(key, value);")
.addLine(" return true;")
.addLine(" }")
.addLine("")
.addLine(" @Override public boolean putAll(@%s K key, %s<? extends V> values) {",
Nullable.class, Iterable.class)
.addLine(" boolean anyModified = false;")
.addLine(" for (V value : values) {")
.addLine(" put.accept(key, value);")
.addLine(" anyModified = true;")
.addLine(" }")
.addLine(" return anyModified;")
.addLine(" }")
.addLine("")
.addLine(" @Override public boolean putAll(%s<? extends K, ? extends V> multimap) {",
Multimap.class)
.addLine(" boolean anyModified = false;")
.addLine(" for (%s<? extends K, ? extends V> entry : multimap.entries()) {",
Map.Entry.class)
.addLine(" put.accept(entry.getKey(), entry.getValue());")
.addLine(" anyModified = true;")
.addLine(" }")
.addLine(" return anyModified;")
.addLine(" }")
.addLine("")
.addLine(" @Override")
.addLine(" public %s<V> replaceValues(@%s K key, %s<? extends V> values) {",
Set.class, Nullable.class, Iterable.class)
.addLine(" %s.checkNotNull(values);", Preconditions.class)
.addLine(" %s<V> result = removeAll(key);", Set.class)
.addLine(" putAll(key, values);")
.addLine(" return result;")
.addLine(" }")
.addLine("")
.addLine(" @Override public %s<V> get(@%s K key) {", Set.class, Nullable.class)
.addLine(" return new CheckedSet<>(")
.addLine(" multimap.get(key), value -> put.accept(key, value));")
.addLine(" }")
.addLine("")
.addLine(" @Override public %s<K, %s<V>> asMap() {", Map.class, Collection.class)
.addLine(" return %s.transformEntries(%s.asMap(multimap), (key, values) -> ",
Maps.class, Multimaps.class)
.addLine(" (%s<V>) new CheckedSet<>(", Collection.class)
.addLine(" values, value -> put.accept(key, value)));")
.addLine(" }")
.addLine("}");
}
};
}