001package daikon.derive.binary;
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 two base variables. */
013public abstract class BinaryDerivation 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  public VarInfo base1;
021
022  /** Original variable 2. */
023  public VarInfo base2;
024
025  /**
026   * Create a new BinaryDerivation from two varinfos.
027   *
028   * @param vi1 original variable 1
029   * @param vi2 original variable 2
030   */
031  protected BinaryDerivation(VarInfo vi1, VarInfo vi2) {
032    base1 = vi1;
033    base2 = vi2;
034  }
035
036  @SideEffectFree
037  @Override
038  public BinaryDerivation clone(@GuardSatisfied BinaryDerivation this) {
039    try {
040      return (BinaryDerivation) super.clone();
041    } catch (CloneNotSupportedException e) {
042      throw new Error("This can't happen", e);
043    }
044  }
045
046  @SideEffectFree
047  @Override
048  public VarInfo[] getBases() {
049    return new VarInfo[] {base1, base2};
050  }
051
052  @Pure
053  @Override
054  public VarInfo getBase(int i) {
055    switch (i) {
056      case 0:
057        return base1;
058      case 1:
059        return base2;
060      default:
061        throw new Error("bad base: " + i);
062    }
063  }
064
065  @Override
066  public Derivation switchVars(VarInfo[] old_vars, VarInfo[] new_vars) {
067    BinaryDerivation result = this.clone();
068    result.base1 = new_vars[ArraysPlume.indexOf(old_vars, result.base1)];
069    result.base2 = new_vars[ArraysPlume.indexOf(old_vars, result.base2)];
070    return result;
071  }
072
073  @Override
074  public ValueAndModified computeValueAndModified(ValueTuple vt) {
075    int source_mod1 = base1.getModified(vt);
076    int source_mod2 = base2.getModified(vt);
077    // MISSING_NONSENSICAL takes precedence
078    if (source_mod1 == ValueTuple.MISSING_NONSENSICAL) {
079      return ValueAndModified.MISSING_NONSENSICAL;
080    }
081    if (source_mod2 == ValueTuple.MISSING_NONSENSICAL) {
082      return ValueAndModified.MISSING_NONSENSICAL;
083    }
084    if (source_mod1 == ValueTuple.MISSING_FLOW) {
085      return ValueAndModified.MISSING_FLOW;
086    }
087    if (source_mod2 == ValueTuple.MISSING_FLOW) {
088      return ValueAndModified.MISSING_FLOW;
089    }
090
091    return computeValueAndModifiedImpl(vt);
092  }
093
094  /** Actual implementation once mods are handled. */
095  protected abstract ValueAndModified computeValueAndModifiedImpl(ValueTuple vt);
096
097  @Pure
098  @Override
099  protected boolean isParam() {
100    return base1.isParam() || base2.isParam();
101  }
102
103  @Override
104  public int derivedDepth() {
105    return 1 + Math.max(base1.derivedDepth(), base2.derivedDepth());
106  }
107
108  @Override
109  public boolean canBeMissing() {
110    return base1.canBeMissing || base2.canBeMissing;
111  }
112
113  @Pure
114  @Override
115  public boolean isDerivedFromNonCanonical() {
116    // We insist that both are canonical, not just one.
117    return !(base1.isCanonical() && base2.isCanonical());
118  }
119
120  public VarInfo var1(@GuardSatisfied BinaryDerivation this) {
121    return base1;
122  }
123
124  public VarInfo var2(@GuardSatisfied BinaryDerivation this) {
125    return base2;
126  }
127}