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}