[JGIT PATCH 1/3] Define an abstraction for handling abbreviated SHA-1 strings

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The AbbreviatedObjectId class parses an abbreviated SHA-1 string
into a binary format, permitting it to be more efficiently matched
against existing binary ObjectId fields.

Signed-off-by: Shawn O. Pearce <spearce@xxxxxxxxxxx>
---
 .../spearce/jgit/lib/AbbreviatedObjectIdTest.java  |  227 ++++++++++++++++++++
 .../org/spearce/jgit/lib/AbbreviatedObjectId.java  |  205 ++++++++++++++++++
 .../src/org/spearce/jgit/lib/AnyObjectId.java      |    2 +-
 3 files changed, 433 insertions(+), 1 deletions(-)
 create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/lib/AbbreviatedObjectIdTest.java
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java

diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/AbbreviatedObjectIdTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/AbbreviatedObjectIdTest.java
new file mode 100644
index 0000000..f540f49
--- /dev/null
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/AbbreviatedObjectIdTest.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.lib;
+
+import junit.framework.TestCase;
+
+public class AbbreviatedObjectIdTest extends TestCase {
+	public void testEmpty_FromByteArray() {
+		final AbbreviatedObjectId i;
+		i = AbbreviatedObjectId.fromString(new byte[] {}, 0, 0);
+		assertNotNull(i);
+		assertEquals(0, i.length());
+		assertFalse(i.isComplete());
+		assertEquals("", i.name());
+	}
+
+	public void testEmpty_FromString() {
+		final AbbreviatedObjectId i = AbbreviatedObjectId.fromString("");
+		assertNotNull(i);
+		assertEquals(0, i.length());
+		assertFalse(i.isComplete());
+		assertEquals("", i.name());
+	}
+
+	public void testFull_FromByteArray() {
+		final String s = "7b6e8067ec96acef9a4184b43210d583b6d2f99a";
+		final byte[] b = Constants.encodeASCII(s);
+		final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(b, 0,
+				b.length);
+		assertNotNull(i);
+		assertEquals(s.length(), i.length());
+		assertTrue(i.isComplete());
+		assertEquals(s, i.name());
+
+		final ObjectId f = i.toObjectId();
+		assertNotNull(f);
+		assertEquals(ObjectId.fromString(s), f);
+		assertEquals(f.hashCode(), i.hashCode());
+	}
+
+	public void testFull_FromString() {
+		final String s = "7b6e8067ec96acef9a4184b43210d583b6d2f99a";
+		final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);
+		assertNotNull(i);
+		assertEquals(s.length(), i.length());
+		assertTrue(i.isComplete());
+		assertEquals(s, i.name());
+
+		final ObjectId f = i.toObjectId();
+		assertNotNull(f);
+		assertEquals(ObjectId.fromString(s), f);
+		assertEquals(f.hashCode(), i.hashCode());
+	}
+
+	public void test1_FromString() {
+		final String s = "7";
+		final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);
+		assertNotNull(i);
+		assertEquals(s.length(), i.length());
+		assertFalse(i.isComplete());
+		assertEquals(s, i.name());
+		assertNull(i.toObjectId());
+	}
+
+	public void test2_FromString() {
+		final String s = "7b";
+		final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);
+		assertNotNull(i);
+		assertEquals(s.length(), i.length());
+		assertFalse(i.isComplete());
+		assertEquals(s, i.name());
+		assertNull(i.toObjectId());
+	}
+
+	public void test3_FromString() {
+		final String s = "7b6";
+		final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);
+		assertNotNull(i);
+		assertEquals(s.length(), i.length());
+		assertFalse(i.isComplete());
+		assertEquals(s, i.name());
+		assertNull(i.toObjectId());
+	}
+
+	public void test4_FromString() {
+		final String s = "7b6e";
+		final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);
+		assertNotNull(i);
+		assertEquals(s.length(), i.length());
+		assertFalse(i.isComplete());
+		assertEquals(s, i.name());
+		assertNull(i.toObjectId());
+	}
+
+	public void test5_FromString() {
+		final String s = "7b6e8";
+		final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);
+		assertNotNull(i);
+		assertEquals(s.length(), i.length());
+		assertFalse(i.isComplete());
+		assertEquals(s, i.name());
+		assertNull(i.toObjectId());
+	}
+
+	public void test6_FromString() {
+		final String s = "7b6e80";
+		final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);
+		assertNotNull(i);
+		assertEquals(s.length(), i.length());
+		assertFalse(i.isComplete());
+		assertEquals(s, i.name());
+		assertNull(i.toObjectId());
+	}
+
+	public void test7_FromString() {
+		final String s = "7b6e806";
+		final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);
+		assertNotNull(i);
+		assertEquals(s.length(), i.length());
+		assertFalse(i.isComplete());
+		assertEquals(s, i.name());
+		assertNull(i.toObjectId());
+	}
+
+	public void test8_FromString() {
+		final String s = "7b6e8067";
+		final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);
+		assertNotNull(i);
+		assertEquals(s.length(), i.length());
+		assertFalse(i.isComplete());
+		assertEquals(s, i.name());
+		assertNull(i.toObjectId());
+	}
+
+	public void test9_FromString() {
+		final String s = "7b6e8067e";
+		final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);
+		assertNotNull(i);
+		assertEquals(s.length(), i.length());
+		assertFalse(i.isComplete());
+		assertEquals(s, i.name());
+		assertNull(i.toObjectId());
+	}
+
+	public void test17_FromString() {
+		final String s = "7b6e8067ec96acef9";
+		final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);
+		assertNotNull(i);
+		assertEquals(s.length(), i.length());
+		assertFalse(i.isComplete());
+		assertEquals(s, i.name());
+		assertNull(i.toObjectId());
+	}
+
+	public void testEquals_Short() {
+		final String s = "7b6e8067";
+		final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(s);
+		final AbbreviatedObjectId b = AbbreviatedObjectId.fromString(s);
+		assertNotSame(a, b);
+		assertTrue(a.hashCode() == b.hashCode());
+		assertTrue(a.equals(b));
+		assertTrue(b.equals(a));
+	}
+
+	public void testEquals_Full() {
+		final String s = "7b6e8067ec96acef9a4184b43210d583b6d2f99a";
+		final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(s);
+		final AbbreviatedObjectId b = AbbreviatedObjectId.fromString(s);
+		assertNotSame(a, b);
+		assertTrue(a.hashCode() == b.hashCode());
+		assertTrue(a.equals(b));
+		assertTrue(b.equals(a));
+	}
+
+	public void testNotEquals_SameLength() {
+		final String sa = "7b6e8067";
+		final String sb = "7b6e806e";
+		final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(sa);
+		final AbbreviatedObjectId b = AbbreviatedObjectId.fromString(sb);
+		assertFalse(a.equals(b));
+		assertFalse(b.equals(a));
+	}
+
+	public void testNotEquals_DiffLength() {
+		final String sa = "7b6e8067abcd";
+		final String sb = "7b6e8067";
+		final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(sa);
+		final AbbreviatedObjectId b = AbbreviatedObjectId.fromString(sb);
+		assertFalse(a.equals(b));
+		assertFalse(b.equals(a));
+	}
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java b/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java
new file mode 100644
index 0000000..1a8d296
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.lib;
+
+import java.io.UnsupportedEncodingException;
+
+/**
+ * A prefix abbreviation of an {@link ObjectId}.
+ * <p>
+ * Sometimes Git produces abbreviated SHA-1 strings, using sufficient leading
+ * digits from the ObjectId name to still be unique within the repository the
+ * string was generated from. These ids are likely to be unique for a useful
+ * period of time, especially if they contain at least 6-10 hex digits.
+ * <p>
+ * This class converts the hex string into a binary form, to make it more
+ * efficient for matching against an object.
+ */
+public class AbbreviatedObjectId {
+	/**
+	 * Convert an AbbreviatedObjectId from hex characters (US-ASCII).
+	 * 
+	 * @param buf
+	 *            the US-ASCII buffer to read from.
+	 * @param offset
+	 *            position to read the first character from.
+	 * @param end
+	 *            one past the last position to read (<code>end-offset</code> is
+	 *            the length of the string).
+	 * @return the converted object id.
+	 */
+	public static final AbbreviatedObjectId fromString(final byte[] buf,
+			final int offset, final int end) {
+		if (end - offset > AnyObjectId.STR_LEN)
+			throw new IllegalArgumentException("Invalid id");
+		return fromHexString(buf, offset, end);
+	}
+
+	/**
+	 * Convert an AbbreviatedObjectId from hex characters.
+	 * 
+	 * @param str
+	 *            the string to read from. Must be &lt;= 40 characters.
+	 * @return the converted object id.
+	 */
+	public static final AbbreviatedObjectId fromString(final String str) {
+		if (str.length() > AnyObjectId.STR_LEN)
+			throw new IllegalArgumentException("Invalid id: " + str);
+		final byte[] b = Constants.encodeASCII(str);
+		return fromHexString(b, 0, b.length);
+	}
+
+	private static final AbbreviatedObjectId fromHexString(final byte[] bs,
+			int ptr, final int end) {
+		try {
+			final int a = hexUInt32(bs, ptr, end);
+			final int b = hexUInt32(bs, ptr + 8, end);
+			final int c = hexUInt32(bs, ptr + 16, end);
+			final int d = hexUInt32(bs, ptr + 24, end);
+			final int e = hexUInt32(bs, ptr + 32, end);
+			return new AbbreviatedObjectId(end - ptr, a, b, c, d, e);
+		} catch (ArrayIndexOutOfBoundsException e1) {
+			try {
+				final String str = new String(bs, ptr, end - ptr, "US-ASCII");
+				throw new IllegalArgumentException("Invalid id: " + str);
+			} catch (UnsupportedEncodingException e2) {
+				throw new IllegalArgumentException("Invalid id");
+			}
+		}
+	}
+
+	private static final int hexUInt32(final byte[] bs, int p, final int end) {
+		if (8 <= end - p)
+			return AnyObjectId.hexUInt32(bs, p);
+
+		int r = 0, n = 0;
+		while (n < 8 && p < end) {
+			final int v = AnyObjectId.fromhex[bs[p++]];
+			if (v < 0)
+				throw new ArrayIndexOutOfBoundsException();
+			r <<= 4;
+			r |= v;
+			n++;
+		}
+		return r << (8 - n) * 4;
+	}
+
+	/** Number of half-bytes used by this id. */
+	final int nibbles;
+
+	final int w1;
+
+	final int w2;
+
+	final int w3;
+
+	final int w4;
+
+	final int w5;
+
+	private AbbreviatedObjectId(final int n, final int new_1, final int new_2,
+			final int new_3, final int new_4, final int new_5) {
+		nibbles = n;
+		w1 = new_1;
+		w2 = new_2;
+		w3 = new_3;
+		w4 = new_4;
+		w5 = new_5;
+	}
+
+	/** @return number of hex digits appearing in this id */
+	public int length() {
+		return nibbles;
+	}
+
+	/** @return true if this ObjectId is actually a complete id. */
+	public boolean isComplete() {
+		return length() == AnyObjectId.RAW_LEN * 2;
+	}
+
+	/** @return a complete ObjectId; null if {@link #isComplete()} is false */
+	public ObjectId toObjectId() {
+		return isComplete() ? new ObjectId(w1, w2, w3, w4, w5) : null;
+	}
+
+	@Override
+	public int hashCode() {
+		return w2;
+	}
+
+	@Override
+	public boolean equals(final Object o) {
+		if (o instanceof AbbreviatedObjectId) {
+			final AbbreviatedObjectId b = (AbbreviatedObjectId) o;
+			return nibbles == b.nibbles && w1 == b.w1 && w2 == b.w2
+					&& w3 == b.w3 && w4 == b.w4 && w5 == b.w5;
+		}
+		return false;
+	}
+
+	/**
+	 * @return string form of the abbreviation, in lower case hexadecimal.
+	 */
+	public final String name() {
+		final char[] b = new char[AnyObjectId.STR_LEN];
+
+		AnyObjectId.formatHexChar(b, 0, w1);
+		if (nibbles <= 8)
+			return new String(b, 0, nibbles);
+
+		AnyObjectId.formatHexChar(b, 8, w2);
+		if (nibbles <= 16)
+			return new String(b, 0, nibbles);
+
+		AnyObjectId.formatHexChar(b, 16, w3);
+		if (nibbles <= 24)
+			return new String(b, 0, nibbles);
+
+		AnyObjectId.formatHexChar(b, 24, w4);
+		if (nibbles <= 32)
+			return new String(b, 0, nibbles);
+
+		AnyObjectId.formatHexChar(b, 32, w5);
+		return new String(b, 0, nibbles);
+	}
+
+	@Override
+	public String toString() {
+		return "AbbreviatedObjectId[" + name() + "]";
+	}
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java b/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java
index a534202..e88e09d 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java
@@ -396,7 +396,7 @@ private void toHexCharArray(final char[] dst) {
 	private static final char[] hexchar = { '0', '1', '2', '3', '4', '5', '6',
 			'7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
 
-	private static void formatHexChar(final char[] dst, final int p, int w) {
+	static void formatHexChar(final char[] dst, final int p, int w) {
 		int o = p + 7;
 		while (o >= p && w != 0) {
 			dst[o--] = hexchar[w & 0xf];
-- 
1.6.1.rc2.299.gead4c

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux