Move WorkingTreeIterator inherited state into an object

Instead of copying up to 4 fields from the parent iterator each time a
child iterator is initialized and used, construct a single state
object that contains the 4 fields, and pass that one state object
through to the child.  This makes it easier to add additional state
fields that must be inherited, at the slight expense of an extra
object allocation per TreeWalk, and an extra level of field
indirection whenever the options, nameEncoder, or read buffer is
required by the iterator.

Change-Id: Ic4603c33b772d7a45f9c81140537d51945688fcb
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
This commit is contained in:
Shawn O. Pearce 2010-11-18 17:04:10 -08:00
parent 3de186fbf0
commit bd98a0a9a5
1 changed files with 40 additions and 37 deletions

View File

@ -90,7 +90,7 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
protected static final Entry[] EOF = {};
/** Size we perform file IO in if we have to read and hash a file. */
private static final int BUFFER_SIZE = 2048;
static final int BUFFER_SIZE = 2048;
/**
* Maximum size of files which may be read fully into memory for performance
@ -98,21 +98,15 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
*/
private static final long MAXIMUM_FILE_SIZE_TO_READ_FULLY = 65536;
/** Inherited state of this iterator, describing working tree, etc. */
private final IteratorState state;
/** The {@link #idBuffer()} for the current entry. */
private byte[] contentId;
/** Index within {@link #entries} that {@link #contentId} came from. */
private int contentIdFromPtr;
/** Buffer used to perform {@link #contentId} computations. */
private byte[] contentReadBuffer;
/** Digest computer for {@link #contentId} computations. */
private MessageDigest contentDigest;
/** File name character encoder. */
private final CharsetEncoder nameEncoder;
/** List of entries obtained from the subclass. */
private Entry[] entries;
@ -125,9 +119,6 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
/** If there is a .gitignore file present, the parsed rules from it. */
private IgnoreNode ignoreNode;
/** Options used to process the working tree. */
private final WorkingTreeOptions options;
/**
* Create a new iterator with no parent.
*
@ -136,8 +127,7 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
*/
protected WorkingTreeIterator(WorkingTreeOptions options) {
super();
nameEncoder = Constants.CHARSET.newEncoder();
this.options = options;
state = new IteratorState(options);
}
/**
@ -160,8 +150,7 @@ protected WorkingTreeIterator(WorkingTreeOptions options) {
protected WorkingTreeIterator(final String prefix,
WorkingTreeOptions options) {
super(prefix);
nameEncoder = Constants.CHARSET.newEncoder();
this.options = options;
state = new IteratorState(options);
}
/**
@ -172,8 +161,7 @@ protected WorkingTreeIterator(final String prefix,
*/
protected WorkingTreeIterator(final WorkingTreeIterator p) {
super(p);
nameEncoder = p.nameEncoder;
options = p.options;
state = p.state;
}
/**
@ -222,21 +210,6 @@ public byte[] idBuffer() {
return zeroid;
}
private void initializeDigestAndReadBuffer() {
if (contentDigest != null)
return;
if (parent == null) {
contentReadBuffer = new byte[BUFFER_SIZE];
contentDigest = Constants.newMessageDigest();
} else {
final WorkingTreeIterator p = (WorkingTreeIterator) parent;
p.initializeDigestAndReadBuffer();
contentReadBuffer = p.contentReadBuffer;
contentDigest = p.contentDigest;
}
}
private static final byte[] digits = { '0', '1', '2', '3', '4', '5', '6',
'7', '8', '9' };
@ -249,7 +222,7 @@ private byte[] idBufferBlob(final Entry e) {
if (is == null)
return zeroid;
try {
initializeDigestAndReadBuffer();
state.initializeDigestAndReadBuffer();
final long len = e.getLength();
if (!mightNeedCleaning(e))
@ -299,7 +272,7 @@ private static void safeClose(final InputStream in) {
}
private boolean mightNeedCleaning(Entry entry) {
switch (options.getAutoCRLF()) {
switch (getOptions().getAutoCRLF()) {
case FALSE:
default:
return false;
@ -339,7 +312,7 @@ private InputStream filterClean(Entry entry, InputStream in) {
* @return working tree options
*/
public WorkingTreeOptions getOptions() {
return options;
return state.options;
}
@Override
@ -520,6 +493,7 @@ protected void init(final Entry[] list) {
entries = list;
int i, o;
final CharsetEncoder nameEncoder = state.nameEncoder;
for (i = 0, o = 0; i < entries.length; i++) {
final Entry e = entries[i];
if (e == null)
@ -678,6 +652,9 @@ private long computeLength(InputStream in) throws IOException {
}
private byte[] computeHash(InputStream in, long length) throws IOException {
final MessageDigest contentDigest = state.contentDigest;
final byte[] contentReadBuffer = state.contentReadBuffer;
contentDigest.reset();
contentDigest.update(hblob);
contentDigest.update((byte) ' ');
@ -857,4 +834,30 @@ IgnoreNode load() throws IOException {
return r.getRules().isEmpty() ? null : r;
}
}
private static final class IteratorState {
/** Options used to process the working tree. */
final WorkingTreeOptions options;
/** File name character encoder. */
final CharsetEncoder nameEncoder;
/** Digest computer for {@link #contentId} computations. */
MessageDigest contentDigest;
/** Buffer used to perform {@link #contentId} computations. */
byte[] contentReadBuffer;
IteratorState(WorkingTreeOptions options) {
this.options = options;
this.nameEncoder = Constants.CHARSET.newEncoder();
}
void initializeDigestAndReadBuffer() {
if (contentDigest == null) {
contentDigest = Constants.newMessageDigest();
contentReadBuffer = new byte[BUFFER_SIZE];
}
}
}
}