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}