Commit bad68c0a998116685ad75cab84210004dd2c5be1

Russell Belfer 2012-11-13T14:02:59

Add iterator for git_index object The index iterator could previously only be created from a repo object, but this allows creating an iterator from a `git_index` object instead (while keeping, though renaming, the old function).

diff --git a/src/diff.c b/src/diff.c
index b75ada1..e6634e6 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -777,6 +777,19 @@ int git_diff_tree_to_tree(
 	);
 }
 
+int git_diff__tree_to_index(
+	git_diff_list **diff,
+	git_tree *tree,
+	git_index *index,
+	const git_diff_options *opts)
+{
+	DIFF_FROM_ITERATORS(
+		git_repository *repo = git_index_owner(index),
+	    git_iterator_for_index_range(&a, index, pfx, pfx),
+		git_iterator_for_tree_range(&b, repo, tree, pfx, pfx)
+	);
+}
+
 int git_diff_index_to_tree(
 	git_diff_list **diff,
 	git_repository *repo,
@@ -786,7 +799,7 @@ int git_diff_index_to_tree(
 	DIFF_FROM_ITERATORS(
 		assert(repo && diff),
 		git_iterator_for_tree_range(&a, repo, old_tree, pfx, pfx),
-	    git_iterator_for_index_range(&b, repo, pfx, pfx)
+	    git_iterator_for_repo_index_range(&b, repo, pfx, pfx)
 	);
 }
 
@@ -797,7 +810,7 @@ int git_diff_workdir_to_index(
 {
 	DIFF_FROM_ITERATORS(
 		assert(repo && diff),
-		git_iterator_for_index_range(&a, repo, pfx, pfx),
+		git_iterator_for_repo_index_range(&a, repo, pfx, pfx),
 	    git_iterator_for_workdir_range(&b, repo, pfx, pfx)
 	);
 }
diff --git a/src/diff.h b/src/diff.h
index 1e3be75..3df7ce6 100644
--- a/src/diff.h
+++ b/src/diff.h
@@ -61,5 +61,11 @@ extern bool git_diff_delta__should_skip(
 extern int git_diff__oid_for_file(
 	git_repository *, const char *, uint16_t, git_off_t, git_oid *);
 
+extern int git_diff__tree_to_index(
+	git_diff_list **diff,
+	git_tree *tree,
+	git_index *index,
+	const git_diff_options *opts);
+
 #endif
 
diff --git a/src/index.c b/src/index.c
index 007f19a..128dd18 100644
--- a/src/index.c
+++ b/src/index.c
@@ -835,7 +835,9 @@ unsigned int git_index__prefix_position(git_index *index, const char *path)
 	srch_key.path = path;
 	srch_key.stage = 0;
 
-	git_vector_bsearch3(&pos, &index->entries, index->entries_search, &srch_key);
+	git_vector_sort(&index->entries);
+	git_vector_bsearch3(
+		&pos, &index->entries, index->entries_search, &srch_key);
 
 	return pos;
 }
diff --git a/src/iterator.c b/src/iterator.c
index 33b775c..ee83a4f 100644
--- a/src/iterator.c
+++ b/src/iterator.c
@@ -330,6 +330,7 @@ typedef struct {
 	git_iterator base;
 	git_index *index;
 	unsigned int current;
+	bool free_index;
 } index_iterator;
 
 static int index_iterator__current(
@@ -387,32 +388,47 @@ static int index_iterator__reset(git_iterator *self)
 static void index_iterator__free(git_iterator *self)
 {
 	index_iterator *ii = (index_iterator *)self;
-	git_index_free(ii->index);
+	if (ii->free_index)
+		git_index_free(ii->index);
 	ii->index = NULL;
 }
 
 int git_iterator_for_index_range(
 	git_iterator **iter,
-	git_repository *repo,
+	git_index  *index,
 	const char *start,
 	const char *end)
 {
-	int error;
 	index_iterator *ii;
 
 	ITERATOR_BASE_INIT(ii, index, INDEX);
 
-	if ((error = git_repository_index(&ii->index, repo)) < 0)
-		git__free(ii);
-	else {
-		ii->base.ignore_case = ii->index->ignore_case;
-		ii->current = start ? git_index__prefix_position(ii->index, start) : 0;
-		*iter = (git_iterator *)ii;
-	}
+	ii->index = index;
+	ii->base.ignore_case = ii->index->ignore_case;
+	ii->current = start ? git_index__prefix_position(ii->index, start) : 0;
 
-	return error;
+	*iter = (git_iterator *)ii;
+
+	return 0;
 }
 
+int git_iterator_for_repo_index_range(
+	git_iterator **iter,
+	git_repository *repo,
+	const char *start,
+	const char *end)
+{
+	int error;
+	git_index *index;
+
+	if ((error = git_repository_index(&index, repo)) < 0)
+		return error;
+
+	if (!(error = git_iterator_for_index_range(iter, index, start, end)))
+		((index_iterator *)(*iter))->free_index = true;
+
+	return error;
+}
 
 typedef struct workdir_iterator_frame workdir_iterator_frame;
 struct workdir_iterator_frame {
@@ -690,24 +706,21 @@ int git_iterator_for_workdir_range(
 
 	assert(iter && repo);
 
-	if ((error = git_repository__ensure_not_bare(repo, "scan working directory")) < 0)
+	if ((error = git_repository__ensure_not_bare(
+			repo, "scan working directory")) < 0)
 		return error;
 
 	ITERATOR_BASE_INIT(wi, workdir, WORKDIR);
-
 	wi->repo = repo;
 
-	if ((error = git_repository_index(&index, repo)) < 0) {
+	if ((error = git_repository_index__weakptr(&index, repo)) < 0) {
 		git__free(wi);
 		return error;
 	}
 
-	/* Set the ignore_case flag for the workdir iterator to match
-	 * that of the index. */
+	/* Match ignore_case flag for iterator to that of the index */
 	wi->base.ignore_case = index->ignore_case;
 
-	git_index_free(index);
-
 	if (git_buf_sets(&wi->path, git_repository_workdir(repo)) < 0 ||
 		git_path_to_dir(&wi->path) < 0 ||
 		git_ignore__for_path(repo, "", &wi->ignores) < 0)
diff --git a/src/iterator.h b/src/iterator.h
index d7df501..77ead76 100644
--- a/src/iterator.h
+++ b/src/iterator.h
@@ -52,13 +52,23 @@ GIT_INLINE(int) git_iterator_for_tree(
 }
 
 extern int git_iterator_for_index_range(
-	git_iterator **iter, git_repository *repo,
+	git_iterator **iter, git_index *index,
 	const char *start, const char *end);
 
 GIT_INLINE(int) git_iterator_for_index(
+	git_iterator **iter, git_index *index)
+{
+	return git_iterator_for_index_range(iter, index, NULL, NULL);
+}
+
+extern int git_iterator_for_repo_index_range(
+	git_iterator **iter, git_repository *repo,
+	const char *start, const char *end);
+
+GIT_INLINE(int) git_iterator_for_repo_index(
 	git_iterator **iter, git_repository *repo)
 {
-	return git_iterator_for_index_range(iter, repo, NULL, NULL);
+	return git_iterator_for_repo_index_range(iter, repo, NULL, NULL);
 }
 
 extern int git_iterator_for_workdir_range(
diff --git a/src/submodule.c b/src/submodule.c
index 1bd8c42..527d9e4 100644
--- a/src/submodule.c
+++ b/src/submodule.c
@@ -1118,7 +1118,7 @@ static int load_submodule_config_from_index(
 	git_iterator *i;
 	const git_index_entry *entry;
 
-	if ((error = git_iterator_for_index(&i, repo)) < 0)
+	if ((error = git_iterator_for_repo_index(&i, repo)) < 0)
 		return error;
 
 	error = git_iterator_current(i, &entry);
diff --git a/src/vector.h b/src/vector.h
index 5061f78..6d820b8 100644
--- a/src/vector.h
+++ b/src/vector.h
@@ -29,17 +29,26 @@ void git_vector_swap(git_vector *a, git_vector *b);
 
 void git_vector_sort(git_vector *v);
 
+/** Linear search for matching entry using internal comparison function */
 int git_vector_search(git_vector *v, const void *entry);
+
+/** Linear search for matching entry using explicit comparison function */
 int git_vector_search2(git_vector *v, git_vector_cmp cmp, const void *key);
 
+/**
+ * Binary search for matching entry using explicit comparison function that
+ * returns position where item would go if not found.
+ */
 int git_vector_bsearch3(
 	unsigned int *at_pos, git_vector *v, git_vector_cmp cmp, const void *key);
 
+/** Binary search for matching entry using internal comparison function */
 GIT_INLINE(int) git_vector_bsearch(git_vector *v, const void *key)
 {
 	return git_vector_bsearch3(NULL, v, v->_cmp, key);
 }
 
+/** Binary search for matching entry using explicit comparison function */
 GIT_INLINE(int) git_vector_bsearch2(
 	git_vector *v, git_vector_cmp cmp, const void *key)
 {
diff --git a/tests-clar/diff/iterator.c b/tests-clar/diff/iterator.c
index c2ab994..3689032 100644
--- a/tests-clar/diff/iterator.c
+++ b/tests-clar/diff/iterator.c
@@ -350,7 +350,7 @@ static void index_iterator_test(
 	int count = 0;
 	git_repository *repo = cl_git_sandbox_init(sandbox);
 
-	cl_git_pass(git_iterator_for_index_range(&i, repo, start, end));
+	cl_git_pass(git_iterator_for_repo_index_range(&i, repo, start, end));
 	cl_git_pass(git_iterator_current(i, &entry));
 
 	while (entry != NULL) {