Re: [PATCH 5/8] string-list: add pos to iterator callback

2 messages, 2 authors, 2016-06-15 · open the first message on its own page

Re: [PATCH 5/8] string-list: add pos to iterator callback

From: Junio C Hamano <hidden>
Date: 2016-06-15 23:01:47

Jeff King [off-list ref] writes:
When we are running a string-list foreach or filter, the
callback function sees only the string_list_item, along with
a void* data pointer provided by the caller. This is
sufficient for most purposes.

However, it can also be useful to know the position of the
item within the string (for example, if the data pointer
s/the string/&-list/ (or s/&/&_list/).
points to a secondary array in which each element
corresponds to part of the string list). We can help this
use case by providing the position to each callback.

Signed-off-by: Jeff King <redacted>
---
The diff here is noisy, and I expect in the long run that the one caller
I add to builtin/tag.c later in the series will eventually stop using
string_list entirely (in favor of a custom struct), which may leave us
with no callers that actually use the new field.

I do think the logic above is sound, though, and it's a potentially
useful thing. There may be other sites that avoid the for_each wrapper
in favor of iterating themselves simply _because_ they needed to know
the position (I would just do the same here, except that my new caller
wants to use filter_string_list, which is a little more complicated).
While I can buy that some callers would want to learn the pos in the
list, I am not sure if this is a good direction to go.  Primarily, I
am having trouble sifting between "want" and "need".

How often do callers want to do this?  If only narrow specialized
callers want this, is it unreasonable to ask them to add a "int ctr"
in their cb_data and use "pos = ((struct theirs *)cb_data)->ctr++"
in their callback instead?

Re: [PATCH 5/8] string-list: add pos to iterator callback

From: Jeff King <hidden>
Date: 2016-06-15 23:01:47

On Tue, Jul 01, 2014 at 10:45:19AM -0700, Junio C Hamano wrote:
Jeff King [off-list ref] writes:
quoted
When we are running a string-list foreach or filter, the
callback function sees only the string_list_item, along with
a void* data pointer provided by the caller. This is
sufficient for most purposes.

However, it can also be useful to know the position of the
item within the string (for example, if the data pointer
s/the string/&-list/ (or s/&/&_list/).
Thanks, yeah.
While I can buy that some callers would want to learn the pos in the
list, I am not sure if this is a good direction to go.  Primarily, I
am having trouble sifting between "want" and "need".

How often do callers want to do this?  If only narrow specialized
callers want this, is it unreasonable to ask them to add a "int ctr"
in their cb_data and use "pos = ((struct theirs *)cb_data)->ctr++"
in their callback instead?
Not all that often, I suppose (I only add one caller in this series). I
just found it a little hack-ish to force callers to keep their own
counter when we already have it (especially because it is not too hard
to get it wrong, for example by forgetting to increment the counter in
one code path of the callback).

Here's what the caller would look like without "pos" (done as a patch on
top of the series, so pos is still there, but no longer used).
diff --git a/builtin/tag.c b/builtin/tag.c
index f17192c..dc6f105 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -151,14 +151,20 @@ static int util_is_not_null(struct string_list_item *it, int pos, void *data)
 	return !!it->util;
 }
 
-static int matches_contains(struct string_list_item *it, int pos, void *data)
+struct contains_callback_data {
+	int ctr;
+	unsigned char *contains;
+};
+
+static int matches_contains(struct string_list_item *it, int pos, void *vdata)
 {
-	unsigned char *contains = data;
-	return contains[pos];
+	struct contains_callback_data *data = vdata;
+	return data->contains[data->ctr++];
 }
 
 static void limit_by_contains(struct string_list *tags, struct commit_list *with)
 {
+	struct contains_callback_data cbdata;
 	struct commit_list *tag_commits = NULL, **tail = &tag_commits;
 	unsigned char *result;
 	int i;
@@ -180,7 +186,10 @@ static void limit_by_contains(struct string_list *tags, struct commit_list *with
 
 	result = xmalloc(tags->nr);
 	commit_contains(with, tag_commits, NULL, result);
-	filter_string_list(tags, 1, matches_contains, result);
+
+	cbdata.ctr = 0;
+	cbdata.contains = result;
+	filter_string_list(tags, 1, matches_contains, &cbdata);
 
 	free(result);
 	free_commit_list(tag_commits);
So I think it's a small change in a lot of places rather than a kind of
ugly change in one spot.

All that being said, I think the real issue here is that I want more
than a string list (I am already using the util field for the sha1, but
this code would be potentially simpler if I could also store the commit
object). In the long run I hope to factor out a ref-listing API that can
be used by tag, branch, and for-each-ref. And then this string-list code
would go away in favor of a more expansive struct. So it may not be
worth worrying about keeping it too clean.

-Peff
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help