001package daikon.derive.binary; 002 003import daikon.ProglangType; 004import daikon.ValueTuple; 005import daikon.VarInfo; 006import daikon.derive.Derivation; 007import daikon.derive.ValueAndModified; 008import java.util.logging.Logger; 009import org.checkerframework.checker.interning.qual.Interned; 010import org.checkerframework.checker.lock.qual.GuardSatisfied; 011import org.checkerframework.dataflow.qual.Pure; 012import org.checkerframework.dataflow.qual.SideEffectFree; 013import org.plumelib.util.ArraysPlume; 014import org.plumelib.util.Intern; 015 016/** 017 * Represents the concatenation of two base variables. This derived variable works for both 018 * sequences of numbers and strings. 019 */ 020public final class SequencesConcat extends BinaryDerivation { 021 static final long serialVersionUID = 20020122L; 022 023 /** Debug tracer. */ 024 public static final Logger debug = Logger.getLogger("daikon.derive.binary.SequencesConcat"); 025 026 // Variables starting with dkconfig_ should only be set via the 027 // daikon.config.Configuration interface. 028 /** Boolean. True iff SequencesConcat derived variables should be created. */ 029 public static boolean dkconfig_enabled = false; 030 031 @Override 032 public VarInfo var1(@GuardSatisfied SequencesConcat this) { 033 return base1; 034 } 035 036 @Override 037 public VarInfo var2(@GuardSatisfied SequencesConcat this) { 038 return base2; 039 } 040 041 /** 042 * Create a new SequenceScarlarConcat that represents the concatenation of two base variables. 043 * 044 * @param vi1 base variable 1 045 * @param vi2 base variable 2 046 */ 047 public SequencesConcat(VarInfo vi1, VarInfo vi2) { 048 super(vi1, vi2); 049 } 050 051 @Override 052 public ValueAndModified computeValueAndModifiedImpl(ValueTuple full_vt) { 053 Object val1 = var1().getValue(full_vt); 054 Object val2 = var2().getValue(full_vt); 055 056 int mod = ValueTuple.UNMODIFIED; 057 int mod1 = base1.getModified(full_vt); 058 int mod2 = base2.getModified(full_vt); 059 060 if (mod1 == ValueTuple.MODIFIED) { 061 mod = ValueTuple.MODIFIED; 062 } 063 if (mod1 == ValueTuple.MISSING_NONSENSICAL) { 064 mod = ValueTuple.MISSING_NONSENSICAL; 065 } 066 if (mod2 == ValueTuple.MODIFIED) { 067 mod = ValueTuple.MODIFIED; 068 } 069 if (mod2 == ValueTuple.MISSING_NONSENSICAL) { 070 mod = ValueTuple.MISSING_NONSENSICAL; 071 } 072 073 if (val1 == null && val2 == null) { 074 return new ValueAndModified(null, mod); 075 } 076 if (var1().rep_type == ProglangType.INT_ARRAY) { 077 // val1 instanceof long[] || val2 instanceof long[] 078 long[] result = 079 ArraysPlume.concat( 080 val1 == null ? null : (long[]) val1, val2 == null ? null : (long[]) val2); 081 return new ValueAndModified(Intern.intern(result), mod); 082 } else if (var1().rep_type == ProglangType.DOUBLE_ARRAY) { 083 double[] result = 084 ArraysPlume.concat( 085 val1 == null ? null : (double[]) val1, val2 == null ? null : (double[]) val2); 086 return new ValueAndModified(Intern.intern(result), mod); 087 088 } else if (var1().rep_type == ProglangType.STRING_ARRAY) { 089 // val1 instanceof String[] || val2 instanceof String[] 090 @Interned String[] result = 091 ArraysPlume.concat( 092 val1 == null ? null : (@Interned String[]) val1, 093 val2 == null ? null : (@Interned String[]) val2); 094 return new ValueAndModified(Intern.intern(result), mod); 095 } else { 096 throw new Error("Attempted to concatenate unknown arrays"); 097 } 098 } 099 100 @Override 101 protected VarInfo makeVarInfo() { 102 return VarInfo.make_function("concat", var1(), var2()); 103 } 104 105 @SideEffectFree 106 @Override 107 public String toString(@GuardSatisfied SequencesConcat this) { 108 return "[SequencesConcat of " + var1().name() + " " + var2().name() + "]"; 109 } 110 111 @Pure 112 @Override 113 public boolean isSameFormula(Derivation other) { 114 return (other instanceof SequencesConcat); 115 } 116 117 @SideEffectFree 118 @Override 119 public String esc_name(String index) { 120 return String.format("SequencesConcat[%s,%s]", var1().esc_name(), var2().esc_name()); 121 } 122}