Merge "Add ObjectId getByte for random access"
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0001_ObjectId.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectIdTest.java
similarity index 89%
rename from org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0001_ObjectId.java
rename to org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectIdTest.java
index 03176cb..2eb1e6b9 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0001_ObjectId.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectIdTest.java
@@ -47,7 +47,7 @@
 
 import junit.framework.TestCase;
 
-public class T0001_ObjectId extends TestCase {
+public class ObjectIdTest extends TestCase {
 	public void test001_toString() {
 		final String x = "def4c620bc3713bb1bb26b808ec9312548e73946";
 		final ObjectId oid = ObjectId.fromString(x);
@@ -108,4 +108,18 @@ public void test011_toString() {
 		final ObjectId oid = ObjectId.fromString(x);
 		assertEquals(x.toLowerCase(), oid.name());
 	}
+
+	public void testGetByte() {
+		byte[] raw = new byte[20];
+		for (int i = 0; i < 20; i++)
+			raw[i] = (byte) (0xa0 + i);
+		ObjectId id = ObjectId.fromRaw(raw);
+
+		assertEquals(raw[0] & 0xff, id.getFirstByte());
+		assertEquals(raw[0] & 0xff, id.getByte(0));
+		assertEquals(raw[1] & 0xff, id.getByte(1));
+
+		for (int i = 2; i < 20; i++)
+			assertEquals("index " + i, raw[i] & 0xff, id.getByte(i));
+	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/AnyObjectId.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AnyObjectId.java
index 7b30cec..61cc15d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/AnyObjectId.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AnyObjectId.java
@@ -97,15 +97,61 @@ public static boolean equals(final AnyObjectId firstObjectId,
 	int w5;
 
 	/**
-	 * For ObjectIdMap
+	 * Get the first 8 bits of the ObjectId.
 	 *
-	 * @return a discriminator usable for a fan-out style map
+	 * This is a faster version of {@code getByte(0)}.
+	 *
+	 * @return a discriminator usable for a fan-out style map. Returned values
+	 *         are unsigned and thus are in the range [0,255] rather than the
+	 *         signed byte range of [-128, 127].
 	 */
 	public final int getFirstByte() {
 		return w1 >>> 24;
 	}
 
 	/**
+	 * Get any byte from the ObjectId.
+	 *
+	 * Callers hard-coding {@code getByte(0)} should instead use the much faster
+	 * special case variant {@link #getFirstByte()}.
+	 *
+	 * @param index
+	 *            index of the byte to obtain from the raw form of the ObjectId.
+	 *            Must be in range [0, {@link Constants#OBJECT_ID_LENGTH}).
+	 * @return the value of the requested byte at {@code index}. Returned values
+	 *         are unsigned and thus are in the range [0,255] rather than the
+	 *         signed byte range of [-128, 127].
+	 * @throws ArrayIndexOutOfBoundsException
+	 *             {@code index} is less than 0, equal to
+	 *             {@link Constants#OBJECT_ID_LENGTH}, or greater than
+	 *             {@link Constants#OBJECT_ID_LENGTH}.
+	 */
+	public final int getByte(int index) {
+		int w;
+		switch (index >> 2) {
+		case 0:
+			w = w1;
+			break;
+		case 1:
+			w = w2;
+			break;
+		case 2:
+			w = w3;
+			break;
+		case 3:
+			w = w4;
+			break;
+		case 4:
+			w = w5;
+			break;
+		default:
+			throw new ArrayIndexOutOfBoundsException(index);
+		}
+
+		return (w >>> (8 * (3 - (index & 3)))) & 0xff;
+	}
+
+	/**
 	 * Compare this ObjectId to another and obtain a sort ordering.
 	 *
 	 * @param other