001package daikon.derive.unary; 002 003import daikon.ProglangType; 004import daikon.Quantify; 005import daikon.ValueTuple; 006import daikon.VarInfo; 007import daikon.VarInfoAux; 008import daikon.derive.Derivation; 009import daikon.derive.ValueAndModified; 010import daikon.derive.binary.SequenceFloatIntersection; 011import daikon.derive.binary.SequenceFloatSubsequence; 012import daikon.derive.binary.SequenceFloatUnion; 013import daikon.derive.binary.SequenceScalarIntersection; 014import daikon.derive.binary.SequenceScalarSubsequence; 015import daikon.derive.binary.SequenceScalarUnion; 016import daikon.derive.binary.SequenceStringIntersection; 017import daikon.derive.binary.SequenceStringUnion; 018import daikon.derive.binary.SequencesConcat; 019import daikon.derive.binary.SequencesJoin; 020import daikon.derive.binary.SequencesJoinFloat; 021import daikon.derive.binary.SequencesPredicate; 022import daikon.derive.binary.SequencesPredicateFloat; 023import daikon.derive.ternary.SequenceFloatArbitrarySubsequence; 024import daikon.derive.ternary.SequenceScalarArbitrarySubsequence; 025import org.checkerframework.dataflow.qual.Pure; 026import org.checkerframework.dataflow.qual.SideEffectFree; 027import org.plumelib.util.Intern; 028 029// originally from pass1. 030public final class SequenceLength extends UnaryDerivation { 031 static final long serialVersionUID = 20020122L; 032 033 // Variables starting with dkconfig_ should only be set via the 034 // daikon.config.Configuration interface. 035 /** Boolean. True iff SequenceLength derived variables should be generated. */ 036 public static boolean dkconfig_enabled = true; 037 038 public final int shift; 039 040 public SequenceLength(VarInfo vi, int shift) { 041 super(vi); 042 this.shift = shift; // typically 0 or -1 043 } 044 045 public static boolean applicable(VarInfo vi) { 046 assert vi.rep_type.isArray(); 047 048 if (vi.derived != null) { 049 assert ((vi.derived instanceof SequenceScalarSubsequence) 050 || (vi.derived instanceof SequenceScalarArbitrarySubsequence) 051 || (vi.derived instanceof SequenceStringIntersection) 052 || (vi.derived instanceof SequenceScalarIntersection) 053 || (vi.derived instanceof SequenceStringUnion) 054 || (vi.derived instanceof SequenceScalarUnion) 055 || (vi.derived instanceof SequencesConcat) 056 || (vi.derived instanceof SequencesPredicate) 057 || (vi.derived instanceof SequencesJoin) 058 || (vi.derived instanceof SequenceFloatSubsequence) 059 || (vi.derived instanceof SequenceFloatArbitrarySubsequence) 060 || (vi.derived instanceof SequenceFloatIntersection) 061 || (vi.derived instanceof SequenceFloatUnion) 062 || (vi.derived instanceof SequencesPredicateFloat) 063 || (vi.derived instanceof SequencesJoinFloat)); 064 065 if (!( // All of the below give new information when taking a sizeof 066 (vi.derived instanceof SequenceStringIntersection) 067 || (vi.derived instanceof SequenceScalarIntersection) 068 || (vi.derived instanceof SequenceStringUnion) 069 || (vi.derived instanceof SequenceScalarUnion) 070 || (vi.derived instanceof SequencesConcat) 071 || (vi.derived instanceof SequenceFloatIntersection) 072 || (vi.derived instanceof SequenceFloatUnion))) { 073 074 return false; 075 } 076 } 077 // Don't do this for now, because we depend on being able to call 078 // sequenceSize() later. 079 // if (vi.name.indexOf("~.") != -1) 080 // return false; 081 082 return true; 083 } 084 085 @Override 086 public ValueAndModified computeValueAndModifiedImpl(ValueTuple vt) { 087 int source_mod = base.getModified(vt); 088 if (source_mod == ValueTuple.MISSING_NONSENSICAL) { 089 return ValueAndModified.MISSING_NONSENSICAL; 090 } 091 Object val = base.getValue(vt); 092 if (val == null) { 093 return ValueAndModified.MISSING_NONSENSICAL; 094 } 095 096 int len; 097 ProglangType rep_type = base.rep_type; 098 099 if (rep_type == ProglangType.INT_ARRAY) { 100 len = ((long[]) val).length; 101 } else if (rep_type == ProglangType.DOUBLE_ARRAY) { 102 len = ((double[]) val).length; 103 } else { 104 len = ((Object[]) val).length; 105 } 106 return new ValueAndModified(Intern.internedLong(len + shift), source_mod); 107 } 108 109 @Override 110 protected VarInfo makeVarInfo() { 111 VarInfo v = VarInfo.make_scalar_seq_func("size", ProglangType.INT, base, shift); 112 113 if (base.aux.hasValue(VarInfoAux.MINIMUM_LENGTH)) { 114 v.aux = 115 v.aux.setInt( 116 VarInfoAux.MINIMUM_VALUE, base.aux.getInt(VarInfoAux.MINIMUM_LENGTH) + shift); 117 } 118 if (base.aux.hasValue(VarInfoAux.MAXIMUM_LENGTH)) { 119 v.aux = 120 v.aux.setInt( 121 VarInfoAux.MAXIMUM_VALUE, base.aux.getInt(VarInfoAux.MAXIMUM_LENGTH) + shift); 122 } 123 124 return v; 125 } 126 127 @Pure 128 @Override 129 public boolean isSameFormula(Derivation other) { 130 return (other instanceof SequenceLength) && (((SequenceLength) other).shift == this.shift); 131 } 132 133 @Override 134 @SuppressWarnings("nullness") 135 @SideEffectFree 136 public String esc_name(String index) { 137 // This should be able to use Quantify.Length to calculate the name, 138 // but it can't because the old version formatted these slightly 139 // differently. But this could be used when the old regression results 140 // are no longer needed. 141 // Quantify.Length ql = new Quantify.Length (base, shift); 142 // return ql.esc_name(); 143 144 if (base.isPrestate()) { 145 return String.format( 146 "\\old(%s.length)%s", base.enclosing_var.postState.esc_name(), shift_str(shift)); 147 } else { 148 return String.format("%s.length%s", base.enclosing_var.esc_name(), shift_str(shift)); 149 } 150 } 151 152 @Override 153 public String jml_name(String index) { 154 Quantify.Length ql = new Quantify.Length(base, shift); 155 return ql.jml_name(); 156 } 157 158 @SideEffectFree 159 @Override 160 public String simplify_name() { 161 Quantify.Length ql = new Quantify.Length(base, shift); 162 return ql.simplify_name(); 163 } 164 165 @SideEffectFree 166 @Override 167 public String csharp_name(String index) { 168 Quantify.Length ql = new Quantify.Length(base, shift); 169 return ql.csharp_name(); 170 } 171 172 /** Adds one to the default complexity if shift is not 0. */ 173 @Override 174 public int complexity() { 175 return super.complexity() + ((shift != 0) ? 1 : 0); 176 } 177}