package cmu.conditional; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.function.BiConsumer; import java.util.function.BiFunction; import de.fosd.typechef.featureexpr.FeatureExpr; /** * Choice implementation as tree. * Each node represents a decision as {@link FeatureExpr} between two conditionals. * * @author Jens Meinicke * */ class TreeChoice<T> extends IChoice<T> implements Cloneable { private Conditional<T> thenBranch; private Conditional<T> elseBranch; private FeatureExpr featureExpr; TreeChoice(FeatureExpr featureExpr, Conditional<T> thenBranch, Conditional<T> elseBranch) { super(featureExpr, thenBranch, elseBranch); this.featureExpr = featureExpr; this.thenBranch = thenBranch; this.elseBranch = elseBranch; } @Override public <U> Conditional<U> mapfr(final FeatureExpr inFeature, final BiFunction<FeatureExpr, T, Conditional<U>> f) { if (inFeature == null) { Conditional<U> newResultA = thenBranch.mapfr(null, f); Conditional<U> newResultB = elseBranch.mapfr(null, f); return new TreeChoice<>(featureExpr, newResultA, newResultB); } Conditional<U> newResultA = thenBranch.mapfr(inFeature.and(featureExpr), f); Conditional<U> newResultB = elseBranch.mapfr(inFeature.and(featureExpr.not()), f); return new TreeChoice<>(featureExpr, newResultA, newResultB); } @Override public void mapfr(final FeatureExpr inFeature, final BiConsumer<FeatureExpr, T> f) { if (inFeature == null) { thenBranch.mapfr(null, f); elseBranch.mapfr(null, f); return; } thenBranch.mapfr(inFeature.and(featureExpr), f); elseBranch.mapfr(inFeature.and(featureExpr.not()), f); } @Override public Conditional<T> simplify(FeatureExpr ctx) { FeatureExpr and = ctx.and(featureExpr); if (isContradiction(and)) { return elseBranch.simplify(ctx.andNot(featureExpr)); } FeatureExpr andNot = ctx.andNot(featureExpr); if (isContradiction(andNot)) { return thenBranch.simplify(and); } final Conditional<T> tb = thenBranch.simplify(and); final Conditional<T> eb = elseBranch.simplify(andNot); if (tb.equals(eb)) { return tb; } if (tb instanceof One) { if (eb instanceof TreeChoice) { if (((TreeChoice<T>) eb).thenBranch.equals(tb)) { return new TreeChoice<>(featureExpr.or(featureExpr.not().and(((TreeChoice<T>) eb).featureExpr)), tb, ((TreeChoice<T>) eb).elseBranch); } if (((TreeChoice<T>) eb).elseBranch.equals(tb)) { return new TreeChoice<>(featureExpr.or(featureExpr.not().and(((TreeChoice<T>) eb).featureExpr.not())), tb, ((TreeChoice<T>) eb).thenBranch); } } } if (eb instanceof One) { if (tb instanceof TreeChoice) { if (((TreeChoice<T>) tb).thenBranch.equals(eb)) { return new TreeChoice<>(featureExpr.not().or(featureExpr.and(((TreeChoice<T>) tb).featureExpr)), eb, ((TreeChoice<T>) tb).elseBranch); } if (((TreeChoice<T>) tb).elseBranch.equals(eb)) { return new TreeChoice<>(featureExpr.not().or(featureExpr.and(((TreeChoice<T>) tb).featureExpr.not())), eb, ((TreeChoice<T>) tb).thenBranch); } } } return new TreeChoice<>(featureExpr, tb, eb); } @Override public String toString() { return "Choice(" + getCTXString(featureExpr) + ", " + thenBranch + ", " + elseBranch + ")"; } @SuppressWarnings("unchecked") @Override public boolean equals(Object obj) { if (obj instanceof TreeChoice) { TreeChoice<T> c = (TreeChoice<T>) obj; return c.thenBranch.equals(thenBranch) && c.elseBranch.equals(elseBranch) && c.featureExpr.equivalentTo(featureExpr); } return false; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((elseBranch == null) ? 0 : elseBranch.hashCode()); result = prime * result + ((featureExpr == null) ? 0 : featureExpr.hashCode()); result = prime * result + ((thenBranch == null) ? 0 : thenBranch.hashCode()); return result; } @Override public T getValue() { System.out.println("___________________________________________________"); System.out.println("Get value of choice called: " + this); for (StackTraceElement e : Thread.currentThread().getStackTrace()) { System.out.println(e); } System.out.println("---------------------------------------------------"); // return thenBranch.getValue(true); throw new RuntimeException("Get value of choice called: " + toString()); } @Override public T getValue(boolean ignore) { if (ignore) { return thenBranch.getValue(ignore); } return getValue(); } @Override public List<T> toList() { List<T> list = new LinkedList<>(); for (T e : thenBranch.toList()) { if (!list.contains(e)) { list.add(e); } } for (T e : elseBranch.toList()) { if (!list.contains(e)) { list.add(e); } } return list; } @Override protected void toMap(FeatureExpr ctx, Map<T, FeatureExpr> map) { thenBranch.toMap(ctx.and(featureExpr), map); elseBranch.toMap(ctx.andNot(featureExpr), map); } @Override public Conditional<T> clone() throws CloneNotSupportedException { return new TreeChoice<>(featureExpr, thenBranch.clone(), elseBranch.clone()); } @Override public Conditional<T> simplifyValues() { final Conditional<T> tb = thenBranch.simplifyValues(); final Conditional<T> eb = elseBranch.simplifyValues(); if (tb.equals(eb)) { return tb; } if (tb instanceof One) { if (eb instanceof TreeChoice) { if (((TreeChoice<T>) eb).thenBranch.equals(tb)) { return new TreeChoice<>(featureExpr.or(featureExpr.not().and(((TreeChoice<T>) eb).featureExpr)), tb, ((TreeChoice<T>) eb).elseBranch); } if (((TreeChoice<T>) eb).elseBranch.equals(tb)) { return new TreeChoice<>(featureExpr.or(featureExpr.not().and(((TreeChoice<T>) eb).featureExpr.not())), tb, ((TreeChoice<T>) eb).thenBranch); } } } if (eb instanceof One) { if (tb instanceof TreeChoice) { if (((TreeChoice<T>) tb).thenBranch.equals(eb)) { return new TreeChoice<>(featureExpr.not().or(featureExpr.and(((TreeChoice<T>) tb).featureExpr)), eb, ((TreeChoice<T>) tb).elseBranch); } if (((TreeChoice<T>) tb).elseBranch.equals(eb)) { return new TreeChoice<>(featureExpr.not().or(featureExpr.and(((TreeChoice<T>) tb).featureExpr.not())), eb, ((TreeChoice<T>) tb).thenBranch); } } } return new TreeChoice<>(featureExpr, tb, eb); } @Override public int size() { return thenBranch.size() + elseBranch.size(); } }