Mercurial > hg4j
comparison src/org/tmatesoft/hg/internal/RangePairSeq.java @ 674:cce0387c6041
Introduced dedicated IntSliceSeq/IntTuple in place of IntArray with subsequences
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Wed, 17 Jul 2013 15:40:51 +0200 |
parents | src/org/tmatesoft/hg/internal/RangeSeq.java@d3c71498919c |
children |
comparison
equal
deleted
inserted
replaced
673:545b1d4cc11d | 674:cce0387c6041 |
---|---|
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 RangePairSeq { | |
28 private final IntSliceSeq ranges = new IntSliceSeq(3); | |
29 | |
30 public void add(int start1, int start2, int length) { | |
31 int count = ranges.size(); | |
32 if (count > 0) { | |
33 int lastS1 = ranges.get(--count, 0); | |
34 int lastS2 = ranges.get(count, 1); | |
35 int lastLen = ranges.get(count, 2); | |
36 if (start1 == lastS1 + lastLen && start2 == lastS2 + lastLen) { | |
37 // new range continues the previous one - just increase the length | |
38 ranges.set(count, lastS1, lastS2, lastLen + length); | |
39 return; | |
40 } | |
41 } | |
42 ranges.add(start1, start2, length); | |
43 } | |
44 | |
45 public void clear() { | |
46 ranges.clear(); | |
47 } | |
48 | |
49 public int size() { | |
50 return ranges.size(); | |
51 } | |
52 | |
53 /** | |
54 * find out line index in the target that matches specified origin line | |
55 */ | |
56 public int mapLineIndex(int ln) { | |
57 for (IntTuple t : ranges) { | |
58 int s1 = t.at(0); | |
59 if (s1 > ln) { | |
60 return -1; | |
61 } | |
62 int l = t.at(2); | |
63 if (s1 + l > ln) { | |
64 int s2 = t.at(1); | |
65 return s2 + (ln - s1); | |
66 } | |
67 } | |
68 return -1; | |
69 } | |
70 | |
71 /** | |
72 * find out line index in origin that matches specified target line | |
73 */ | |
74 public int reverseMapLine(int targetLine) { | |
75 for (IntTuple t : ranges) { | |
76 int ts = t.at(1); | |
77 if (ts > targetLine) { | |
78 return -1; | |
79 } | |
80 int l = t.at(2); | |
81 if (ts + l > targetLine) { | |
82 int os = t.at(0); | |
83 return os + (targetLine - ts); | |
84 } | |
85 } | |
86 return -1; | |
87 } | |
88 | |
89 public RangePairSeq intersect(RangePairSeq target) { | |
90 RangePairSeq v = new RangePairSeq(); | |
91 for (IntTuple t : ranges) { | |
92 int originLine = t.at(0); | |
93 int targetLine = t.at(1); | |
94 int length = t.at(2); | |
95 int startTargetLine = -1, startOriginLine = -1, c = 0; | |
96 for (int j = 0; j < length; j++) { | |
97 int lnInFinal = target.mapLineIndex(targetLine + j); | |
98 if (lnInFinal == -1 || (startTargetLine != -1 && lnInFinal != startTargetLine + c)) { | |
99 // the line is not among "same" in ultimate origin | |
100 // or belongs to another/next "same" chunk | |
101 if (startOriginLine == -1) { | |
102 continue; | |
103 } | |
104 v.add(startOriginLine, startTargetLine, c); | |
105 c = 0; | |
106 startOriginLine = startTargetLine = -1; | |
107 // fall-through to check if it's not complete miss but a next chunk | |
108 } | |
109 if (lnInFinal != -1) { | |
110 if (startOriginLine == -1) { | |
111 startOriginLine = originLine + j; | |
112 startTargetLine = lnInFinal; | |
113 c = 1; | |
114 } else { | |
115 // lnInFinal != startTargetLine + s is covered above | |
116 assert lnInFinal == startTargetLine + c; | |
117 c++; | |
118 } | |
119 } | |
120 } | |
121 if (startOriginLine != -1) { | |
122 assert c > 0; | |
123 v.add(startOriginLine, startTargetLine, c); | |
124 } | |
125 } | |
126 return v; | |
127 } | |
128 | |
129 // true when specified line in origin is equal to a line in target | |
130 public boolean includesOriginLine(int ln) { | |
131 return includes(ln, 0); | |
132 } | |
133 | |
134 // true when specified line in target is equal to a line in origin | |
135 public boolean includesTargetLine(int ln) { | |
136 return includes(ln, 1); | |
137 } | |
138 | |
139 private boolean includes(int ln, int o) { | |
140 for (IntTuple t : ranges) { | |
141 int rangeStart = t.at(o); | |
142 if (rangeStart > ln) { | |
143 return false; | |
144 } | |
145 int rangeLen = t.at(2); | |
146 if (rangeStart + rangeLen > ln) { | |
147 return true; | |
148 } | |
149 } | |
150 return false; | |
151 } | |
152 | |
153 public CharSequence dump() { | |
154 StringBuilder sb = new StringBuilder(); | |
155 Formatter f = new Formatter(sb); | |
156 for (IntTuple t : ranges) { | |
157 int s1 = t.at(0); | |
158 int s2 = t.at(1); | |
159 int len = t.at(2); | |
160 f.format("[%d..%d) == [%d..%d); ", s1, s1 + len, s2, s2 + len); | |
161 } | |
162 return sb; | |
163 } | |
164 | |
165 @Override | |
166 public String toString() { | |
167 return String.format("RangeSeq[%d]:%s", size(), dump()); | |
168 } | |
169 } |