Commit eec952351363354cad2e094a10d8545e4d2a996f

Vicent Marti 2010-12-02T04:58:22

Commit parents now use the common 'vector' code No more linked lists, no more O(n) access. Signed-off-by: Vicent Marti <tanoku@gmail.com>

diff --git a/src/commit.c b/src/commit.c
index 8af92bf..dbb6926 100644
--- a/src/commit.c
+++ b/src/commit.c
@@ -43,16 +43,7 @@
 
 static void clear_parents(git_commit *commit)
 {
-	git_commit_parents *node, *next_node;
-
-	node = commit->parents;
-	while (node) {
-		next_node = node->next;
-		free(node);
-		node = next_node;
-	}
-
-	commit->parents = NULL;
+	git_vector_clear(&commit->parents);
 }
 
 void git_commit__free(git_commit *commit)
@@ -74,18 +65,18 @@ const git_oid *git_commit_id(git_commit *c)
 
 int git_commit__writeback(git_commit *commit, git_odb_source *src)
 {
-	git_commit_parents *parent;
+	unsigned int i;
 
 	if (commit->tree == NULL)
 		return GIT_EMISSINGOBJDATA;
 
 	git__write_oid(src, "tree", git_tree_id(commit->tree));
 
-	parent = commit->parents;
+	for (i = 0; i < commit->parents.length; ++i) {
+		git_commit *parent;
 
-	while (parent != NULL) {
-		git__write_oid(src, "parent", git_commit_id(parent->commit));
-		parent = parent->next;
+		parent = git_vector_get(&commit->parents, i);
+		git__write_oid(src, "parent", git_commit_id(parent));
 	}
 
 	if (commit->author == NULL)
@@ -115,6 +106,14 @@ int commit_parse_buffer(git_commit *commit, void *data, size_t len, unsigned int
 	git_oid oid;
 	int error;
 
+	/* first parse; the vector hasn't been initialized yet */
+	if (commit->parents.contents == NULL) {
+		git_vector_init(&commit->parents, 4, NULL, NULL);
+	}
+
+	clear_parents(commit);
+
+
 	if ((error = git__parse_oid(&oid, &buffer, buffer_end, "tree ")) < 0)
 		return error;
 
@@ -125,21 +124,14 @@ int commit_parse_buffer(git_commit *commit, void *data, size_t len, unsigned int
 	 * TODO: commit grafts!
 	 */
 
-	clear_parents(commit);
-
 	while (git__parse_oid(&oid, &buffer, buffer_end, "parent ") == 0) {
 		git_commit *parent;
-		git_commit_parents *node;
 
 		if ((error = git_repository_lookup((git_object **)&parent, commit->object.repo, &oid, GIT_OBJ_COMMIT)) < 0)
 			return error;
 
-		if ((node = git__malloc(sizeof(git_commit_parents))) == NULL)
+		if (git_vector_insert(&commit->parents, parent) < 0)
 			return GIT_ENOMEM;
-
-		node->commit = parent;
-		node->next = commit->parents;
-		commit->parents = node;
 	}
 
 
@@ -259,31 +251,14 @@ time_t git_commit_time(git_commit *commit)
 
 unsigned int git_commit_parentcount(git_commit *commit)
 {
-	git_commit_parents *parent;
-	unsigned int count = 0;
-
 	assert(commit);
-	CHECK_FULL_PARSE();
-
-	for (parent = commit->parents; parent != NULL; parent = parent->next) {
-		count++;
-	}
-
-	return count;
+	return commit->parents.length;
 }
 
 git_commit * git_commit_parent(git_commit *commit, unsigned int n)
 {
-	git_commit_parents *parent;
-
 	assert(commit);
-	CHECK_FULL_PARSE();
-
-	for (parent = commit->parents; parent != NULL && n > 0; parent = parent->next) {
-		n--;
-	}
-
-	return parent ? parent->commit : NULL;
+	return git_vector_get(&commit->parents, n);
 }
 
 void git_commit_set_tree(git_commit *commit, git_tree *tree)
@@ -334,17 +309,9 @@ void git_commit_set_message(git_commit *commit, const char *message)
 	/* TODO: extract short message */
 }
 
-void git_commit_add_parent(git_commit *commit, git_commit *new_parent)
+int git_commit_add_parent(git_commit *commit, git_commit *new_parent)
 {
-	git_commit_parents *node;
-
-	commit->object.modified = 1;
 	CHECK_FULL_PARSE();
-
-	if ((node = git__malloc(sizeof(git_commit_parents))) == NULL)
-		return;
-
-	node->commit = new_parent;
-	node->next = commit->parents;
-	commit->parents = node;
+	commit->object.modified = 1;
+	return git_vector_insert(&commit->parents, new_parent);
 }
diff --git a/src/commit.h b/src/commit.h
index 1c765ab..617d237 100644
--- a/src/commit.h
+++ b/src/commit.h
@@ -4,19 +4,15 @@
 #include "git/commit.h"
 #include "tree.h"
 #include "repository.h"
+#include "vector.h"
 
 #include <time.h>
 
-typedef struct git_commit_parents {
-	git_commit *commit;
-	struct git_commit_parents *next;
-} git_commit_parents;
-
 struct git_commit {
 	git_object object;
 
 	time_t commit_time;
-	git_commit_parents *parents;
+	git_vector parents;
 
 	git_tree *tree;
 	git_person *author;
diff --git a/src/git/commit.h b/src/git/commit.h
index 70b08e9..056997f 100644
--- a/src/git/commit.h
+++ b/src/git/commit.h
@@ -113,8 +113,9 @@ GIT_EXTERN(git_commit *) git_commit_parent(git_commit *commit, unsigned int n);
  * Add a new parent commit to an existing commit
  * @param commit the commit object
  * @param new_parent the new commit which will be a parent
+ * @return 0 on success; error code otherwise
  */
-GIT_EXTERN(void) git_commit_add_parent(git_commit *commit, git_commit *new_parent);
+GIT_EXTERN(int) git_commit_add_parent(git_commit *commit, git_commit *new_parent);
 
 /**
  * Set the message of a commit
diff --git a/src/revwalk.c b/src/revwalk.c
index eda45f0..b724f77 100644
--- a/src/revwalk.c
+++ b/src/revwalk.c
@@ -123,7 +123,7 @@ static git_revwalk_commit *commit_to_walkcommit(git_revwalk *walk, git_commit *c
 static git_revwalk_commit *insert_commit(git_revwalk *walk, git_commit *commit_object)
 {
 	git_revwalk_commit *commit;
-	git_commit_parents *parents;
+	unsigned int i;
 
 	assert(walk && commit_object);
 
@@ -139,13 +139,16 @@ static git_revwalk_commit *insert_commit(git_revwalk *walk, git_commit *commit_o
 
 	commit->seen = 1;
 
-	for (parents = commit->commit_object->parents; parents != NULL; parents = parents->next) {
+	for (i = 0; i < commit->commit_object->parents.length; ++i) {
+		git_commit *parent_object;
 		git_revwalk_commit *parent;
 
-		if ((parent = commit_to_walkcommit(walk, parents->commit)) == NULL)
+		parent_object = git_vector_get(&commit->commit_object->parents, i);
+
+		if ((parent = commit_to_walkcommit(walk, parent_object)) == NULL)
 			return NULL;
 
-		parent = insert_commit(walk, parents->commit);
+		parent = insert_commit(walk, parent_object);
 		if (parent == NULL)
 			return NULL;
 
diff --git a/tests/t0402-details.c b/tests/t0402-details.c
index a01a708..d97917a 100644
--- a/tests/t0402-details.c
+++ b/tests/t0402-details.c
@@ -52,7 +52,7 @@ BEGIN_TEST(query_details_test)
 		must_be_true(strchr(message, '\n') != NULL);
 		must_be_true(strchr(message_short, '\n') == NULL);
 		must_be_true(commit_time > 0);
-		must_be_true(0 <= parents && parents <= 2);
+		must_be_true(parents <= 2);
 		for (p = 0;p < parents;p++) {
 			parent = git_commit_parent(commit, p);
 			must_be_true(parent != NULL);