Commit 684b35c41b9166645e2edb9bc708aa7ddf9c1f24

Edward Thomson 2016-02-25T15:11:14

iterator: disambiguate reset and reset_range Disambiguate the reset and reset_range functions. Now reset_range with a NULL path will clear the start or end; reset will leave the existing start and end unchanged.

diff --git a/src/checkout.c b/src/checkout.c
index deeee62..cf505f1 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -2508,7 +2508,7 @@ int git_checkout_iterator(
 	workdir_opts.start = data.pfx;
 	workdir_opts.end = data.pfx;
 
-	if ((error = git_iterator_reset(target, data.pfx, data.pfx)) < 0 ||
+	if ((error = git_iterator_reset_range(target, data.pfx, data.pfx)) < 0 ||
 		(error = git_iterator_for_workdir_ext(
 			&workdir, data.repo, data.opts.target_directory, index, NULL,
 			&workdir_opts)) < 0)
diff --git a/src/iterator.c b/src/iterator.c
index 7b3ad40..f7b87fc 100644
--- a/src/iterator.c
+++ b/src/iterator.c
@@ -18,6 +18,7 @@
 	(P)->cb.advance = NAME_LC ## _iterator__advance; \
 	(P)->cb.advance_into = NAME_LC ## _iterator__advance_into; \
 	(P)->cb.reset   = NAME_LC ## _iterator__reset; \
+	(P)->cb.reset_range = NAME_LC ## _iterator__reset_range; \
 	(P)->cb.at_end  = NAME_LC ## _iterator__at_end; \
 	(P)->cb.free    = NAME_LC ## _iterator__free; \
 	} while (0)
@@ -199,16 +200,18 @@ static void iterator_pathlist__update_ignore_case(git_iterator *iter)
 static int iterator__reset_range(
 	git_iterator *iter, const char *start, const char *end)
 {
+	if (iter->start)
+		git__free(iter->start);
+
 	if (start) {
-		if (iter->start)
-			git__free(iter->start);
 		iter->start = git__strdup(start);
 		GITERR_CHECK_ALLOC(iter->start);
 	}
 
+	if (iter->end)
+		git__free(iter->end);
+
 	if (end) {
-		if (iter->end)
-			git__free(iter->end);
 		iter->end = git__strdup(end);
 		GITERR_CHECK_ALLOC(iter->end);
 	}
@@ -270,7 +273,14 @@ static int empty_iterator__noop(const git_index_entry **e, git_iterator *i)
 	return GIT_ITEROVER;
 }
 
-static int empty_iterator__reset(git_iterator *i, const char *s, const char *e)
+static int empty_iterator__reset(git_iterator *i)
+{
+	GIT_UNUSED(i);
+	return 0;
+}
+
+static int empty_iterator__reset_range(
+	git_iterator *i, const char *s, const char *e)
 {
 	GIT_UNUSED(i); GIT_UNUSED(s); GIT_UNUSED(e);
 	return 0;
@@ -741,17 +751,23 @@ static int tree_iterator__advance_into(
 	return tree_iterator__current(entry, self);
 }
 
-static int tree_iterator__reset(
-	git_iterator *self, const char *start, const char *end)
+static int tree_iterator__reset(git_iterator *self)
 {
 	tree_iterator *ti = (tree_iterator *)self;
 
+	ti->base.flags &= ~GIT_ITERATOR_FIRST_ACCESS;
+
 	tree_iterator__pop_all(ti, false, false);
+	return tree_iterator__push_frame(ti); /* re-expand root tree */
+}
 
+static int tree_iterator__reset_range(
+	git_iterator *self, const char *start, const char *end)
+{
 	if (iterator__reset_range(self, start, end) < 0)
 		return -1;
 
-	return tree_iterator__push_frame(ti); /* re-expand root tree */
+	return tree_iterator__reset(self);
 }
 
 static int tree_iterator__at_end(git_iterator *self)
@@ -1017,16 +1033,13 @@ static int index_iterator__advance_into(
 	return index_iterator__current(entry, self);
 }
 
-static int index_iterator__reset(
-	git_iterator *self, const char *start, const char *end)
+static int index_iterator__reset(git_iterator *self)
 {
 	index_iterator *ii = (index_iterator *)self;
 	const git_index_entry *ie;
 
-	if (iterator__reset_range(self, start, end) < 0)
-		return -1;
-
 	ii->current = 0;
+	ii->base.flags &= ~GIT_ITERATOR_FIRST_ACCESS;
 
 	iterator_pathlist_walk__reset(self);
 
@@ -1057,6 +1070,15 @@ static int index_iterator__reset(
 	return 0;
 }
 
+static int index_iterator__reset_range(
+	git_iterator *self, const char *start, const char *end)
+{
+	if (iterator__reset_range(self, start, end) < 0)
+		return -1;
+
+	return index_iterator__reset(self);
+}
+
 static void index_iterator__free(git_iterator *self)
 {
 	index_iterator *ii = (index_iterator *)self;
@@ -1098,7 +1120,7 @@ int git_iterator_for_index(
 	git_buf_init(&ii->partial, 0);
 	ii->tree_entry.mode = GIT_FILEMODE_TREE;
 
-	index_iterator__reset((git_iterator *)ii, NULL, NULL);
+	index_iterator__reset((git_iterator *)ii);
 
 	*iter = (git_iterator *)ii;
 	return 0;
@@ -1479,19 +1501,17 @@ static int fs_iterator__advance(
 	return fs_iterator__advance_over(entry, self);
 }
 
-static int fs_iterator__reset(
-	git_iterator *self, const char *start, const char *end)
+static int fs_iterator__reset(git_iterator *self)
 {
 	int error;
 	fs_iterator *fi = (fs_iterator *)self;
 
+	fi->base.flags &= ~GIT_ITERATOR_FIRST_ACCESS;
+
 	while (fi->stack != NULL && fi->stack->next != NULL)
 		fs_iterator__pop_frame(fi, fi->stack, false);
 	fi->depth = 0;
 
-	if ((error = iterator__reset_range(self, start, end)) < 0)
-		return error;
-
 	fs_iterator__seek_frame_start(fi, fi->stack);
 
 	error = fs_iterator__update_entry(fi);
@@ -1501,6 +1521,17 @@ static int fs_iterator__reset(
 	return error;
 }
 
+static int fs_iterator__reset_range(
+	git_iterator *self, const char *start, const char *end)
+{
+	int error;
+
+	if ((error = iterator__reset_range(self, start, end)) < 0)
+		return error;
+
+	return fs_iterator__reset(self);
+}
+
 static void fs_iterator__free(git_iterator *self)
 {
 	fs_iterator *fi = (fs_iterator *)self;
diff --git a/src/iterator.h b/src/iterator.h
index 3f5c828..019f2e6 100644
--- a/src/iterator.h
+++ b/src/iterator.h
@@ -57,7 +57,8 @@ typedef struct {
 	int (*current)(const git_index_entry **, git_iterator *);
 	int (*advance)(const git_index_entry **, git_iterator *);
 	int (*advance_into)(const git_index_entry **, git_iterator *);
-	int (*reset)(git_iterator *, const char *start, const char *end);
+	int (*reset)(git_iterator *);
+	int (*reset_range)(git_iterator *, const char *start, const char *end);
 	int (*at_end)(git_iterator *);
 	void (*free)(git_iterator *);
 } git_iterator_callbacks;
@@ -201,15 +202,20 @@ GIT_INLINE(int) git_iterator_advance_into_or_over(
 
 /**
  * Go back to the start of the iteration.
- *
- * This resets the iterator to the start of the iteration.  It also allows
- * you to reset the `start` and `end` pathname boundaries of the iteration
- * when doing so.
  */
-GIT_INLINE(int) git_iterator_reset(
+GIT_INLINE(int) git_iterator_reset(git_iterator *iter)
+{
+	return iter->cb->reset(iter);
+}
+
+/**
+ * Go back to the start of the iteration after updating the `start` and
+ * `end` pathname boundaries of the iteration.
+ */
+GIT_INLINE(int) git_iterator_reset_range(
 	git_iterator *iter, const char *start, const char *end)
 {
-	return iter->cb->reset(iter, start, end);
+	return iter->cb->reset_range(iter, start, end);
 }
 
 /**
diff --git a/src/pathspec.c b/src/pathspec.c
index 8a93cdd..361b398 100644
--- a/src/pathspec.c
+++ b/src/pathspec.c
@@ -418,7 +418,7 @@ static int pathspec_match_from_iterator(
 		GITERR_CHECK_ALLOC(m);
 	}
 
-	if ((error = git_iterator_reset(iter, ps->prefix, ps->prefix)) < 0)
+	if ((error = git_iterator_reset_range(iter, ps->prefix, ps->prefix)) < 0)
 		goto done;
 
 	if (git_iterator_type(iter) == GIT_ITERATOR_TYPE_WORKDIR &&
diff --git a/tests/diff/iterator.c b/tests/diff/iterator.c
index 25a23ed..b64c954 100644
--- a/tests/diff/iterator.c
+++ b/tests/diff/iterator.c
@@ -54,7 +54,7 @@ static void tree_iterator_test(
 	cl_assert_equal_i(expected_count, count);
 
 	/* test reset */
-	cl_git_pass(git_iterator_reset(i, NULL, NULL));
+	cl_git_pass(git_iterator_reset(i));
 
 	while (!(error = git_iterator_advance(&entry, i))) {
 		cl_assert(entry);
@@ -634,7 +634,7 @@ static void workdir_iterator_test(
 	cl_assert_equal_i(expected_count, count);
 	cl_assert_equal_i(expected_count + expected_ignores, count_all);
 
-	cl_git_pass(git_iterator_reset(i, NULL, NULL));
+	cl_git_pass(git_iterator_reset(i));
 
 	error = git_iterator_current(&entry, i);
 	cl_assert((error == 0 && entry != NULL) ||
diff --git a/tests/repo/iterator.c b/tests/repo/iterator.c
index c18e24a..5e5e4b5 100644
--- a/tests/repo/iterator.c
+++ b/tests/repo/iterator.c
@@ -59,7 +59,7 @@ static void expect_iterator_items(
 
 	cl_assert_equal_i(expected_flat, count);
 
-	cl_git_pass(git_iterator_reset(i, NULL, NULL));
+	cl_git_pass(git_iterator_reset(i));
 
 	count = 0;
 	cl_git_pass(git_iterator_current(&entry, i));