Mercurial > jhg
comparison src/org/tmatesoft/hg/internal/Patch.java @ 329:694ebabb5cb3
Refactor revlog patch mechanism, towards patch merging
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Thu, 13 Oct 2011 03:30:50 +0200 |
parents | |
children | 9747a786a34d |
comparison
equal
deleted
inserted
replaced
328:a674b8590362 | 329:694ebabb5cb3 |
---|---|
1 /* | |
2 * Copyright (c) 2011 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.io.IOException; | |
20 import java.util.ArrayList; | |
21 | |
22 /** | |
23 * @see http://mercurial.selenic.com/wiki/BundleFormat, in Changelog group description | |
24 * | |
25 * range [start..end] in original source gets replaced with data of length (do not keep, use data.length instead) | |
26 * range [end(i)..start(i+1)] is copied from the source | |
27 * | |
28 * @author Artem Tikhomirov | |
29 * @author TMate Software Ltd. | |
30 */ | |
31 public final class Patch { | |
32 private final IntVector starts, ends; | |
33 private final ArrayList<byte[]> data; | |
34 | |
35 public Patch() { | |
36 starts = new IntVector(); | |
37 ends = new IntVector(); | |
38 data = new ArrayList<byte[]>(); | |
39 } | |
40 | |
41 public int count() { | |
42 return data.size(); | |
43 } | |
44 | |
45 // number of bytes this patch will add (or remove, if negative) from the base revision | |
46 private int patchSizeDelta() { | |
47 int rv = 0; | |
48 int prevEnd = 0; | |
49 for (int i = 0, x = data.size(); i < x; i++) { | |
50 final int start = starts.get(i); | |
51 final int len = data.get(i).length; | |
52 rv += start - prevEnd; // would copy from original | |
53 rv += len; // and add new | |
54 prevEnd = ends.get(i); | |
55 } | |
56 rv -= prevEnd; | |
57 return rv; | |
58 } | |
59 | |
60 public byte[] apply(DataAccess baseRevisionContent, int outcomeLen) throws IOException { | |
61 if (outcomeLen == -1) { | |
62 outcomeLen = baseRevisionContent.length() + patchSizeDelta(); | |
63 } | |
64 int prevEnd = 0, destIndex = 0; | |
65 byte[] rv = new byte[outcomeLen]; | |
66 for (int i = 0, x = data.size(); i < x; i++) { | |
67 final int start = starts.get(i); | |
68 baseRevisionContent.seek(prevEnd); | |
69 // copy source bytes that were not modified (up to start of the record) | |
70 baseRevisionContent.readBytes(rv, destIndex, start - prevEnd); | |
71 destIndex += start - prevEnd; | |
72 // insert new data from the patch, if any | |
73 byte[] d = data.get(i); | |
74 System.arraycopy(d, 0, rv, destIndex, d.length); | |
75 destIndex += d.length; | |
76 prevEnd = ends.get(i); | |
77 } | |
78 baseRevisionContent.seek(prevEnd); | |
79 // copy everything in the source past last record's end | |
80 baseRevisionContent.readBytes(rv, destIndex, (int) (baseRevisionContent.length() - prevEnd)); | |
81 return rv; | |
82 } | |
83 | |
84 public void clear() { | |
85 starts.clear(); | |
86 ends.clear(); | |
87 data.clear(); | |
88 } | |
89 | |
90 /** | |
91 * Initialize instance from stream. Any previous patch information (i.e. if instance if reused) is cleared first. | |
92 * Read up to the end of DataAccess and interpret data as patch records. | |
93 */ | |
94 public void read(DataAccess da) throws IOException { | |
95 clear(); | |
96 while (!da.isEmpty()) { | |
97 readOne(da); | |
98 } | |
99 } | |
100 | |
101 /** | |
102 * Caller is responsible to ensure stream got some data to read | |
103 */ | |
104 public void readOne(DataAccess da) throws IOException { | |
105 int s = da.readInt(); | |
106 int e = da.readInt(); | |
107 int len = da.readInt(); | |
108 byte[] src = new byte[len]; | |
109 da.readBytes(src, 0, len); | |
110 starts.add(s); | |
111 ends.add(e); | |
112 data.add(src); | |
113 } | |
114 | |
115 /* | |
116 private void add(Patch another, int index) { | |
117 starts.add(another.starts.get(index)); | |
118 ends.add(another.ends.get(index)); | |
119 data.add(another.data.get(index)); | |
120 } | |
121 | |
122 /** | |
123 * Modify this patch with subsequent patch | |
124 * / | |
125 public void apply(Patch another) { | |
126 Patch r = new Patch(); | |
127 int p1AppliedPos = 0; | |
128 int p1PrevEnd = 0; | |
129 for (int i = 0, j = 0, iMax = another.count(), jMax = this.count(); i < iMax; i++) { | |
130 int newerPatchEntryStart = another.starts.get(i); | |
131 int olderPatchEntryEnd; | |
132 | |
133 while (j < jMax) { | |
134 if (starts.get(j) < newerPatchEntryStart) { | |
135 if (starts.get(j)+data.get(j).length <= newerPatchEntryStart) { | |
136 r.add(this, j); | |
137 } else { | |
138 int newLen = newerPatchEntryStart - starts.get(j); | |
139 int newEnd = ends.get(j) <= newerPatchEntryStart ? ends.get(j) : newerPatchEntryStart; | |
140 r.add(starts.get(j), newEnd, data.get(j), newLen); | |
141 break; | |
142 } | |
143 } | |
144 p1AppliedPos += starts.get(j) - p1PrevEnd; | |
145 p1AppliedPos += data.get(j).length; | |
146 p1PrevEnd = ends.get(j); | |
147 j++; | |
148 } | |
149 r.add(newerPatchEntryStart, another.ends.get(i), another.data.get(i)); | |
150 p1AppliedPos += newerPatchEntryStart + p1PrevEnd - another.data.get(i).length; | |
151 // either j == jMax and another(i, i+1, ..., iMax) need to be just copied | |
152 // or new patch entry starts before end of one of original patch entries | |
153 if (olderPatchEntryEnd > (destPosition + newerPatchEntryStart)) { | |
154 destPosition += starts.get(j) - prevEnd; // count those in the original stream up to old patch start | |
155 int newLen = newerPatchEntryStart - destPosition; | |
156 } | |
157 } | |
158 } | |
159 */ | |
160 } |