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