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}