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}