package cmu.conditional; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.function.BiConsumer; import java.util.function.BiFunction; import de.fosd.typechef.featureexpr.FeatureExpr; /** * Choice implementation using a map from value to {@link FeatureExpr}. * * @author Jens Meinicke * * @param <T> */ public class MapChoice<T> extends IChoice<T> implements Cloneable { Map<T, FeatureExpr> map = new HashMap<>(); MapChoice(FeatureExpr featureExpr, Conditional<T> thenBranch, Conditional<T> elseBranch) { super(featureExpr, thenBranch, elseBranch); for (Entry<T, FeatureExpr> e : thenBranch.toMap().entrySet()) { FeatureExpr and = e.getValue().and(featureExpr); if (!isContradiction(and)) { if (map.containsKey(e.getKey())) { map.put(e.getKey(), map.get(e.getKey()).or(and)); } else { map.put(e.getKey(), and); } } } for (Entry<T, FeatureExpr> e : elseBranch.toMap().entrySet()) { FeatureExpr andNot = e.getValue().andNot(featureExpr); if (!isContradiction(andNot)) { if (map.containsKey(e.getKey())) { map.put(e.getKey(), map.get(e.getKey()).or(andNot)); } else { map.put(e.getKey(), andNot); } } } } MapChoice(Map<T, FeatureExpr> newMap) { super(newMap); map = newMap; } @Override public T getValue() { if (map.size() == 1) { return map.keySet().iterator().next(); } throw new RuntimeException("get Value on choice called" + map); } @Override public T getValue(final boolean ignore) { if (map.isEmpty()) { return null; } return map.keySet().iterator().next(); } @Override public <U> Conditional<U> mapfr(FeatureExpr inFeature, BiFunction<FeatureExpr, T, Conditional<U>> f) { Map<U, FeatureExpr> newMap = new HashMap<>(); for (Entry<T, FeatureExpr> e : map.entrySet()) { Conditional<U> result = f.apply(inFeature == null ? e.getValue() : e.getValue().and(inFeature), e.getKey()); if (result == null) { newMap.put(null, e.getValue()); continue; } for (Entry<U, FeatureExpr> r : result.toMap().entrySet()) {// ?? FeatureExpr and = r.getValue().and(e.getValue()); final U key = r.getKey(); if (newMap.containsKey(key)) { newMap.put(key, newMap.get(key).or(and)); } else { if (!isContradiction(and)) { newMap.put(key, and); } } } } return new MapChoice<>(newMap); } @Override public void mapfr(FeatureExpr inFeature, BiConsumer<FeatureExpr, T> f) { for (Entry<T, FeatureExpr> e : map.entrySet()) { f.accept(inFeature == null ? e.getValue() : e.getValue().and(inFeature), e.getKey()); } } @SuppressWarnings("unchecked") @Override public Conditional<T> simplifyValues() { if (map.size() == 1) { T value = map.keySet().iterator().next(); if (value instanceof Byte) { return (Conditional<T>) One.valueOf((Byte)value); } if (value instanceof Boolean) { return (Conditional<T>) One.valueOf((Boolean)value); } if (value instanceof Integer) { return (Conditional<T>) new One<>((Integer)value); } return new One<>(value); } return this; } @SuppressWarnings("unchecked") @Override public Conditional<T> simplify(FeatureExpr ctx) { if (map.size() == 1) { return simplifyValues(); } if (isTautology(ctx)) { return this; } Map<T, FeatureExpr> newMap = new HashMap<>(); for (Entry<T, FeatureExpr> e : map.entrySet()) { final FeatureExpr value = e.getValue(); if (!isContradiction(value.and(ctx))) { T key = e.getKey(); if (ctx.equals(value)) { if (key instanceof Byte) { return (Conditional<T>) One.valueOf((Byte)key); } if (key instanceof Boolean) { return (Conditional<T>) One.valueOf((Boolean)key); } if (key instanceof Integer) { return (Conditional<T>) new One<>((Integer)key); } return new One<>(key); } else { newMap.put(key, value); } } } return new MapChoice<>(newMap); } @Override public List<T> toList() { return new ArrayList<>(map.keySet()); } @Override protected void toMap(FeatureExpr f, Map<T, FeatureExpr> map) { throw new RuntimeException("Should never be called"); } @Override public Conditional<T> clone() throws CloneNotSupportedException { return new MapChoice<>(map); } @Override public int hashCode() { return map.hashCode();//throw new RuntimeException("not yet implemented"); } @Override public boolean equals(final Object o) { if (o instanceof MapChoice) { @SuppressWarnings("rawtypes") MapChoice other = (MapChoice) o; return other.map.equals(map); } return false; } @Override public String toString() { StringBuilder content = new StringBuilder(); content.append('{'); for (Entry<T, FeatureExpr> e: map.entrySet()) { content.append(getCTXString(e.getValue())); content.append(':'); content.append(e.getKey()); content.append(" ; "); } content.delete(content.length() - 3, content.length() - 1); content.append('}'); return content.toString(); } @Override public Map<T, FeatureExpr> toMap() { return map; } @Override public int size() { return map.size(); } }