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  static final long serialVersionUID = 20020122L;
015
016  /** Original variable 1. */
017  VarInfo base1;
018
019  /** Original variable 2. */
020  VarInfo base2;
021
022  /** Original variable 3. */
023  VarInfo base3;
024
025  /**
026   * Create a new TernaryDerivation from three varinfos.
027   *
028   * @param vi1 original variable 1
029   * @param vi2 original variable 2
030   * @param vi3 original variable 3
031   */
032  protected TernaryDerivation(VarInfo vi1, VarInfo vi2, VarInfo vi3) {
033    base1 = vi1;
034    base2 = vi2;
035    base3 = vi3;
036  }
037
038  @SideEffectFree
039  @Override
040  public TernaryDerivation clone(@GuardSatisfied TernaryDerivation this) {
041    try {
042      return (TernaryDerivation) super.clone();
043    } catch (CloneNotSupportedException e) {
044      throw new Error("This can't happen", e);
045    }
046  }
047
048  @SideEffectFree
049  @Override
050  public VarInfo[] getBases() {
051    return new VarInfo[] {base1, base2, base3};
052  }
053
054  @Pure
055  @Override
056  public VarInfo getBase(int i) {
057    switch (i) {
058      case 0:
059        return base1;
060      case 1:
061        return base2;
062      case 2:
063        return base3;
064      default:
065        throw new Error("bad base: " + i);
066    }
067  }
068
069  @Override
070  public Derivation switchVars(VarInfo[] old_vars, VarInfo[] new_vars) {
071    TernaryDerivation result = this.clone();
072    result.base1 = new_vars[ArraysPlume.indexOf(old_vars, result.base1)];
073    result.base2 = new_vars[ArraysPlume.indexOf(old_vars, result.base2)];
074    result.base3 = new_vars[ArraysPlume.indexOf(old_vars, result.base3)];
075    return result;
076  }
077
078  @Override
079  public abstract ValueAndModified computeValueAndModified(ValueTuple full_vt);
080
081  @Pure
082  @Override
083  protected boolean isParam() {
084    return base1.isParam() || base2.isParam() || base3.isParam();
085  }
086
087  @Override
088  public int derivedDepth() {
089    return 1 + Math.max(base1.derivedDepth(), Math.max(base2.derivedDepth(), base3.derivedDepth()));
090  }
091
092  @Override
093  public boolean canBeMissing() {
094    return base1.canBeMissing || base2.canBeMissing || base3.canBeMissing;
095  }
096
097  @Pure
098  @Override
099  public boolean isDerivedFromNonCanonical() {
100    // We insist that both are canonical, not just one.
101    return !(base1.isCanonical() && base2.isCanonical() && base3.isCanonical());
102  }
103}