comparison src/org/tmatesoft/hg/internal/RangeSeq.java @ 558:154718ae23ed

Annotate: refactor/reuse range handling code
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Mon, 25 Feb 2013 18:41:44 +0100
parents
children d3c71498919c
comparison
equal deleted inserted replaced
557:b9e5ac26dd83 558:154718ae23ed
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.Formatter;
20
21 /**
22 * Sequence of range pairs (denoted origin and target), {originStart, targetStart, length}, tailored for diff/annotate
23 *
24 * @author Artem Tikhomirov
25 * @author TMate Software Ltd.
26 */
27 public final class RangeSeq {
28 // XXX smth like IntSliceVector to access triples (or slices of any size, in fact)
29 // with easy indexing, e.g. #get(sliceIndex, indexWithinSlice)
30 // and vect.get(7,2) instead of vect.get(7*SIZEOF_SLICE+2)
31 private final IntVector ranges = new IntVector(3*10, 3*5);
32 private int count;
33
34 public void add(int start1, int start2, int length) {
35 if (count > 0) {
36 int lastIndex = 3 * (count-1);
37 int lastS1 = ranges.get(lastIndex);
38 int lastS2 = ranges.get(lastIndex + 1);
39 int lastLen = ranges.get(lastIndex + 2);
40 if (start1 == lastS1 + lastLen && start2 == lastS2 + lastLen) {
41 // new range continues the previous one - just increase the length
42 ranges.set(lastIndex + 2, lastLen + length);
43 return;
44 }
45 }
46 ranges.add(start1, start2, length);
47 count++;
48 }
49
50 public void clear() {
51 ranges.clear();
52 count = 0;
53 }
54
55 public int size() {
56 return count;
57 }
58
59 /**
60 * find out line index in the target that matches specified origin line
61 */
62 public int mapLineIndex(int ln) {
63 for (int i = 0; i < ranges.size(); i += 3) {
64 int s1 = ranges.get(i);
65 if (s1 > ln) {
66 return -1;
67 }
68 int l = ranges.get(i+2);
69 if (s1 + l > ln) {
70 int s2 = ranges.get(i + 1);
71 return s2 + (ln - s1);
72 }
73 }
74 return -1;
75 }
76
77 /**
78 * find out line index in origin that matches specified target line
79 */
80 public int reverseMapLine(int targetLine) {
81 for (int i = 0; i < ranges.size(); i +=3) {
82 int ts = ranges.get(i + 1);
83 if (ts > targetLine) {
84 return -1;
85 }
86 int l = ranges.get(i + 2);
87 if (ts + l > targetLine) {
88 int os = ranges.get(i);
89 return os + (targetLine - ts);
90 }
91 }
92 return -1;
93 }
94
95 public RangeSeq intersect(RangeSeq target) {
96 RangeSeq v = new RangeSeq();
97 for (int i = 0; i < ranges.size(); i += 3) {
98 int originLine = ranges.get(i);
99 int targetLine = ranges.get(i + 1);
100 int length = ranges.get(i + 2);
101 int startTargetLine = -1, startOriginLine = -1, c = 0;
102 for (int j = 0; j < length; j++) {
103 int lnInFinal = target.mapLineIndex(targetLine + j);
104 if (lnInFinal == -1 || (startTargetLine != -1 && lnInFinal != startTargetLine + c)) {
105 // the line is not among "same" in ultimate origin
106 // or belongs to another/next "same" chunk
107 if (startOriginLine == -1) {
108 continue;
109 }
110 v.add(startOriginLine, startTargetLine, c);
111 c = 0;
112 startOriginLine = startTargetLine = -1;
113 // fall-through to check if it's not complete miss but a next chunk
114 }
115 if (lnInFinal != -1) {
116 if (startOriginLine == -1) {
117 startOriginLine = originLine + j;
118 startTargetLine = lnInFinal;
119 c = 1;
120 } else {
121 // lnInFinal != startTargetLine + s is covered above
122 assert lnInFinal == startTargetLine + c;
123 c++;
124 }
125 }
126 }
127 if (startOriginLine != -1) {
128 assert c > 0;
129 v.add(startOriginLine, startTargetLine, c);
130 }
131 }
132 return v;
133 }
134
135 // true when specified line in origin is equal to a line in target
136 public boolean includesOriginLine(int ln) {
137 return includes(ln, 0);
138 }
139
140 // true when specified line in target is equal to a line in origin
141 public boolean includesTargetLine(int ln) {
142 return includes(ln, 1);
143 }
144
145 private boolean includes(int ln, int o) {
146 for (int i = 2; i < ranges.size(); o += 3, i+=3) {
147 int rangeStart = ranges.get(o);
148 if (rangeStart > ln) {
149 return false;
150 }
151 int rangeLen = ranges.get(i);
152 if (rangeStart + rangeLen > ln) {
153 return true;
154 }
155 }
156 return false;
157 }
158
159 public CharSequence dump() {
160 StringBuilder sb = new StringBuilder();
161 Formatter f = new Formatter(sb);
162 for (int i = 0; i < ranges.size(); i += 3) {
163 int s1 = ranges.get(i);
164 int s2 = ranges.get(i + 1);
165 int len = ranges.get(i + 2);
166 f.format("[%d..%d) == [%d..%d); ", s1, s1 + len, s2, s2 + len);
167 }
168 return sb;
169 }
170
171 @Override
172 public String toString() {
173 return String.format("RangeSeq[%d]", count);
174 }
175 }