KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > jrcs > diff > myers > MyersDiff


1 /*
2  * ====================================================================
3  *
4  * The Apache Software License, Version 1.1
5  *
6  * Copyright (c) 1999-2003 The Apache Software Foundation. All rights
7  * reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in
18  * the documentation and/or other materials provided with the
19  * distribution.
20  *
21  * 3. The end-user documentation included with the redistribution, if
22  * any, must include the following acknowledgement:
23  * "This product includes software developed by the
24  * Apache Software Foundation (http://www.apache.org/)."
25  * Alternately, this acknowledgement may appear in the software itself,
26  * if and wherever such third-party acknowledgements normally appear.
27  *
28  * 4. The names "The Jakarta Project", "Commons", and "Apache Software
29  * Foundation" must not be used to endorse or promote products derived
30  * from this software without prior written permission. For written
31  * permission, please contact apache@apache.org.
32  *
33  * 5. Products derived from this software may not be called "Apache"
34  * nor may "Apache" appear in their names without prior written
35  * permission of the Apache Software Foundation.
36  *
37  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
41  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48  * SUCH DAMAGE.
49  * ====================================================================
50  *
51  * This software consists of voluntary contributions made by many
52  * individuals on behalf of the Apache Software Foundation. For more
53  * information on the Apache Software Foundation, please see
54  * <http://www.apache.org/>.
55  *
56  */

57
58 package org.apache.commons.jrcs.diff.myers;
59
60 import org.apache.commons.jrcs.diff.*;
61
62 /**
63  * A clean-room implementation of
64  * <a HREF="http://www.cs.arizona.edu/people/gene/">
65  * Eugene Myers</a> differencing algorithm.
66  * <p>
67  * See the paper at
68  * <a HREF="http://www.cs.arizona.edu/people/gene/PAPERS/diff.ps">
69  * http://www.cs.arizona.edu/people/gene/PAPERS/diff.ps</a>
70  *
71  * @version $Revision: 1.2 $ $Date: 2005/06/16 18:11:13 $
72  * @author <a HREF="mailto:juanco@suigeneris.org">Juanco Anez</a>
73  * @see Delta
74  * @see Revision
75  * @see Diff
76  */

77 public class MyersDiff
78     implements DiffAlgorithm
79 {
80     /**
81      * Constructs an instance of the Myers differencing algorithm.
82      */

83     public MyersDiff()
84     {
85         // do nothing
86
}
87
88     /**
89      * {@inheritDoc}
90      */

91     public Revision diff(Object JavaDoc[] orig, Object JavaDoc[] rev)
92         throws DifferentiationFailedException
93     {
94         PathNode path = buildPath(orig, rev);
95         return buildRevision(path, orig, rev);
96     }
97
98     /**
99      * Computes the minimum diffpath that expresses de differences
100      * between the original and revised sequences, according
101      * to Gene Myers differencing algorithm.
102      *
103      * @param orig The original sequence.
104      * @param rev The revised sequence.
105      * @return A minimum {@link PathNode Path} accross the differences graph.
106      * @throws DifferentiationFailedException if a diff path could not be found.
107      */

108     public static PathNode buildPath(Object JavaDoc[] orig, Object JavaDoc[] rev)
109         throws DifferentiationFailedException
110     {
111         if (orig == null)
112             throw new IllegalArgumentException JavaDoc("original sequence is null");
113         if (rev == null)
114             throw new IllegalArgumentException JavaDoc("revised sequence is null");
115
116         // these are local constants
117
final int N = orig.length;
118         final int M = rev.length;
119
120         final int MAX = N + M + 1;
121         final int size = 1 + 2 * MAX;
122         final int middle = (size + 1) / 2;
123         final PathNode diagonal[] = new PathNode[size];
124
125         diagonal[middle + 1] = new Snake(0, -1, null);
126         for (int d = 0; d < MAX; d++)
127         {
128             for (int k = -d; k <= d; k += 2)
129             {
130                 final int kmiddle = middle + k;
131                 final int kplus = kmiddle + 1;
132                 final int kminus = kmiddle - 1;
133                 PathNode prev = null;
134
135                 int i;
136                 if ( (k == -d) ||
137                     (k != d && diagonal[kminus].i < diagonal[kplus].i))
138                 {
139                     i = diagonal[kplus].i;
140                     prev = diagonal[kplus];
141                 }
142                 else
143                 {
144                     i = diagonal[kminus].i + 1;
145                     prev = diagonal[kminus];
146                 }
147
148                 diagonal[kminus] = null; // no longer used
149

150                 int j = i - k;
151
152                 PathNode node = new DiffNode(i, j, prev);
153
154                 // orig and rev are zero-based
155
// but the algorithm is one-based
156
// that's why there's no +1 when indexing the sequences
157
while (i < N && j < M && orig[i].equals(rev[j]))
158                 {
159                     i++;
160                     j++;
161                 }
162                 if (i > node.i)
163                     node = new Snake(i, j, node);
164
165                 diagonal[kmiddle] = node;
166
167                 if (i >= N && j >= M)
168                 {
169                     return diagonal[kmiddle];
170                 }
171             }
172             diagonal[middle+d-1] = null;
173
174         }
175         // According to Myers, this cannot happen
176
throw new DifferentiationFailedException("could not find a diff path");
177     }
178
179     /**
180      * Constructs a {@link Revision} from a difference path.
181      *
182      * @param path The path.
183      * @param orig The original sequence.
184      * @param rev The revised sequence.
185      * @return A {@link Revision} script corresponding to the path.
186      * @throws DifferentiationFailedException if a {@link Revision} could
187      * not be built from the given path.
188      */

189     public static Revision buildRevision(PathNode path, Object JavaDoc[] orig, Object JavaDoc[] rev)
190     {
191         if (path == null)
192             throw new IllegalArgumentException JavaDoc("path is null");
193         if (orig == null)
194             throw new IllegalArgumentException JavaDoc("original sequence is null");
195         if (rev == null)
196             throw new IllegalArgumentException JavaDoc("revised sequence is null");
197
198         Revision revision = new Revision();
199         if (path.isSnake())
200             path = path.prev;
201         while (path != null && path.prev != null && path.prev.j >= 0)
202         {
203             if(path.isSnake())
204                throw new IllegalStateException JavaDoc("bad diffpath: found snake when looking for diff");
205             int i = path.i;
206             int j = path.j;
207
208             path = path.prev;
209             int ianchor = path.i;
210             int janchor = path.j;
211
212             Delta delta = Delta.newDelta(new Chunk(orig, ianchor, i - ianchor),
213                                          new Chunk(rev, janchor, j - janchor));
214             revision.insertDelta(delta);
215             if (path.isSnake())
216                 path = path.prev;
217         }
218         return revision;
219     }
220
221 }
222
Popular Tags