Allow AbstractTreeIterators to find out about StopWalkExceptions
[egit/zawir.git] / org.spearce.jgit / src / org / spearce / jgit / treewalk / AbstractTreeIterator.java
blob232204a38bfe858066c3ba94c21d20cd03e149be
1 /*
2 * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
3 * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or
8 * without modification, are permitted provided that the following
9 * conditions are met:
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * - Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided
17 * with the distribution.
19 * - Neither the name of the Git Development Community nor the
20 * names of its contributors may be used to endorse or promote
21 * products derived from this software without specific prior
22 * written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
25 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
26 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
29 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
34 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
36 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 package org.spearce.jgit.treewalk;
41 import java.io.IOException;
42 import java.nio.ByteBuffer;
43 import java.nio.CharBuffer;
45 import org.spearce.jgit.errors.CorruptObjectException;
46 import org.spearce.jgit.errors.IncorrectObjectTypeException;
47 import org.spearce.jgit.lib.Constants;
48 import org.spearce.jgit.lib.FileMode;
49 import org.spearce.jgit.lib.ObjectId;
50 import org.spearce.jgit.lib.Repository;
51 import org.spearce.jgit.treewalk.filter.TreeFilter;
53 /**
54 * Walks a Git tree (directory) in Git sort order.
55 * <p>
56 * A new iterator instance should be positioned before the first entry. The data
57 * about the first entry is not available until after the first call to
58 * {@link #next()} is made.
59 * <p>
60 * Implementors must walk a tree in the Git sort order, which has the following
61 * odd sorting:
62 * <ol>
63 * <li>A.c</li>
64 * <li>A/c</li>
65 * <li>A0c</li>
66 * </ol>
67 * <p>
68 * In the second item, <code>A</code> is the name of a subtree and
69 * <code>c</code> is a file within that subtree. The other two items are files
70 * in the root level tree.
72 * @see CanonicalTreeParser
74 public abstract class AbstractTreeIterator {
75 private static final int DEFAULT_PATH_SIZE = 128;
77 /** A dummy object id buffer that matches the zero ObjectId. */
78 protected static final byte[] zeroid = new byte[Constants.OBJECT_ID_LENGTH];
80 /** Iterator for the parent tree; null if we are the root iterator. */
81 final AbstractTreeIterator parent;
83 /** The iterator this current entry is path equal to. */
84 AbstractTreeIterator matches;
86 /**
87 * Mode bits for the current entry.
88 * <p>
89 * A numerical value from FileMode is usually faster for an iterator to
90 * obtain from its data source so this is the preferred representation.
92 * @see org.spearce.jgit.lib.FileMode
94 protected int mode;
96 /**
97 * Path buffer for the current entry.
98 * <p>
99 * This buffer is pre-allocated at the start of walking and is shared from
100 * parent iterators down into their subtree iterators. The sharing allows
101 * the current entry to always be a full path from the root, while each
102 * subtree only needs to populate the part that is under their control.
104 protected byte[] path;
107 * Position within {@link #path} this iterator starts writing at.
108 * <p>
109 * This is the first offset in {@link #path} that this iterator must
110 * populate during {@link #next}. At the root level (when {@link #parent}
111 * is null) this is 0. For a subtree iterator the index before this position
112 * should have the value '/'.
114 protected final int pathOffset;
117 * Total length of the current entry's complete path from the root.
118 * <p>
119 * This is the number of bytes within {@link #path} that pertain to the
120 * current entry. Values at this index through the end of the array are
121 * garbage and may be randomly populated from prior entries.
123 protected int pathLen;
125 /** Create a new iterator with no parent. */
126 protected AbstractTreeIterator() {
127 parent = null;
128 path = new byte[DEFAULT_PATH_SIZE];
129 pathOffset = 0;
133 * Create a new iterator with no parent and a prefix.
134 * <p>
135 * The prefix path supplied is inserted in front of all paths generated by
136 * this iterator. It is intended to be used when an iterator is being
137 * created for a subsection of an overall repository and needs to be
138 * combined with other iterators that are created to run over the entire
139 * repository namespace.
141 * @param prefix
142 * position of this iterator in the repository tree. The value
143 * may be null or the empty string to indicate the prefix is the
144 * root of the repository. A trailing slash ('/') is
145 * automatically appended if the prefix does not end in '/'.
147 protected AbstractTreeIterator(final String prefix) {
148 parent = null;
150 if (prefix != null && prefix.length() > 0) {
151 final ByteBuffer b;
153 b = Constants.CHARSET.encode(CharBuffer.wrap(prefix));
154 pathLen = b.limit();
155 path = new byte[Math.max(DEFAULT_PATH_SIZE, pathLen + 1)];
156 b.get(path, 0, pathLen);
157 if (path[pathLen - 1] != '/')
158 path[pathLen++] = '/';
159 pathOffset = pathLen;
160 } else {
161 path = new byte[DEFAULT_PATH_SIZE];
162 pathOffset = 0;
167 * Create an iterator for a subtree of an existing iterator.
169 * @param p
170 * parent tree iterator.
172 protected AbstractTreeIterator(final AbstractTreeIterator p) {
173 parent = p;
174 path = p.path;
175 pathOffset = p.pathLen + 1;
176 try {
177 path[pathOffset - 1] = '/';
178 } catch (ArrayIndexOutOfBoundsException e) {
179 growPath(p.pathLen);
180 path[pathOffset - 1] = '/';
185 * Create an iterator for a subtree of an existing iterator.
186 * <p>
187 * The caller is responsible for setting up the path of the child iterator.
189 * @param p
190 * parent tree iterator.
191 * @param childPath
192 * path array to be used by the child iterator. This path must
193 * contain the path from the top of the walk to the first child
194 * and must end with a '/'.
195 * @param childPathOffset
196 * position within <code>childPath</code> where the child can
197 * insert its data. The value at
198 * <code>childPath[childPathOffset-1]</code> must be '/'.
200 protected AbstractTreeIterator(final AbstractTreeIterator p,
201 final byte[] childPath, final int childPathOffset) {
202 parent = p;
203 path = childPath;
204 pathOffset = childPathOffset;
208 * Grow the path buffer larger.
210 * @param len
211 * number of live bytes in the path buffer. This many bytes will
212 * be moved into the larger buffer.
214 protected void growPath(final int len) {
215 final byte[] n = new byte[path.length << 1];
216 System.arraycopy(path, 0, n, 0, len);
217 for (AbstractTreeIterator p = this; p != null; p = p.parent)
218 p.path = n;
222 * Compare the path of this current entry to another iterator's entry.
224 * @param p
225 * the other iterator to compare the path against.
226 * @return -1 if this entry sorts first; 0 if the entries are equal; 1 if
227 * p's entry sorts first.
229 public int pathCompare(final AbstractTreeIterator p) {
230 final byte[] a = path;
231 final byte[] b = p.path;
232 final int aLen = pathLen;
233 final int bLen = p.pathLen;
234 int cPos;
236 for (cPos = 0; cPos < aLen && cPos < bLen; cPos++) {
237 final int cmp = (a[cPos] & 0xff) - (b[cPos] & 0xff);
238 if (cmp != 0)
239 return cmp;
242 if (cPos < aLen) {
243 final int aj = a[cPos] & 0xff;
244 final int lastb = p.lastPathChar();
245 if (aj < lastb)
246 return -1;
247 else if (aj > lastb)
248 return 1;
249 else if (cPos == aLen - 1)
250 return 0;
251 else
252 return -1;
255 if (cPos < bLen) {
256 final int bk = b[cPos] & 0xff;
257 final int lasta = lastPathChar();
258 if (lasta < bk)
259 return -1;
260 else if (lasta > bk)
261 return 1;
262 else if (cPos == bLen - 1)
263 return 0;
264 else
265 return 1;
268 final int lasta = lastPathChar();
269 final int lastb = p.lastPathChar();
270 if (lasta < lastb)
271 return -1;
272 else if (lasta > lastb)
273 return 1;
275 if (aLen == bLen)
276 return 0;
277 else if (aLen < bLen)
278 return -1;
279 else
280 return 1;
283 private int lastPathChar() {
284 return FileMode.TREE.equals(mode) ? '/' : '\0';
288 * Check if the current entry of both iterators has the same id.
289 * <p>
290 * This method is faster than {@link #getEntryObjectId()} as it does not
291 * require copying the bytes out of the buffers. A direct {@link #idBuffer}
292 * compare operation is performed.
294 * @param otherIterator
295 * the other iterator to test against.
296 * @return true if both iterators have the same object id; false otherwise.
298 public boolean idEqual(final AbstractTreeIterator otherIterator) {
299 return ObjectId.equals(idBuffer(), idOffset(),
300 otherIterator.idBuffer(), otherIterator.idOffset());
304 * Get the object id of the current entry.
306 * @return an object id for the current entry.
308 public ObjectId getEntryObjectId() {
309 return ObjectId.fromRaw(idBuffer(), idOffset());
313 * Get the byte array buffer object IDs must be copied out of.
314 * <p>
315 * The id buffer contains the bytes necessary to construct an ObjectId for
316 * the current entry of this iterator. The buffer can be the same buffer for
317 * all entries, or it can be a unique buffer per-entry. Implementations are
318 * encouraged to expose their private buffer whenever possible to reduce
319 * garbage generation and copying costs.
321 * @return byte array the implementation stores object IDs within.
322 * @see #getEntryObjectId()
324 public abstract byte[] idBuffer();
327 * Get the position within {@link #idBuffer()} of this entry's ObjectId.
329 * @return offset into the array returned by {@link #idBuffer()} where the
330 * ObjectId must be copied out of.
332 public abstract int idOffset();
335 * Create a new iterator for the current entry's subtree.
336 * <p>
337 * The parent reference of the iterator must be <code>this</code>,
338 * otherwise the caller would not be able to exit out of the subtree
339 * iterator correctly and return to continue walking <code>this</code>.
341 * @param repo
342 * repository to load the tree data from.
343 * @return a new parser that walks over the current subtree.
344 * @throws IncorrectObjectTypeException
345 * the current entry is not actually a tree and cannot be parsed
346 * as though it were a tree.
347 * @throws IOException
348 * a loose object or pack file could not be read.
350 public abstract AbstractTreeIterator createSubtreeIterator(Repository repo)
351 throws IncorrectObjectTypeException, IOException;
354 * Is this tree iterator at its EOF point (no more entries)?
355 * <p>
356 * An iterator is at EOF if there is no current entry.
358 * @return true if we have walked all entries and have none left.
360 public abstract boolean eof();
363 * Advance to the next tree entry, populating this iterator with its data.
364 * <p>
365 * Implementations must populate the following members:
366 * <ul>
367 * <li>{@link #mode}</li>
368 * <li>{@link #path} (from {@link #pathOffset} to {@link #pathLen})</li>
369 * <li>{@link #pathLen}</li>
370 * </ul>
371 * as well as any implementation dependent information necessary to
372 * accurately return data from {@link #idBuffer()} and {@link #idOffset()}
373 * when demanded.
375 * @throws CorruptObjectException
376 * the tree is invalid.
378 public abstract void next() throws CorruptObjectException;
381 * Advance to the next tree entry, populating this iterator with its data.
382 * <p>
383 * This method behaves like {@link #next()} but is called by
384 * {@link TreeWalk} only if a {@link TreeFilter} was used and ruled out the
385 * current entry from the results. In such cases this tree iterator may
386 * perform special behavior.
388 * @throws CorruptObjectException
389 * the tree is invalid.
391 public void skip() throws CorruptObjectException {
392 next();
396 * Indicates to the iterator that no more entries will be read.
397 * <p>
398 * This is only invoked by TreeWalk when the iteration is aborted early due
399 * to a {@link org.spearce.jgit.errors.StopWalkException} being thrown from
400 * within a TreeFilter.
402 public void stopWalk() {
403 // Do nothing by default. Most iterators do not care.