comparison test/org/tmatesoft/hg/test/FileAnnotation.java @ 546:cd78e8b9d7bc

File annotate test. Refactored FileAnnotation as standalone class, introduced LineInspector to make line offset calc code shared
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Mon, 18 Feb 2013 19:19:48 +0100
parents
children
comparison
equal deleted inserted replaced
545:15b406c7cd9d 546:cd78e8b9d7bc
1 /*
2 * Copyright (c) 2013 TMate Software Ltd
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * For information on how to redistribute this software under
14 * the terms of a license other than GNU General Public License
15 * contact TMate Software at support@hg4j.com
16 */
17 package org.tmatesoft.hg.test;
18
19 import java.util.LinkedList;
20
21 import org.tmatesoft.hg.internal.AnnotateFacility;
22 import org.tmatesoft.hg.internal.AnnotateFacility.LineInspector;
23 import org.tmatesoft.hg.internal.IntVector;
24 import org.tmatesoft.hg.internal.AnnotateFacility.AddBlock;
25 import org.tmatesoft.hg.internal.AnnotateFacility.ChangeBlock;
26 import org.tmatesoft.hg.internal.AnnotateFacility.DeleteBlock;
27 import org.tmatesoft.hg.internal.AnnotateFacility.EqualBlock;
28
29 /**
30 *
31 * @author Artem Tikhomirov
32 * @author TMate Software Ltd.
33 */
34 public class FileAnnotation implements AnnotateFacility.BlockInspectorEx {
35 // blocks deleted in the target, as reported at the previous step
36 private LinkedList<DeleteBlock> deleted = new LinkedList<DeleteBlock>();
37 // blocks deleted in the origin, to become deletions in target at the next step
38 private LinkedList<DeleteBlock> newDeleted = new LinkedList<DeleteBlock>();
39 // keeps <startSeq1, startSeq2, len> of equal blocks, origin to target, from previous step
40 // XXX smth like IntSliceVector to access triples (or slices of any size, in fact)
41 // with easy indexing, e.g. #get(sliceIndex, indexWithinSlice)
42 // and vect.get(7,2) instead of vect.get(7*SIZEOF_SLICE+2)
43 private IntVector identical = new IntVector(20*3, 2*3);
44 // equal blocks of the current iteration, to be recalculated before next step
45 // to track line number (current target to ultimate target) mapping
46 private IntVector newIdentical = new IntVector(20*3, 2*3);
47
48 private boolean[] knownLines;
49 private final LineInspector delegate;
50
51 public FileAnnotation(AnnotateFacility.LineInspector lineInspector) {
52 delegate = lineInspector;
53 }
54
55 public void start(int originLineCount, int targetLineCount) {
56 if (knownLines == null) {
57 knownLines = new boolean[targetLineCount];
58 }
59 }
60
61 // private static void ppp(IntVector v) {
62 // for (int i = 0; i < v.size(); i+= 3) {
63 // int len = v.get(i+2);
64 // System.out.printf("[%d..%d) == [%d..%d); ", v.get(i), v.get(i) + len, v.get(i+1), v.get(i+1) + len);
65 // }
66 // System.out.println();
67 // }
68
69 public void done() {
70 if (identical.size() > 0) {
71 // update line numbers of the intermediate target to point to ultimate target's line numbers
72 IntVector v = new IntVector(identical.size(), 2*3);
73 for (int i = 0; i < newIdentical.size(); i+= 3) {
74 int originLine = newIdentical.get(i);
75 int targetLine = newIdentical.get(i+1);
76 int length = newIdentical.get(i+2);
77 int startTargetLine = -1, startOriginLine = -1, c = 0;
78 for (int j = 0; j < length; j++) {
79 int lnInFinal = mapLineIndex(targetLine + j);
80 if (lnInFinal == -1 || (startTargetLine != -1 && lnInFinal != startTargetLine + c)) {
81 // the line is not among "same" in ultimate origin
82 // or belongs to another/next "same" chunk
83 if (startOriginLine == -1) {
84 continue;
85 }
86 v.add(startOriginLine);
87 v.add(startTargetLine);
88 v.add(c);
89 c = 0;
90 startOriginLine = startTargetLine = -1;
91 // fall-through to check if it's not complete miss but a next chunk
92 }
93 if (lnInFinal != -1) {
94 if (startOriginLine == -1) {
95 startOriginLine = originLine + j;
96 startTargetLine = lnInFinal;
97 c = 1;
98 } else {
99 assert lnInFinal == startTargetLine + c;
100 c++;
101 }
102 }
103 }
104 if (startOriginLine != -1) {
105 assert c > 0;
106 v.add(startOriginLine);
107 v.add(startTargetLine);
108 v.add(c);
109 }
110 }
111 newIdentical.clear();
112 identical = v;
113 } else {
114 IntVector li = newIdentical;
115 newIdentical = identical;
116 identical = li;
117 }
118 LinkedList<DeleteBlock> ld = newDeleted;
119 deleted.clear();
120 newDeleted = deleted;
121 deleted = ld;
122 }
123
124 public void same(EqualBlock block) {
125 newIdentical.add(block.originStart());
126 newIdentical.add(block.targetStart());
127 newIdentical.add(block.length());
128 }
129
130 public void added(AddBlock block) {
131 for (int i = 0, ln = block.firstAddedLine(), x = block.totalAddedLines(); i < x; i++, ln++) {
132 int lnInFinal = mapLineIndex(ln);
133 if (lnInFinal != -1 && !knownLines[lnInFinal]) {
134 delegate.line(lnInFinal, block.targetChangesetIndex(), new LineDescriptor());
135 knownLines[lnInFinal] = true;
136 }
137 }
138 }
139
140 public void changed(ChangeBlock block) {
141 deleted(block);
142 added(block);
143 }
144
145 public void deleted(DeleteBlock block) {
146 newDeleted.add(block);
147 }
148
149 // line - index in the target
150 private boolean isDeleted(int line) {
151 for (DeleteBlock b : deleted) {
152 if (b.firstRemovedLine() > line) {
153 break;
154 }
155 // line >= b.firstRemovedLine
156 if (b.firstRemovedLine() + b.totalRemovedLines() > line) {
157 return true;
158 }
159 }
160 return false;
161 }
162
163 // map target lines to the lines of the revision being annotated (the one that came first)
164 private int mapLineIndex(int ln) {
165 if (isDeleted(ln)) {
166 return -1;
167 }
168 if (identical.isEmpty()) {
169 return ln;
170 }
171 for (int i = 0; i < identical.size(); i += 3) {
172 final int originStart = identical.get(i);
173 if (originStart > ln) {
174 // assert false;
175 return -1;
176 }
177 // ln >= b.originStart
178 final int length = identical.get(i+2);
179 if (originStart + length > ln) {
180 int targetStart = identical.get(i+1);
181 return targetStart + (ln - originStart);
182 }
183 }
184 // assert false;
185 return -1;
186 }
187
188 private final class LineDescriptor implements AnnotateFacility.LineDescriptor {
189 LineDescriptor() {
190 }
191
192 public int totalLines() {
193 return FileAnnotation.this.knownLines.length;
194 }
195 }
196 }