2 * Copyright (C) 2008-2009, Google Inc.
3 * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
4 * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
5 * and other copyright owners as documented in the project's IP log.
7 * This program and the accompanying materials are made available
8 * under the terms of the Eclipse Distribution License v1.0 which
9 * accompanies this distribution, is reproduced below, and is
10 * available at http://www.eclipse.org/org/documents/edl-v10.php
12 * All rights reserved.
14 * Redistribution and use in source and binary forms, with or
15 * without modification, are permitted provided that the following
18 * - Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
21 * - Redistributions in binary form must reproduce the above
22 * copyright notice, this list of conditions and the following
23 * disclaimer in the documentation and/or other materials provided
24 * with the distribution.
26 * - Neither the name of the Eclipse Foundation, Inc. nor the
27 * names of its contributors may be used to endorse or promote
28 * products derived from this software without specific prior
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
32 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
33 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
34 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
36 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
37 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
38 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
39 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
40 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
43 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46 package org
.eclipse
.jgit
.treewalk
;
48 import java
.io
.IOException
;
49 import java
.nio
.ByteBuffer
;
50 import java
.nio
.CharBuffer
;
52 import org
.eclipse
.jgit
.errors
.CorruptObjectException
;
53 import org
.eclipse
.jgit
.errors
.IncorrectObjectTypeException
;
54 import org
.eclipse
.jgit
.lib
.Constants
;
55 import org
.eclipse
.jgit
.lib
.FileMode
;
56 import org
.eclipse
.jgit
.lib
.MutableObjectId
;
57 import org
.eclipse
.jgit
.lib
.ObjectId
;
58 import org
.eclipse
.jgit
.lib
.Repository
;
59 import org
.eclipse
.jgit
.lib
.WindowCursor
;
60 import org
.eclipse
.jgit
.treewalk
.filter
.TreeFilter
;
63 * Walks a Git tree (directory) in Git sort order.
65 * A new iterator instance should be positioned on the first entry, or at eof.
66 * Data for the first entry (if not at eof) should be available immediately.
68 * Implementors must walk a tree in the Git sort order, which has the following
76 * In the second item, <code>A</code> is the name of a subtree and
77 * <code>c</code> is a file within that subtree. The other two items are files
78 * in the root level tree.
80 * @see CanonicalTreeParser
82 public abstract class AbstractTreeIterator
{
83 /** Default size for the {@link #path} buffer. */
84 protected static final int DEFAULT_PATH_SIZE
= 128;
86 /** A dummy object id buffer that matches the zero ObjectId. */
87 protected static final byte[] zeroid
= new byte[Constants
.OBJECT_ID_LENGTH
];
89 /** Iterator for the parent tree; null if we are the root iterator. */
90 final AbstractTreeIterator parent
;
92 /** The iterator this current entry is path equal to. */
93 AbstractTreeIterator matches
;
96 * Number of entries we moved forward to force a D/F conflict match.
98 * @see NameConflictTreeWalk
103 * Mode bits for the current entry.
105 * A numerical value from FileMode is usually faster for an iterator to
106 * obtain from its data source so this is the preferred representation.
108 * @see org.eclipse.jgit.lib.FileMode
113 * Path buffer for the current entry.
115 * This buffer is pre-allocated at the start of walking and is shared from
116 * parent iterators down into their subtree iterators. The sharing allows
117 * the current entry to always be a full path from the root, while each
118 * subtree only needs to populate the part that is under their control.
120 protected byte[] path
;
123 * Position within {@link #path} this iterator starts writing at.
125 * This is the first offset in {@link #path} that this iterator must
126 * populate during {@link #next}. At the root level (when {@link #parent}
127 * is null) this is 0. For a subtree iterator the index before this position
128 * should have the value '/'.
130 protected final int pathOffset
;
133 * Total length of the current entry's complete path from the root.
135 * This is the number of bytes within {@link #path} that pertain to the
136 * current entry. Values at this index through the end of the array are
137 * garbage and may be randomly populated from prior entries.
139 protected int pathLen
;
141 /** Create a new iterator with no parent. */
142 protected AbstractTreeIterator() {
144 path
= new byte[DEFAULT_PATH_SIZE
];
149 * Create a new iterator with no parent and a prefix.
151 * The prefix path supplied is inserted in front of all paths generated by
152 * this iterator. It is intended to be used when an iterator is being
153 * created for a subsection of an overall repository and needs to be
154 * combined with other iterators that are created to run over the entire
155 * repository namespace.
158 * position of this iterator in the repository tree. The value
159 * may be null or the empty string to indicate the prefix is the
160 * root of the repository. A trailing slash ('/') is
161 * automatically appended if the prefix does not end in '/'.
163 protected AbstractTreeIterator(final String prefix
) {
166 if (prefix
!= null && prefix
.length() > 0) {
169 b
= Constants
.CHARSET
.encode(CharBuffer
.wrap(prefix
));
171 path
= new byte[Math
.max(DEFAULT_PATH_SIZE
, pathLen
+ 1)];
172 b
.get(path
, 0, pathLen
);
173 if (path
[pathLen
- 1] != '/')
174 path
[pathLen
++] = '/';
175 pathOffset
= pathLen
;
177 path
= new byte[DEFAULT_PATH_SIZE
];
183 * Create a new iterator with no parent and a prefix.
185 * The prefix path supplied is inserted in front of all paths generated by
186 * this iterator. It is intended to be used when an iterator is being
187 * created for a subsection of an overall repository and needs to be
188 * combined with other iterators that are created to run over the entire
189 * repository namespace.
192 * position of this iterator in the repository tree. The value
193 * may be null or the empty array to indicate the prefix is the
194 * root of the repository. A trailing slash ('/') is
195 * automatically appended if the prefix does not end in '/'.
197 protected AbstractTreeIterator(final byte[] prefix
) {
200 if (prefix
!= null && prefix
.length
> 0) {
201 pathLen
= prefix
.length
;
202 path
= new byte[Math
.max(DEFAULT_PATH_SIZE
, pathLen
+ 1)];
203 System
.arraycopy(prefix
, 0, path
, 0, pathLen
);
204 if (path
[pathLen
- 1] != '/')
205 path
[pathLen
++] = '/';
206 pathOffset
= pathLen
;
208 path
= new byte[DEFAULT_PATH_SIZE
];
214 * Create an iterator for a subtree of an existing iterator.
217 * parent tree iterator.
219 protected AbstractTreeIterator(final AbstractTreeIterator p
) {
222 pathOffset
= p
.pathLen
+ 1;
224 path
[pathOffset
- 1] = '/';
225 } catch (ArrayIndexOutOfBoundsException e
) {
227 path
[pathOffset
- 1] = '/';
232 * Create an iterator for a subtree of an existing iterator.
234 * The caller is responsible for setting up the path of the child iterator.
237 * parent tree iterator.
239 * path array to be used by the child iterator. This path must
240 * contain the path from the top of the walk to the first child
241 * and must end with a '/'.
242 * @param childPathOffset
243 * position within <code>childPath</code> where the child can
244 * insert its data. The value at
245 * <code>childPath[childPathOffset-1]</code> must be '/'.
247 protected AbstractTreeIterator(final AbstractTreeIterator p
,
248 final byte[] childPath
, final int childPathOffset
) {
251 pathOffset
= childPathOffset
;
255 * Grow the path buffer larger.
258 * number of live bytes in the path buffer. This many bytes will
259 * be moved into the larger buffer.
261 protected void growPath(final int len
) {
262 setPathCapacity(path
.length
<< 1, len
);
266 * Ensure that path is capable to hold at least {@code capacity} bytes
269 * the amount of bytes to hold
271 * the amount of live bytes in path buffer
273 protected void ensurePathCapacity(final int capacity
, final int len
) {
274 if (path
.length
>= capacity
)
276 final byte[] o
= path
;
277 int current
= o
.length
;
278 int newCapacity
= current
;
279 while (newCapacity
< capacity
&& newCapacity
> 0)
281 setPathCapacity(newCapacity
, len
);
285 * Set path buffer capacity to the specified size
290 * the amount of bytes to copy
292 private void setPathCapacity(int capacity
, int len
) {
293 final byte[] o
= path
;
294 final byte[] n
= new byte[capacity
];
295 System
.arraycopy(o
, 0, n
, 0, len
);
296 for (AbstractTreeIterator p
= this; p
!= null && p
.path
== o
; p
= p
.parent
)
301 * Compare the path of this current entry to another iterator's entry.
304 * the other iterator to compare the path against.
305 * @return -1 if this entry sorts first; 0 if the entries are equal; 1 if
306 * p's entry sorts first.
308 public int pathCompare(final AbstractTreeIterator p
) {
309 return pathCompare(p
, p
.mode
);
312 int pathCompare(final AbstractTreeIterator p
, final int pMode
) {
313 final byte[] a
= path
;
314 final byte[] b
= p
.path
;
315 final int aLen
= pathLen
;
316 final int bLen
= p
.pathLen
;
319 // Its common when we are a subtree for both parents to match;
320 // when this happens everything in path[0..cPos] is known to
321 // be equal and does not require evaluation again.
323 cPos
= alreadyMatch(this, p
);
325 for (; cPos
< aLen
&& cPos
< bLen
; cPos
++) {
326 final int cmp
= (a
[cPos
] & 0xff) - (b
[cPos
] & 0xff);
332 return (a
[cPos
] & 0xff) - lastPathChar(pMode
);
334 return lastPathChar(mode
) - (b
[cPos
] & 0xff);
335 return lastPathChar(mode
) - lastPathChar(pMode
);
338 private static int alreadyMatch(AbstractTreeIterator a
,
339 AbstractTreeIterator b
) {
341 final AbstractTreeIterator ap
= a
.parent
;
342 final AbstractTreeIterator bp
= b
.parent
;
343 if (ap
== null || bp
== null)
345 if (ap
.matches
== bp
.matches
)
352 private static int lastPathChar(final int mode
) {
353 return FileMode
.TREE
.equals(mode
) ?
'/' : '\0';
357 * Check if the current entry of both iterators has the same id.
359 * This method is faster than {@link #getEntryObjectId()} as it does not
360 * require copying the bytes out of the buffers. A direct {@link #idBuffer}
361 * compare operation is performed.
363 * @param otherIterator
364 * the other iterator to test against.
365 * @return true if both iterators have the same object id; false otherwise.
367 public boolean idEqual(final AbstractTreeIterator otherIterator
) {
368 return ObjectId
.equals(idBuffer(), idOffset(),
369 otherIterator
.idBuffer(), otherIterator
.idOffset());
373 * Get the object id of the current entry.
375 * @return an object id for the current entry.
377 public ObjectId
getEntryObjectId() {
378 return ObjectId
.fromRaw(idBuffer(), idOffset());
382 * Obtain the ObjectId for the current entry.
385 * buffer to copy the object id into.
387 public void getEntryObjectId(final MutableObjectId out
) {
388 out
.fromRaw(idBuffer(), idOffset());
391 /** @return the file mode of the current entry. */
392 public FileMode
getEntryFileMode() {
393 return FileMode
.fromBits(mode
);
396 /** @return the file mode of the current entry as bits */
397 public int getEntryRawMode() {
401 /** @return path of the current entry, as a string. */
402 public String
getEntryPathString() {
403 return TreeWalk
.pathOf(this);
407 * Get the byte array buffer object IDs must be copied out of.
409 * The id buffer contains the bytes necessary to construct an ObjectId for
410 * the current entry of this iterator. The buffer can be the same buffer for
411 * all entries, or it can be a unique buffer per-entry. Implementations are
412 * encouraged to expose their private buffer whenever possible to reduce
413 * garbage generation and copying costs.
415 * @return byte array the implementation stores object IDs within.
416 * @see #getEntryObjectId()
418 public abstract byte[] idBuffer();
421 * Get the position within {@link #idBuffer()} of this entry's ObjectId.
423 * @return offset into the array returned by {@link #idBuffer()} where the
424 * ObjectId must be copied out of.
426 public abstract int idOffset();
429 * Create a new iterator for the current entry's subtree.
431 * The parent reference of the iterator must be <code>this</code>,
432 * otherwise the caller would not be able to exit out of the subtree
433 * iterator correctly and return to continue walking <code>this</code>.
436 * repository to load the tree data from.
437 * @return a new parser that walks over the current subtree.
438 * @throws IncorrectObjectTypeException
439 * the current entry is not actually a tree and cannot be parsed
440 * as though it were a tree.
441 * @throws IOException
442 * a loose object or pack file could not be read.
444 public abstract AbstractTreeIterator
createSubtreeIterator(Repository repo
)
445 throws IncorrectObjectTypeException
, IOException
;
448 * Create a new iterator as though the current entry were a subtree.
450 * @return a new empty tree iterator.
452 public EmptyTreeIterator
createEmptyTreeIterator() {
453 return new EmptyTreeIterator(this);
457 * Create a new iterator for the current entry's subtree.
459 * The parent reference of the iterator must be <code>this</code>, otherwise
460 * the caller would not be able to exit out of the subtree iterator
461 * correctly and return to continue walking <code>this</code>.
464 * repository to load the tree data from.
466 * temporary ObjectId buffer for use by this method.
468 * window cursor to use during repository access.
469 * @return a new parser that walks over the current subtree.
470 * @throws IncorrectObjectTypeException
471 * the current entry is not actually a tree and cannot be parsed
472 * as though it were a tree.
473 * @throws IOException
474 * a loose object or pack file could not be read.
476 public AbstractTreeIterator
createSubtreeIterator(final Repository repo
,
477 final MutableObjectId idBuffer
, final WindowCursor curs
)
478 throws IncorrectObjectTypeException
, IOException
{
479 return createSubtreeIterator(repo
);
483 * Is this tree iterator positioned on its first entry?
485 * An iterator is positioned on the first entry if <code>back(1)</code>
486 * would be an invalid request as there is no entry before the current one.
488 * An empty iterator (one with no entries) will be
489 * <code>first() && eof()</code>.
491 * @return true if the iterator is positioned on the first entry.
493 public abstract boolean first();
496 * Is this tree iterator at its EOF point (no more entries)?
498 * An iterator is at EOF if there is no current entry.
500 * @return true if we have walked all entries and have none left.
502 public abstract boolean eof();
505 * Move to next entry, populating this iterator with the entry data.
507 * The delta indicates how many moves forward should occur. The most common
508 * delta is 1 to move to the next entry.
510 * Implementations must populate the following members:
512 * <li>{@link #mode}</li>
513 * <li>{@link #path} (from {@link #pathOffset} to {@link #pathLen})</li>
514 * <li>{@link #pathLen}</li>
516 * as well as any implementation dependent information necessary to
517 * accurately return data from {@link #idBuffer()} and {@link #idOffset()}
521 * number of entries to move the iterator by. Must be a positive,
523 * @throws CorruptObjectException
524 * the tree is invalid.
526 public abstract void next(int delta
) throws CorruptObjectException
;
529 * Move to prior entry, populating this iterator with the entry data.
531 * The delta indicates how many moves backward should occur.The most common
532 * delta is 1 to move to the prior entry.
534 * Implementations must populate the following members:
536 * <li>{@link #mode}</li>
537 * <li>{@link #path} (from {@link #pathOffset} to {@link #pathLen})</li>
538 * <li>{@link #pathLen}</li>
540 * as well as any implementation dependent information necessary to
541 * accurately return data from {@link #idBuffer()} and {@link #idOffset()}
545 * number of entries to move the iterator by. Must be a positive,
547 * @throws CorruptObjectException
548 * the tree is invalid.
550 public abstract void back(int delta
) throws CorruptObjectException
;
553 * Advance to the next tree entry, populating this iterator with its data.
555 * This method behaves like <code>seek(1)</code> but is called by
556 * {@link TreeWalk} only if a {@link TreeFilter} was used and ruled out the
557 * current entry from the results. In such cases this tree iterator may
558 * perform special behavior.
560 * @throws CorruptObjectException
561 * the tree is invalid.
563 public void skip() throws CorruptObjectException
{
568 * Indicates to the iterator that no more entries will be read.
570 * This is only invoked by TreeWalk when the iteration is aborted early due
571 * to a {@link org.eclipse.jgit.errors.StopWalkException} being thrown from
572 * within a TreeFilter.
574 public void stopWalk() {
575 // Do nothing by default. Most iterators do not care.
579 * @return the length of the name component of the path for the current entry
581 public int getNameLength() {
582 return pathLen
- pathOffset
;
586 * Get the name component of the current entry path into the provided buffer.
588 * @param buffer the buffer to get the name into, it is assumed that buffer can hold the name
589 * @param offset the offset of the name in the buffer
590 * @see #getNameLength()
592 public void getName(byte[] buffer
, int offset
) {
593 System
.arraycopy(path
, pathOffset
, buffer
, offset
, pathLen
- pathOffset
);