Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

283
LINES

< > BotCompany Repo | #1000883 // class BlockDiffer

JavaX fragment (include)

1  
2  
static class BlockDiff {
3  
  public CopyBlock asCopyBlock() { return null; }
4  
  public NewBlock  asNewBlock () { return null; }
5  
}
6  
7  
static class CopyBlock extends BlockDiff {
8  
  int firstLine, lines;
9  
10  
  CopyBlock(int firstLine, int lines) {
11  
    this.firstLine = firstLine;
12  
    this.lines = lines;
13  
  }
14  
15  
  public CopyBlock asCopyBlock() { return this; }
16  
  public int getFirstLine() { return firstLine; }
17  
  public int getLines() { return lines; }
18  
}
19  
20  
static class NewBlock extends BlockDiff {
21  
  int originalStart;
22  
  List<String> contents;
23  
24  
  NewBlock(int originalStart, List<String> contents) {
25  
    this.originalStart = originalStart;
26  
    this.contents = contents;
27  
  }
28  
29  
  public NewBlock  asNewBlock () { return this; }
30  
31  
  public int getOriginalStart() {
32  
    return originalStart;
33  
  }
34  
35  
  public List<String> getContents() {
36  
    return contents;
37  
  }
38  
}
39  
40  
static class ExplodedLine {
41  
  int type;
42  
  String left, right;
43  
  int leftIndex, rightIndex;
44  
45  
  ExplodedLine(int type, String left, String right, int leftIndex, int rightIndex) {
46  
    this.type = type;
47  
    this.left = left;
48  
    this.right = right;
49  
    this.leftIndex = leftIndex;
50  
    this.rightIndex = rightIndex;
51  
  }
52  
  
53  
  public int getType() {
54  
    return type;
55  
  }
56  
57  
  public String getLeft() {
58  
    return left;
59  
  }
60  
61  
  public String getRight() {
62  
    return right;
63  
  }
64  
65  
  public int getLeftIndex() {
66  
    return leftIndex;
67  
  }
68  
69  
  public int getRightIndex() {
70  
    return rightIndex;
71  
  }
72  
}
73  
74  
static class BlockDiffer {
75  
  public static final int IDENTICAL = 0;
76  
  public static final int DIFFERENT = 1;
77  
  public static final int LEFT_ONLY = 2;
78  
  public static final int RIGHT_ONLY = 3;
79  
80  
  private static void printChange(EGDiff.change change) {
81  
    if (change != null) {
82  
      System.out.println("line0="+change.line0+", line1="+change.line1
83  
        +", inserted="+change.inserted+", deleted="+change.deleted);
84  
      printChange(change.link);
85  
    }
86  
  }
87  
88  
89  
  /** Generates the text content of a Unified-format context diff between 2 files
90  
   *  (NB the 'files-changed' header must be added separately).
91  
   */
92  
  public static List<String> generateUniDiff(List<String> fileA, List<String> fileB, int contextSize) {
93  
    EGDiff diff = new EGDiff(fileA.toArray(), fileB.toArray());
94  
    EGDiff.change change = diff.diff_2(false);
95  
96  
    if (change != null) {
97  
      int inserted, deleted;
98  
      List<String> hunkLines = new ArrayList<String>();
99  
      int cumulExtraLinesBwrtA = 0;
100  
101  
      // Each hunk is generated with a header
102  
      do {
103  
        int line0 = change.line0, line1 = change.line1;
104  
        int changeStart = ((line1 < line0) ? line1 : line0);
105  
        int contextStart = ((changeStart > contextSize) ? changeStart - contextSize : 0);
106  
        int headerPosn = hunkLines.size();
107  
108  
        // Provide the first lines of context
109  
        for (int i = contextStart; i < changeStart; i++)
110  
          //System.out.println(" " + fileA.get(i));
111  
          hunkLines.add(" " + fileA.get(i));
112  
113  
        boolean hunkFinish = false;
114  
        // Step through each change giving the change lines and following context
115  
        do {
116  
          inserted = change.inserted;
117  
          deleted = change.deleted;
118  
          line0 = change.line0;
119  
          line1 = change.line1;
120  
121  
          if (line1 < line0) // An insert comes earlier
122  
            while (inserted-- > 0)
123  
              hunkLines.add("+" + fileB.get(line1++));
124  
          while (deleted-- > 0)
125  
            hunkLines.add("-" + fileA.get(line0++));
126  
          while (inserted-- > 0)
127  
            hunkLines.add("+" + fileB.get(line1++));
128  
129  
          // Lines following are trailing context, identical in fileA and fileB
130  
          // The next change may overlap the context, so check and if so, form one hunk
131  
          EGDiff.change nextChange = change.link;
132  
          int nextChangeStart = fileA.size();
133  
          if (nextChange != null)
134  
            nextChangeStart = ((nextChange.line1 < nextChange.line0) ? nextChange.line1 : nextChange.line0);
135  
136  
          if (nextChangeStart - line0 > contextSize * 2) { // A separate hunk
137  
            nextChangeStart = line0 + contextSize;
138  
            hunkFinish = true;
139  
          }
140  
          if (nextChangeStart > fileA.size())
141  
            nextChangeStart = fileA.size(); // Limit to file size
142  
          while (line0 < nextChangeStart) {
143  
            hunkLines.add(" " + fileA.get(line0++));
144  
            line1++; // Keep in sync with trailing context
145  
          }
146  
147  
          change = change.link;
148  
        } while (!hunkFinish && change != null);
149  
150  
        int hunkStartB = contextStart + cumulExtraLinesBwrtA;
151  
        int hunkTotA = line0 - contextStart;
152  
        int hunkTotB = line1 - hunkStartB;
153  
154  
        hunkLines.add(headerPosn, "@@ -" + (contextStart + 1) + ',' + hunkTotA +
155  
                        " +" + (hunkStartB + 1) + ',' + hunkTotB + " @@");
156  
        cumulExtraLinesBwrtA += hunkTotB - hunkTotA;
157  
158  
      } while (change != null);
159  
160  
      return hunkLines;
161  
    }
162  
    return null;
163  
  }
164  
165  
/* For testing:
166  
  private static void printUniDiff(List<String> fileA, List<String> fileB, int contextSize) {
167  
    List<String> uniDiff = generateUniDiff(fileA, fileB, contextSize);
168  
169  
    if (uniDiff != null)
170  
      for (int j = 0; j < uniDiff.size(); j++)
171  
        System.out.println(uniDiff.get(j));
172  
  }
173  
 */
174  
175  
176  
  public static List<BlockDiff> diffLines(List<String> lines, List<String> reference) {
177  
    List<BlockDiff> diffs = new ArrayList<BlockDiff>();
178  
179  
    EGDiff diff = new EGDiff(reference.toArray(), lines.toArray());
180  
    EGDiff.change change = diff.diff_2(false);
181  
    //printChange(change);
182  
    //printUniDiff(reference, lines, 3);
183  
184  
    int l0 = 0, l1 = 0;
185  
    while (change != null) {
186  
      if (change.line0 > l0 && change.line1 > l1)
187  
        diffs.add(new CopyBlock(l0, change.line0-l0));
188  
189  
      if (change.inserted != 0)
190  
        diffs.add(new NewBlock(change.line1, lines.subList(change.line1, change.line1+change.inserted)));
191  
192  
      l0 = change.line0 + change.deleted;
193  
      l1 = change.line1 + change.inserted;
194  
      change = change.link;
195  
    }
196  
197  
    if (l0 < reference.size())
198  
      diffs.add(new CopyBlock(l0, reference.size()-l0));
199  
200  
    return diffs;
201  
  }
202  
203  
  /** fills files with empty lines to align matching blocks
204  
   *
205  
   * @param file1 first file
206  
   * @param file2 second file
207  
   * @return an array with two lists
208  
   */
209  
  public static List<ExplodedLine> explode(List<String> file1, List<String> file2) {
210  
    List<ExplodedLine> lines = new ArrayList<ExplodedLine>();
211  
    List<BlockDiff> diffs = BlockDiffer.diffLines(file2, file1);
212  
    int lastLineCopied = 0, rightOnlyStart = -1, rightPosition = 0;
213  
    for (int i = 0; i < diffs.size(); i++) {
214  
      BlockDiff diff = diffs.get(i);
215  
      if (diff instanceof CopyBlock) {
216  
        CopyBlock copyBlock = (CopyBlock) diff;
217  
        if (lastLineCopied < copyBlock.getFirstLine()) {
218  
          if (rightOnlyStart >= 0) {
219  
            int overlap = Math.min(lines.size()-rightOnlyStart, copyBlock.getFirstLine()-lastLineCopied);
220  
            //lines.subList(rightOnlyStart, rightOnlyStart+overlap).clear();
221  
            convertRightOnlyToDifferent(lines, rightOnlyStart, overlap, file1, lastLineCopied);
222  
            lastLineCopied += overlap;
223  
          }
224  
          addBlock(lines, LEFT_ONLY, file1, lastLineCopied, copyBlock.getFirstLine(), lastLineCopied, -1);
225  
        }
226  
        addBlock(lines, IDENTICAL, file1, copyBlock.getFirstLine(), copyBlock.getFirstLine()+copyBlock.getLines(),
227  
          copyBlock.getFirstLine(), rightPosition);
228  
        rightPosition += copyBlock.getLines();
229  
        lastLineCopied = copyBlock.getFirstLine()+copyBlock.getLines();
230  
        rightOnlyStart = -1;
231  
      } else if (diff instanceof NewBlock) {
232  
        NewBlock newBlock = (NewBlock) diff;
233  
        /*if (nextDiff instanceof BlockDiffer.CopyBlock) {
234  
          BlockDiffer.CopyBlock copyBlock = (BlockDiffer.CopyBlock) nextDiff;
235  
          copyBlock.getFirstLine()-lastLineCopied*/
236  
        rightOnlyStart = lines.size();
237  
        addBlock(lines, RIGHT_ONLY, newBlock.getContents(), 0, newBlock.getContents().size(), -1, rightPosition);
238  
        rightPosition += newBlock.getContents().size();
239  
      }
240  
    }
241  
242  
    if (rightOnlyStart >= 0) {
243  
      int overlap = Math.min(lines.size()-rightOnlyStart, file1.size()-lastLineCopied);
244  
      //lines.subList(rightOnlyStart, rightOnlyStart+overlap).clear();
245  
      convertRightOnlyToDifferent(lines, rightOnlyStart, overlap, file1, lastLineCopied);
246  
      lastLineCopied += overlap;
247  
    }
248  
    addBlock(lines, LEFT_ONLY, file1, lastLineCopied, file1.size(), lastLineCopied, -1);
249  
250  
    return lines;
251  
  }
252  
253  
  private static void convertRightOnlyToDifferent(List<ExplodedLine> lines, int start, int numLines,
254  
                                                  List<String> leftLines, int leftStart) {
255  
    for (int i = 0; i < numLines; i++) {
256  
      ExplodedLine line = lines.get(start+i);
257  
      lines.set(start+i,
258  
        new ExplodedLine(DIFFERENT, leftLines.get(i+leftStart), line.getRight(), i+leftStart, line.getRightIndex()));
259  
    }
260  
  }
261  
262  
  private static void addBlock(List<ExplodedLine> lines, int type, List<String> srcLines, int start, int end,
263  
                               int leftStart, int rightStart) {
264  
    for (int i = start; i < end; i++)
265  
      lines.add(new ExplodedLine(type, type == RIGHT_ONLY ? "" : srcLines.get(i),
266  
                                       type == LEFT_ONLY ? "" : srcLines.get(i),
267  
                                       type == RIGHT_ONLY ? -1 : i - start + leftStart,
268  
                                       type == LEFT_ONLY ? -1 : i - start + rightStart));
269  
  }
270  
271  
  public static List<ExplodedLine> condense(List<ExplodedLine> lines) {
272  
    List<ExplodedLine> result = new ArrayList<ExplodedLine>();
273  
    for (Iterator<ExplodedLine> i = lines.iterator(); i.hasNext();) {
274  
      ExplodedLine line = i.next();
275  
      if (line.getType() == IDENTICAL) {
276  
        if (result.isEmpty() || result.get(result.size()-1).getType() != IDENTICAL)
277  
          result.add(new ExplodedLine(IDENTICAL, "[...]", "[...]", -1, -1));
278  
      } else
279  
        result.add(line);
280  
    }
281  
    return result;
282  
  }
283  
}

download  show line numbers  debug dex  old transpilations   

Travelled to 16 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, ddnzoavkxhuk, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, onxytkatvevr, pyentgdyhuwx, pzhvpgtvlbxg, sawdedvomwva, tslmcundralx, tvejysmllsmz, vouqrxazstgt

No comments. add comment

Snippet ID: #1000883
Snippet name: class BlockDiffer
Eternal ID of this version: #1000883/1
Text MD5: 726e475ca1b8374567b281f5db99c764
Author: stefan
Category: javax
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2016-05-25 17:17:34
Source code size: 10251 bytes / 283 lines
Pitched / IR pitched: No / No
Views / Downloads: 660 / 6087
Referenced in: [show references]