Mercurial > hg4j
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 } |