001package daikon.derive.ternary;
002
003import daikon.ValueTuple;
004import daikon.VarInfo;
005import daikon.derive.Derivation;
006import daikon.derive.ValueAndModified;
007import org.checkerframework.checker.lock.qual.GuardSatisfied;
008import org.checkerframework.dataflow.qual.Pure;
009import org.checkerframework.dataflow.qual.SideEffectFree;
010import org.plumelib.util.ArraysPlume;
011
012/** Abstract class to represent a derived variable that came from three base variables. */
013public abstract class TernaryDerivation extends Derivation {
014  // We are Serializable, so we specify a version to allow changes to
015  // method signatures without breaking serialization.  If you add or
016  // remove fields, you should change this number to the current date.
017  static final long serialVersionUID = 20020122L;
018
019  /** Original variable 1. */
020  VarInfo base1;
021
022  /** Original variable 2. */
023  VarInfo base2;
024
025  /** Original variable 3. */
026  VarInfo base3;
027
028  /**
029   * Create a new TernaryDerivation from three varinfos.
030   *
031   * @param vi1 original variable 1
032   * @param vi2 original variable 2
033   * @param vi3 original variable 3
034   */
035  protected TernaryDerivation(VarInfo vi1, VarInfo vi2, VarInfo vi3) {
036    base1 = vi1;
037    base2 = vi2;
038    base3 = vi3;
039  }
040
041  @SideEffectFree
042  @Override
043  public TernaryDerivation clone(@GuardSatisfied TernaryDerivation this) {
044    try {
045      return (TernaryDerivation) super.clone();
046    } catch (CloneNotSupportedException e) {
047      throw new Error("This can't happen", e);
048    }
049  }
050
051  @SideEffectFree
052  @Override
053  public VarInfo[] getBases() {
054    return new VarInfo[] {base1, base2, base3};
055  }
056
057  @Pure
058  @Override
059  public VarInfo getBase(int i) {
060    switch (i) {
061      case 0:
062        return base1;
063      case 1:
064        return base2;
065      case 2:
066        return base3;
067      default:
068        throw new Error("bad base: " + i);
069    }
070  }
071
072  @Override
073  public Derivation switchVars(VarInfo[] old_vars, VarInfo[] new_vars) {
074    TernaryDerivation result = this.clone();
075    result.base1 = new_vars[ArraysPlume.indexOf(old_vars, result.base1)];
076    result.base2 = new_vars[ArraysPlume.indexOf(old_vars, result.base2)];
077    result.base3 = new_vars[ArraysPlume.indexOf(old_vars, result.base3)];
078    return result;
079  }
080
081  @Override
082  public abstract ValueAndModified computeValueAndModified(ValueTuple full_vt);
083
084  @Pure
085  @Override
086  protected boolean isParam() {
087    return base1.isParam() || base2.isParam() || base3.isParam();
088  }
089
090  @Override
091  public int derivedDepth() {
092    return 1 + Math.max(base1.derivedDepth(), Math.max(base2.derivedDepth(), base3.derivedDepth()));
093  }
094
095  @Override
096  public boolean canBeMissing() {
097    return base1.canBeMissing || base2.canBeMissing || base3.canBeMissing;
098  }
099
100  @Pure
101  @Override
102  public boolean isDerivedFromNonCanonical() {
103    // We insist that both are canonical, not just one.
104    return !(base1.isCanonical() && base2.isCanonical() && base3.isCanonical());
105  }
106}