comparison src/org/tmatesoft/hg/internal/FileAnnotation.java @ 548:ab21ac7dd833

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