Commit aa8f010120577e61715f3ae1286a03055815f9c3

Russell Belfer 2013-04-29T08:59:46

Add git_oid_strcmp and use it for git_oid_streq Add a new git_oid_strcmp that compares a string OID with a hex oid for sort order, and then reimplement git_oid_streq using it. This actually should speed up git_oid_streq because it only reads as far into the string as it needs to, whereas previously it would convert the whole string into an OID and then use git_oid_cmp.

diff --git a/include/git2/oid.h b/include/git2/oid.h
index c35acdc..8d93e79 100644
--- a/include/git2/oid.h
+++ b/include/git2/oid.h
@@ -202,6 +202,16 @@ GIT_EXTERN(int) git_oid_ncmp(const git_oid *a, const git_oid *b, size_t len);
 GIT_EXTERN(int) git_oid_streq(const git_oid *id, const char *str);
 
 /**
+ * Compare an oid to an hex formatted object id.
+ *
+ * @param id oid structure.
+ * @param str input hex string of an object id.
+ * @return -1 if str is not valid, <0 if id sorts before str,
+ *         0 if id matches str, >0 if id sorts after str.
+ */
+GIT_EXTERN(int) git_oid_strcmp(const git_oid *id, const char *str);
+
+/**
  * Check is an oid is all zeros.
  *
  * @return 1 if all zeros, 0 otherwise.
diff --git a/src/oid.c b/src/oid.c
index 4b66990..c7ce6ee 100644
--- a/src/oid.c
+++ b/src/oid.c
@@ -194,14 +194,31 @@ int git_oid_ncmp(const git_oid *oid_a, const git_oid *oid_b, size_t len)
 	return 0;
 }
 
-int git_oid_streq(const git_oid *a, const char *str)
+int git_oid_strcmp(const git_oid *oid_a, const char *str)
 {
-	git_oid id;
+	const unsigned char *a = oid_a->id;
+	unsigned char strval;
+	int hexval;
 
-	if (git_oid_fromstr(&id, str) < 0)
-		return -1;
+	for (a = oid_a->id; *str && (a - oid_a->id) < GIT_OID_RAWSZ; ++a) {
+		if ((hexval = git__fromhex(*str++)) < 0)
+			return -1;
+		strval = hexval << 4;
+		if (*str) {
+			if ((hexval = git__fromhex(*str++)) < 0)
+				return -1;
+			strval |= hexval;
+		}
+		if (*a != strval)
+			return (*a - strval);
+	}
 
-	return git_oid_cmp(a, &id) == 0 ? 0 : -1;
+	return 0;
+}
+
+int git_oid_streq(const git_oid *oid_a, const char *str)
+{
+	return git_oid_strcmp(oid_a, str) == 0 ? 0 : -1;
 }
 
 int git_oid_iszero(const git_oid *oid_a)
diff --git a/tests-clar/core/oid.c b/tests-clar/core/oid.c
index d863a3e..7ee6fb6 100644
--- a/tests-clar/core/oid.c
+++ b/tests-clar/core/oid.c
@@ -16,17 +16,39 @@ void test_core_oid__initialize(void)
 
 void test_core_oid__streq(void)
 {
-	cl_assert(git_oid_streq(&id, str_oid) == 0);
-	cl_assert(git_oid_streq(&id, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef") == -1);
+	cl_assert_equal_i(0, git_oid_streq(&id, str_oid));
+	cl_assert_equal_i(-1, git_oid_streq(&id, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"));
 
-	cl_assert(git_oid_streq(&id, "deadbeef") == -1);
-	cl_assert(git_oid_streq(&id, "I'm not an oid.... :)") == -1);
-	
-	cl_assert(git_oid_streq(&idp, "ae90f12eea699729ed0000000000000000000000") == 0);
-	cl_assert(git_oid_streq(&idp, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef") == -1);
+	cl_assert_equal_i(-1, git_oid_streq(&id, "deadbeef"));
+	cl_assert_equal_i(-1, git_oid_streq(&id, "I'm not an oid.... :)"));
 
-	cl_assert(git_oid_streq(&idp, "deadbeef") == -1);
-	cl_assert(git_oid_streq(&idp, "I'm not an oid.... :)") == -1);
+	cl_assert_equal_i(0, git_oid_streq(&idp, "ae90f12eea699729ed0000000000000000000000"));
+	cl_assert_equal_i(0, git_oid_streq(&idp, "ae90f12eea699729ed"));
+	cl_assert_equal_i(-1, git_oid_streq(&idp, "ae90f12eea699729ed1"));
+	cl_assert_equal_i(-1, git_oid_streq(&idp, "ae90f12eea699729ec"));
+	cl_assert_equal_i(-1, git_oid_streq(&idp, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"));
+
+	cl_assert_equal_i(-1, git_oid_streq(&idp, "deadbeef"));
+	cl_assert_equal_i(-1, git_oid_streq(&idp, "I'm not an oid.... :)"));
+}
+
+void test_core_oid__strcmp(void)
+{
+	cl_assert_equal_i(0, git_oid_strcmp(&id, str_oid));
+	cl_assert(git_oid_strcmp(&id, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef") < 0);
+
+	cl_assert(git_oid_strcmp(&id, "deadbeef") < 0);
+	cl_assert_equal_i(-1, git_oid_strcmp(&id, "I'm not an oid.... :)"));
+
+	cl_assert_equal_i(0, git_oid_strcmp(&idp, "ae90f12eea699729ed0000000000000000000000"));
+	cl_assert_equal_i(0, git_oid_strcmp(&idp, "ae90f12eea699729ed"));
+	cl_assert(git_oid_strcmp(&idp, "ae90f12eea699729ed1") < 0);
+	cl_assert(git_oid_strcmp(&idp, "ae90f12eea699729ec") > 0);
+	cl_assert(git_oid_strcmp(&idp, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef") < 0);
+
+	cl_assert(git_oid_strcmp(&idp, "deadbeef") < 0);
+	cl_assert_equal_i(-1, git_oid_strcmp(&idp, "I'm not an oid.... :)"));
+}
 
 void test_core_oid__ncmp(void)
 {