git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [JGIT PATCH 0/3] Introduce AbbreviatedObjectId
@ 2008-12-10 23:18 Shawn O. Pearce
  2008-12-10 23:18 ` [JGIT PATCH 1/3] Define an abstraction for handling abbreviated SHA-1 strings Shawn O. Pearce
  0 siblings, 1 reply; 4+ messages in thread
From: Shawn O. Pearce @ 2008-12-10 23:18 UTC (permalink / raw)
  To: Robin Rosenberg; +Cc: git

I'm using this new type to handle the "index" line of a git patch
file, where object ids are generally shorter than 40 characters
and thus aren't parsable by ObjectId.

Reading the short id is important because we can validate that a
patch applies correctly by computing the SHA-1 of the result and
testing it against the abbreviated id read in the "index" line.
If the base object SHA-1 matches the abbreviated line then the
result of applying the patch must also match; if it doesn't the
patch application logic is broken.

Shawn O. Pearce (3):
  Define an abstraction for handling abbreviated SHA-1 strings
  Add ObjectId.startsWith(AbbreviatedObjectId)
  Change AnyObjectId.abbreviate() to return AbbreviatedObjectId

 .../ui/internal/components/RefContentProposal.java |    2 +-
 .../egit/ui/internal/fetch/FetchResultTable.java   |   12 +-
 .../egit/ui/internal/push/PushResultTable.java     |   21 +-
 .../src/org/spearce/jgit/pgm/Branch.java           |    2 +-
 .../src/org/spearce/jgit/pgm/Fetch.java            |    8 +-
 .../src/org/spearce/jgit/pgm/Push.java             |    5 +-
 .../spearce/jgit/lib/AbbreviatedObjectIdTest.java  |  285 ++++++++++++++++++++
 .../org/spearce/jgit/lib/AbbreviatedObjectId.java  |  262 ++++++++++++++++++
 .../src/org/spearce/jgit/lib/AnyObjectId.java      |   39 +++-
 9 files changed, 608 insertions(+), 28 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

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [JGIT PATCH 1/3] Define an abstraction for handling abbreviated SHA-1 strings
  2008-12-10 23:18 [JGIT PATCH 0/3] Introduce AbbreviatedObjectId Shawn O. Pearce
@ 2008-12-10 23:18 ` Shawn O. Pearce
  2008-12-10 23:18   ` [JGIT PATCH 2/3] Add ObjectId.startsWith(AbbreviatedObjectId) Shawn O. Pearce
  0 siblings, 1 reply; 4+ messages in thread
From: Shawn O. Pearce @ 2008-12-10 23:18 UTC (permalink / raw)
  To: Robin Rosenberg; +Cc: git

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@spearce.org>
---
 .../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

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [JGIT PATCH 2/3] Add ObjectId.startsWith(AbbreviatedObjectId)
  2008-12-10 23:18 ` [JGIT PATCH 1/3] Define an abstraction for handling abbreviated SHA-1 strings Shawn O. Pearce
@ 2008-12-10 23:18   ` Shawn O. Pearce
  2008-12-10 23:18     ` [JGIT PATCH 3/3] Change AnyObjectId.abbreviate() to return AbbreviatedObjectId Shawn O. Pearce
  0 siblings, 1 reply; 4+ messages in thread
From: Shawn O. Pearce @ 2008-12-10 23:18 UTC (permalink / raw)
  To: Robin Rosenberg; +Cc: git

This test can be useful to determine if the object id at least
begins with an abbreviated id.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
 .../spearce/jgit/lib/AbbreviatedObjectIdTest.java  |   58 ++++++++++++++++++++
 .../org/spearce/jgit/lib/AbbreviatedObjectId.java  |   57 +++++++++++++++++++
 .../src/org/spearce/jgit/lib/AnyObjectId.java      |   11 ++++
 3 files changed, 126 insertions(+), 0 deletions(-)

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
index f540f49..3f82d50 100644
--- a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/AbbreviatedObjectIdTest.java
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/AbbreviatedObjectIdTest.java
@@ -224,4 +224,62 @@ public void testNotEquals_DiffLength() {
 		assertFalse(a.equals(b));
 		assertFalse(b.equals(a));
 	}
+
+	public void testPrefixCompare_Full() {
+		final String s1 = "7b6e8067ec96acef9a4184b43210d583b6d2f99a";
+		final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(s1);
+		final ObjectId i1 = ObjectId.fromString(s1);
+		assertEquals(0, a.prefixCompare(i1));
+		assertTrue(i1.startsWith(a));
+
+		final String s2 = "7b6e8067ec96acef9a4184b43210d583b6d2f99b";
+		final ObjectId i2 = ObjectId.fromString(s2);
+		assertTrue(a.prefixCompare(i2) < 0);
+		assertFalse(i2.startsWith(a));
+
+		final String s3 = "7b6e8067ec96acef9a4184b43210d583b6d2f999";
+		final ObjectId i3 = ObjectId.fromString(s3);
+		assertTrue(a.prefixCompare(i3) > 0);
+		assertFalse(i3.startsWith(a));
+	}
+
+	public void testPrefixCompare_1() {
+		final String sa = "7";
+		final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(sa);
+
+		final String s1 = "7b6e8067ec96acef9a4184b43210d583b6d2f99a";
+		final ObjectId i1 = ObjectId.fromString(s1);
+		assertEquals(0, a.prefixCompare(i1));
+		assertTrue(i1.startsWith(a));
+
+		final String s2 = "8b6e8067ec96acef9a4184b43210d583b6d2f99a";
+		final ObjectId i2 = ObjectId.fromString(s2);
+		assertTrue(a.prefixCompare(i2) < 0);
+		assertFalse(i2.startsWith(a));
+
+		final String s3 = "6b6e8067ec96acef9a4184b43210d583b6d2f99a";
+		final ObjectId i3 = ObjectId.fromString(s3);
+		assertTrue(a.prefixCompare(i3) > 0);
+		assertFalse(i3.startsWith(a));
+	}
+
+	public void testPrefixCompare_17() {
+		final String sa = "7b6e8067ec96acef9";
+		final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(sa);
+
+		final String s1 = "7b6e8067ec96acef9a4184b43210d583b6d2f99a";
+		final ObjectId i1 = ObjectId.fromString(s1);
+		assertEquals(0, a.prefixCompare(i1));
+		assertTrue(i1.startsWith(a));
+
+		final String s2 = "7b6e8067eca6acef9a4184b43210d583b6d2f99a";
+		final ObjectId i2 = ObjectId.fromString(s2);
+		assertTrue(a.prefixCompare(i2) < 0);
+		assertFalse(i2.startsWith(a));
+
+		final String s3 = "7b6e8067ec86acef9a4184b43210d583b6d2f99a";
+		final ObjectId i3 = ObjectId.fromString(s3);
+		assertTrue(a.prefixCompare(i3) > 0);
+		assertFalse(i3.startsWith(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
index 1a8d296..206cc2f 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java
@@ -39,6 +39,8 @@
 
 import java.io.UnsupportedEncodingException;
 
+import org.spearce.jgit.util.NB;
+
 /**
  * A prefix abbreviation of an {@link ObjectId}.
  * <p>
@@ -119,6 +121,24 @@ private static final int hexUInt32(final byte[] bs, int p, final int end) {
 		return r << (8 - n) * 4;
 	}
 
+	static int mask(final int nibbles, final int word, final int v) {
+		final int b = (word - 1) * 8;
+		if (b + 8 <= nibbles) {
+			// We have all of the bits required for this word.
+			//
+			return v;
+		}
+
+		if (nibbles < b) {
+			// We have none of the bits required for this word.
+			//
+			return 0;
+		}
+
+		final int s = 32 - (nibbles - b) * 4;
+		return (v >>> s) << s;
+	}
+
 	/** Number of half-bytes used by this id. */
 	final int nibbles;
 
@@ -157,6 +177,43 @@ public ObjectId toObjectId() {
 		return isComplete() ? new ObjectId(w1, w2, w3, w4, w5) : null;
 	}
 
+	/**
+	 * Compares this abbreviation to a full object id.
+	 * 
+	 * @param other
+	 *            the other object id.
+	 * @return &lt;0 if this abbreviation names an object that is less than
+	 *         <code>other</code>; 0 if this abbreviation exactly matches the
+	 *         first {@link #length()} digits of <code>other.name()</code>;
+	 *         &gt;0 if this abbreviation names an object that is after
+	 *         <code>other</code>.
+	 */
+	public int prefixCompare(final AnyObjectId other) {
+		int cmp;
+
+		cmp = NB.compareUInt32(w1, mask(1, other.w1));
+		if (cmp != 0)
+			return cmp;
+
+		cmp = NB.compareUInt32(w2, mask(2, other.w2));
+		if (cmp != 0)
+			return cmp;
+
+		cmp = NB.compareUInt32(w3, mask(3, other.w3));
+		if (cmp != 0)
+			return cmp;
+
+		cmp = NB.compareUInt32(w4, mask(4, other.w4));
+		if (cmp != 0)
+			return cmp;
+
+		return NB.compareUInt32(w5, mask(5, other.w5));
+	}
+
+	private int mask(final int word, final int v) {
+		return mask(nibbles, word, v);
+	}
+
 	@Override
 	public int hashCode() {
 		return w2;
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 e88e09d..8872017 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java
@@ -226,6 +226,17 @@ int compareTo(final int[] bs, final int p) {
 		return NB.compareUInt32(w5, bs[p + 4]);
 	}
 
+	/**
+	 * Tests if this ObjectId starts with the given abbreviation.
+	 * 
+	 * @param abbr
+	 *            the abbreviation.
+	 * @return true if this ObjectId begins with the abbreviation; else false.
+	 */
+	public boolean startsWith(final AbbreviatedObjectId abbr) {
+		return abbr.prefixCompare(this) == 0;
+	}
+
 	public int hashCode() {
 		return w2;
 	}
-- 
1.6.1.rc2.299.gead4c

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [JGIT PATCH 3/3] Change AnyObjectId.abbreviate() to return AbbreviatedObjectId
  2008-12-10 23:18   ` [JGIT PATCH 2/3] Add ObjectId.startsWith(AbbreviatedObjectId) Shawn O. Pearce
@ 2008-12-10 23:18     ` Shawn O. Pearce
  0 siblings, 0 replies; 4+ messages in thread
From: Shawn O. Pearce @ 2008-12-10 23:18 UTC (permalink / raw)
  To: Robin Rosenberg; +Cc: git

By returning our abstraction type we can reuse the logic inside
AbbreviatedObjectId to format the abbreviated string.  A result
can also be used to test against another ObjectId.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
 .../ui/internal/components/RefContentProposal.java |    2 +-
 .../egit/ui/internal/fetch/FetchResultTable.java   |   12 ++++----
 .../egit/ui/internal/push/PushResultTable.java     |   21 ++++++++-------
 .../src/org/spearce/jgit/pgm/Branch.java           |    2 +-
 .../src/org/spearce/jgit/pgm/Fetch.java            |    8 +++---
 .../src/org/spearce/jgit/pgm/Push.java             |    5 ++-
 .../org/spearce/jgit/lib/AbbreviatedObjectId.java  |    4 +-
 .../src/org/spearce/jgit/lib/AnyObjectId.java      |   26 +++++++++++++++++--
 8 files changed, 51 insertions(+), 29 deletions(-)

diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/components/RefContentProposal.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/components/RefContentProposal.java
index 60abaf3..b63c428 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/components/RefContentProposal.java
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/components/RefContentProposal.java
@@ -111,7 +111,7 @@ public String getDescription() {
 		final StringBuilder sb = new StringBuilder();
 		sb.append(refName);
 		sb.append('\n');
-		sb.append(objectId.abbreviate(db));
+		sb.append(objectId.abbreviate(db).name());
 		sb.append(" - ");
 		if (obj instanceof Commit) {
 			final Commit c = ((Commit) obj);
diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/fetch/FetchResultTable.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/fetch/FetchResultTable.java
index 868ca94..f1169d1 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/fetch/FetchResultTable.java
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/fetch/FetchResultTable.java
@@ -137,15 +137,15 @@ else if (tru.getLocalName().startsWith(Constants.R_TAGS))
 				}
 
 				if (r == RefUpdate.Result.FORCED) {
-					final String aOld = tru.getOldObjectId().abbreviate(db);
-					final String aNew = tru.getNewObjectId().abbreviate(db);
-					return aOld + "..." + aNew; //$NON-NLS-1$
+					final String o = tru.getOldObjectId().abbreviate(db).name();
+					final String n = tru.getNewObjectId().abbreviate(db).name();
+					return o + "..." + n; //$NON-NLS-1$
 				}
 
 				if (r == RefUpdate.Result.FAST_FORWARD) {
-					final String aOld = tru.getOldObjectId().abbreviate(db);
-					final String aNew = tru.getNewObjectId().abbreviate(db);
-					return aOld + ".." + aNew; //$NON-NLS-1$
+					final String o = tru.getOldObjectId().abbreviate(db).name();
+					final String n = tru.getNewObjectId().abbreviate(db).name();
+					return o + ".." + n; //$NON-NLS-1$
 				}
 
 				if (r == RefUpdate.Result.REJECTED)
diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/push/PushResultTable.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/push/PushResultTable.java
index c5e476b..6f460dc 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/push/PushResultTable.java
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/push/PushResultTable.java
@@ -233,9 +233,9 @@ public String getText(Object element) {
 					return UIText.PushResultTable_statusOkNewBranch;
 				}
 
-				return oldRef.getObjectId().abbreviate(localDb)
+				return oldRef.getObjectId().abbreviate(localDb).name()
 						+ (rru.isFastForward() ? ".." : "...")
-						+ rru.getNewObjectId().abbreviate(localDb);
+						+ rru.getNewObjectId().abbreviate(localDb).name();
 			case UP_TO_DATE:
 				return UIText.PushResultTable_statusUpToDate;
 			case NON_EXISTING:
@@ -289,7 +289,7 @@ public String getToolTipText(Object element) {
 			case OK:
 				if (rru.isDelete())
 					return NLS.bind(UIText.PushResultTable_statusDetailDeleted,
-							oldRef.getObjectId().abbreviate(localDb));
+							oldRef.getObjectId().abbreviate(localDb).name());
 				if (oldRef == null)
 					return null;
 				if (rru.isFastForward())
@@ -305,20 +305,21 @@ public String getToolTipText(Object element) {
 				return UIText.PushResultTable_statusDetailNonFastForward;
 			case REJECTED_REMOTE_CHANGED:
 				final Ref remoteRef = oldRef;
-				final String currentValue;
+				final String curVal;
 				if (remoteRef == null)
-					currentValue = UIText.PushResultTable_refNonExisting;
+					curVal = UIText.PushResultTable_refNonExisting;
 				else
-					currentValue = remoteRef.getObjectId().abbreviate(localDb);
+					curVal = remoteRef.getObjectId().abbreviate(localDb).name();
+
 				final ObjectId expectedOldObjectId = rru
 						.getExpectedOldObjectId();
-				final String expectedValue;
+				final String expVal;
 				if (expectedOldObjectId.equals(ObjectId.zeroId()))
-					expectedValue = UIText.PushResultTable_refNonExisting;
+					expVal = UIText.PushResultTable_refNonExisting;
 				else
-					expectedValue = expectedOldObjectId.abbreviate(localDb);
+					expVal = expectedOldObjectId.abbreviate(localDb).name();
 				return NLS.bind(UIText.PushResultTable_statusDetailChanged,
-						currentValue, expectedValue);
+						curVal, expVal);
 			case REJECTED_OTHER_REASON:
 				return rru.getMessage();
 			default:
diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Branch.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Branch.java
index db0aab8..11002f0 100644
--- a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Branch.java
+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Branch.java
@@ -167,7 +167,7 @@ private void printHead(final String ref, final boolean isCurrent,
 			final int spaces = maxNameLength - ref.length() + 1;
 			out.print(String.format("%" + spaces + "s", ""));
 			final ObjectId objectId = refObj.getObjectId();
-			out.print(objectId.abbreviate(db));
+			out.print(objectId.abbreviate(db).name());
 			out.print(' ');
 			out.print(rw.parseCommit(objectId).getShortMessage());
 		}
diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Fetch.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Fetch.java
index ad7e08f..e9d3260 100644
--- a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Fetch.java
+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Fetch.java
@@ -131,14 +131,14 @@ else if (u.getLocalName().startsWith(Constants.R_TAGS))
 		}
 
 		if (r == RefUpdate.Result.FORCED) {
-			final String aOld = u.getOldObjectId().abbreviate(db);
-			final String aNew = u.getNewObjectId().abbreviate(db);
+			final String aOld = u.getOldObjectId().abbreviate(db).name();
+			final String aNew = u.getNewObjectId().abbreviate(db).name();
 			return aOld + "..." + aNew;
 		}
 
 		if (r == RefUpdate.Result.FAST_FORWARD) {
-			final String aOld = u.getOldObjectId().abbreviate(db);
-			final String aNew = u.getNewObjectId().abbreviate(db);
+			final String aOld = u.getOldObjectId().abbreviate(db).name();
+			final String aNew = u.getNewObjectId().abbreviate(db).name();
 			return aOld + ".." + aNew;
 		}
 
diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Push.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Push.java
index 53ad080..19d31a1 100644
--- a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Push.java
+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Push.java
@@ -181,8 +181,9 @@ private void printRefUpdateResult(final URIish uri,
 					boolean fastForward = rru.isFastForward();
 					final char flag = fastForward ? ' ' : '+';
 					final String summary = oldRef.getObjectId().abbreviate(db)
+							.name()
 							+ (fastForward ? ".." : "...")
-							+ rru.getNewObjectId().abbreviate(db);
+							+ rru.getNewObjectId().abbreviate(db).name();
 					final String message = fastForward ? null : "forced update";
 					printUpdateLine(flag, summary, srcRef, remoteName, message);
 				}
@@ -205,7 +206,7 @@ printUpdateLine('!', "[rejected]", srcRef, remoteName,
 
 		case REJECTED_REMOTE_CHANGED:
 			final String message = "remote ref object changed - is not expected one "
-					+ rru.getExpectedOldObjectId().abbreviate(db);
+					+ rru.getExpectedOldObjectId().abbreviate(db).name();
 			printUpdateLine('!', "[rejected]", srcRef, remoteName, message);
 			break;
 
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java b/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java
index 206cc2f..33b62b9 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java
@@ -52,7 +52,7 @@
  * This class converts the hex string into a binary form, to make it more
  * efficient for matching against an object.
  */
-public class AbbreviatedObjectId {
+public final class AbbreviatedObjectId {
 	/**
 	 * Convert an AbbreviatedObjectId from hex characters (US-ASCII).
 	 * 
@@ -152,7 +152,7 @@ static int mask(final int nibbles, final int word, final int v) {
 
 	final int w5;
 
-	private AbbreviatedObjectId(final int n, final int new_1, final int new_2,
+	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;
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 8872017..7d7d61b 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java
@@ -432,16 +432,36 @@ public final String name() {
 	/**
 	 * Return unique abbreviation (prefix) of this object SHA-1.
 	 * <p>
+	 * This method is a utility for <code>abbreviate(repo, 8)</code>.
+	 * 
+	 * @param repo
+	 *            repository for checking uniqueness within.
+	 * @return SHA-1 abbreviation.
+	 */
+	public AbbreviatedObjectId abbreviate(final Repository repo) {
+		return abbreviate(repo, 8);
+	}
+
+	/**
+	 * Return unique abbreviation (prefix) of this object SHA-1.
+	 * <p>
 	 * Current implementation is not guaranteeing uniqueness, it just returns
 	 * fixed-length prefix of SHA-1 string.
-	 *
+	 * 
 	 * @param repo
 	 *            repository for checking uniqueness within.
+	 * @param len
+	 *            minimum length of the abbreviated string.
 	 * @return SHA-1 abbreviation.
 	 */
-	public String abbreviate(final Repository repo) {
+	public AbbreviatedObjectId abbreviate(final Repository repo, final int len) {
 		// TODO implement checking for uniqueness
-		return name().substring(0, 7);
+		final int a = AbbreviatedObjectId.mask(len, 1, w1);
+		final int b = AbbreviatedObjectId.mask(len, 2, w2);
+		final int c = AbbreviatedObjectId.mask(len, 3, w3);
+		final int d = AbbreviatedObjectId.mask(len, 4, w4);
+		final int e = AbbreviatedObjectId.mask(len, 5, w5);
+		return new AbbreviatedObjectId(len, a, b, c, d, e);
 	}
 
 	/**
-- 
1.6.1.rc2.299.gead4c

^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2008-12-10 23:20 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-12-10 23:18 [JGIT PATCH 0/3] Introduce AbbreviatedObjectId Shawn O. Pearce
2008-12-10 23:18 ` [JGIT PATCH 1/3] Define an abstraction for handling abbreviated SHA-1 strings Shawn O. Pearce
2008-12-10 23:18   ` [JGIT PATCH 2/3] Add ObjectId.startsWith(AbbreviatedObjectId) Shawn O. Pearce
2008-12-10 23:18     ` [JGIT PATCH 3/3] Change AnyObjectId.abbreviate() to return AbbreviatedObjectId Shawn O. Pearce

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).