Re: [PATCH 06/21] convert manual allocations to argv_array
On Sat, Feb 20, 2016 at 3:57 AM, Jeff King wrote: > On Sat, Feb 20, 2016 at 03:39:36AM -0500, Eric Sunshine wrote: >> I also had made the strbuf_detach() analogy in my response but deleted >> it before sending; I do think it's a reasonable API template to mirror >> via new argv_array_detach(). > > That would look like this, which I think is not too bad (on top of my > series for now; I'd do the API function as a separate patch at the > beginning and then use it immediately). Looks reasonable. > diff --git a/argv-array.c b/argv-array.c > index eaed477..5d370fa 100644 > --- a/argv-array.c > +++ b/argv-array.c > @@ -74,3 +74,14 @@ void argv_array_clear(struct argv_array *array) > } > argv_array_init(array); > } > + > +const char **argv_array_detach(struct argv_array *array) > +{ > + if (array->argv == empty_argv) > + return xcalloc(1, sizeof(const char *)); > + else { > + const char **ret = array->argv; > + argv_array_init(array); > + return ret; > + } > +} > diff --git a/argv-array.h b/argv-array.h > index a2fa0aa..29056e4 100644 > --- a/argv-array.h > +++ b/argv-array.h > @@ -20,5 +20,6 @@ void argv_array_pushl(struct argv_array *, ...); > void argv_array_pushv(struct argv_array *, const char **); > void argv_array_pop(struct argv_array *); > void argv_array_clear(struct argv_array *); > +const char **argv_array_detach(struct argv_array *); > > #endif /* ARGV_ARRAY_H */ > diff --git a/line-log.c b/line-log.c > index fa095b9..bbe31ed 100644 > --- a/line-log.c > +++ b/line-log.c > @@ -748,15 +748,17 @@ void line_log_init(struct rev_info *rev, const char > *prefix, struct string_list > > if (!rev->diffopt.detect_rename) { > struct line_log_data *r; > - struct argv_array paths = ARGV_ARRAY_INIT; > + struct argv_array array = ARGV_ARRAY_INIT; > + const char **paths; > > for (r = range; r; r = r->next) > - argv_array_push(&paths, r->path); > + argv_array_push(&array, r->path); > + paths = argv_array_detach(&array); > + > parse_pathspec(&rev->diffopt.pathspec, 0, > - PATHSPEC_PREFER_FULL, "", paths.argv); > - /* argv strings are now owned by pathspec */ > - paths.argc = 0; > - argv_array_clear(&paths); > + PATHSPEC_PREFER_FULL, "", paths); > + /* strings are now owned by pathspec */ > + free(paths); > } > } -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 06/21] convert manual allocations to argv_array
On Sat, Feb 20, 2016 at 03:39:36AM -0500, Eric Sunshine wrote: > I also had made the strbuf_detach() analogy in my response but deleted > it before sending; I do think it's a reasonable API template to mirror > via new argv_array_detach(). That would look like this, which I think is not too bad (on top of my series for now; I'd do the API function as a separate patch at the beginning and then use it immediately). diff --git a/argv-array.c b/argv-array.c index eaed477..5d370fa 100644 --- a/argv-array.c +++ b/argv-array.c @@ -74,3 +74,14 @@ void argv_array_clear(struct argv_array *array) } argv_array_init(array); } + +const char **argv_array_detach(struct argv_array *array) +{ + if (array->argv == empty_argv) + return xcalloc(1, sizeof(const char *)); + else { + const char **ret = array->argv; + argv_array_init(array); + return ret; + } +} diff --git a/argv-array.h b/argv-array.h index a2fa0aa..29056e4 100644 --- a/argv-array.h +++ b/argv-array.h @@ -20,5 +20,6 @@ void argv_array_pushl(struct argv_array *, ...); void argv_array_pushv(struct argv_array *, const char **); void argv_array_pop(struct argv_array *); void argv_array_clear(struct argv_array *); +const char **argv_array_detach(struct argv_array *); #endif /* ARGV_ARRAY_H */ diff --git a/line-log.c b/line-log.c index fa095b9..bbe31ed 100644 --- a/line-log.c +++ b/line-log.c @@ -748,15 +748,17 @@ void line_log_init(struct rev_info *rev, const char *prefix, struct string_list if (!rev->diffopt.detect_rename) { struct line_log_data *r; - struct argv_array paths = ARGV_ARRAY_INIT; + struct argv_array array = ARGV_ARRAY_INIT; + const char **paths; for (r = range; r; r = r->next) - argv_array_push(&paths, r->path); + argv_array_push(&array, r->path); + paths = argv_array_detach(&array); + parse_pathspec(&rev->diffopt.pathspec, 0, - PATHSPEC_PREFER_FULL, "", paths.argv); - /* argv strings are now owned by pathspec */ - paths.argc = 0; - argv_array_clear(&paths); + PATHSPEC_PREFER_FULL, "", paths); + /* strings are now owned by pathspec */ + free(paths); } } -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 06/21] convert manual allocations to argv_array
On Sat, Feb 20, 2016 at 3:34 AM, Jeff King wrote: > On Sat, Feb 20, 2016 at 03:29:29AM -0500, Eric Sunshine wrote: >> On Sat, Feb 20, 2016 at 3:10 AM, Jeff King wrote: >> > On Sat, Feb 20, 2016 at 03:07:00AM -0500, Eric Sunshine wrote: >> >> > + /* argv strings are now owned by pathspec */ >> >> > + paths.argc = 0; >> >> > + argv_array_clear(&paths); >> >> >> >> This overly intimate knowledge of the internal implementation of >> >> argv_array_clear() is rather ugly. >> > >> > Yep, I agree. Suggestions? >> > [...] >> > >> > I guess we can make an argv_array_detach_strings() function. Or maybe >> > even just argv_array_detach() would be less gross, and then this >> > function could manually free the array but not the strings themselves. >> >> [...] >> I wonder if a simple "dup'ing" string_list would be more suitable for >> this case. You'd have to append the NULL item manually with >> string_list_append_nodup(), and string_list_clear() would then be the >> correct way to dispose of the list without intimate knowledge of its >> implementation and no need for an API extension. > > A string_list doesn't just store pointers; it's a struct with a util > field. So you can't pass it to things expecting a "const char **". Yep, I knew that but wasn't thinking straight. > I think argv_array_detach() is the least-bad thing here. It matches > strbuf_detach() to say "you now own the storage" (as opposed to just > peeking at argv.argv, which we should do only in a read-only way). I also had made the strbuf_detach() analogy in my response but deleted it before sending; I do think it's a reasonable API template to mirror via new argv_array_detach(). -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 06/21] convert manual allocations to argv_array
On Sat, Feb 20, 2016 at 03:29:29AM -0500, Eric Sunshine wrote: > On Sat, Feb 20, 2016 at 3:10 AM, Jeff King wrote: > > On Sat, Feb 20, 2016 at 03:07:00AM -0500, Eric Sunshine wrote: > >> > + /* argv strings are now owned by pathspec */ > >> > + paths.argc = 0; > >> > + argv_array_clear(&paths); > >> > >> This overly intimate knowledge of the internal implementation of > >> argv_array_clear() is rather ugly. > > > > Yep, I agree. Suggestions? > > > > We can just leak the array of "char *". This function is called only > > once per program invocation, and that's unlikely to change. > > > > I guess we can make an argv_array_detach_strings() function. Or maybe > > even just argv_array_detach() would be less gross, and then this > > function could manually free the array but not the strings themselves. > > The latter is what I was thinking, and I agree that > argv_array_detach() would be less gross than > argv_array_detach_strings(), however, it also feels a bit wrong since > this sort of ownership transfer is kind of out of scope for > argv_array. > > I wonder if a simple "dup'ing" string_list would be more suitable for > this case. You'd have to append the NULL item manually with > string_list_append_nodup(), and string_list_clear() would then be the > correct way to dispose of the list without intimate knowledge of its > implementation and no need for an API extension. A string_list doesn't just store pointers; it's a struct with a util field. So you can't pass it to things expecting a "const char **". I think argv_array_detach() is the least-bad thing here. It matches strbuf_detach() to say "you now own the storage" (as opposed to just peeking at argv.argv, which we should do only in a read-only way). -Peff -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 06/21] convert manual allocations to argv_array
On Sat, Feb 20, 2016 at 3:10 AM, Jeff King wrote: > On Sat, Feb 20, 2016 at 03:07:00AM -0500, Eric Sunshine wrote: >> > + /* argv strings are now owned by pathspec */ >> > + paths.argc = 0; >> > + argv_array_clear(&paths); >> >> This overly intimate knowledge of the internal implementation of >> argv_array_clear() is rather ugly. > > Yep, I agree. Suggestions? > > We can just leak the array of "char *". This function is called only > once per program invocation, and that's unlikely to change. > > I guess we can make an argv_array_detach_strings() function. Or maybe > even just argv_array_detach() would be less gross, and then this > function could manually free the array but not the strings themselves. The latter is what I was thinking, and I agree that argv_array_detach() would be less gross than argv_array_detach_strings(), however, it also feels a bit wrong since this sort of ownership transfer is kind of out of scope for argv_array. I wonder if a simple "dup'ing" string_list would be more suitable for this case. You'd have to append the NULL item manually with string_list_append_nodup(), and string_list_clear() would then be the correct way to dispose of the list without intimate knowledge of its implementation and no need for an API extension. -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 06/21] convert manual allocations to argv_array
On Sat, Feb 20, 2016 at 03:07:00AM -0500, Eric Sunshine wrote: > > diff --git a/line-log.c b/line-log.c > > @@ -746,23 +747,16 @@ void line_log_init(struct rev_info *rev, const char > > *prefix, struct string_list > > if (!rev->diffopt.detect_rename) { > > - int i, count = 0; > > - struct line_log_data *r = range; > > - const char **paths; > > - while (r) { > > - count++; > > - r = r->next; > > - } > > - paths = xmalloc((count+1)*sizeof(char *)); > > - r = range; > > - for (i = 0; i < count; i++) { > > - paths[i] = xstrdup(r->path); > > - r = r->next; > > - } > > - paths[count] = NULL; > > + struct line_log_data *r; > > + struct argv_array paths = ARGV_ARRAY_INIT; > > + > > + for (r = range; r; r = r->next) > > + argv_array_push(&paths, r->path); > > parse_pathspec(&rev->diffopt.pathspec, 0, > > - PATHSPEC_PREFER_FULL, "", paths); > > - free(paths); > > + PATHSPEC_PREFER_FULL, "", paths.argv); > > + /* argv strings are now owned by pathspec */ > > + paths.argc = 0; > > + argv_array_clear(&paths); > > This overly intimate knowledge of the internal implementation of > argv_array_clear() is rather ugly. Yep, I agree. Suggestions? We can just leak the array of "char *". This function is called only once per program invocation, and that's unlikely to change. I guess we can make an argv_array_detach_strings() function. Or maybe even just argv_array_detach() would be less gross, and then this function could manually free the array but not the strings themselves. -Peff -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 06/21] convert manual allocations to argv_array
On Fri, Feb 19, 2016 at 6:23 AM, Jeff King wrote: > There are many manual argv allocations that predate the > argv_array API. Switching to that API brings a few > advantages: > > 1. We no longer have to manually compute the correct final > array size (so it's one less thing we can screw up). > > 2. In many cases we had to make a separate pass to count, > then allocate, then fill in the array. Now we can do it > in one pass, making the code shorter and easier to > follow. > > 3. argv_array handles memory ownership for us, making it > more obvious when things should be free()d and and when > not. > > Most of these cases are pretty straightforward. In some, we > switch from "run_command_v" to "run_command" which lets us > directly use the argv_array embedded in "struct > child_process". > > Signed-off-by: Jeff King > --- > diff --git a/line-log.c b/line-log.c > @@ -746,23 +747,16 @@ void line_log_init(struct rev_info *rev, const char > *prefix, struct string_list > if (!rev->diffopt.detect_rename) { > - int i, count = 0; > - struct line_log_data *r = range; > - const char **paths; > - while (r) { > - count++; > - r = r->next; > - } > - paths = xmalloc((count+1)*sizeof(char *)); > - r = range; > - for (i = 0; i < count; i++) { > - paths[i] = xstrdup(r->path); > - r = r->next; > - } > - paths[count] = NULL; > + struct line_log_data *r; > + struct argv_array paths = ARGV_ARRAY_INIT; > + > + for (r = range; r; r = r->next) > + argv_array_push(&paths, r->path); > parse_pathspec(&rev->diffopt.pathspec, 0, > - PATHSPEC_PREFER_FULL, "", paths); > - free(paths); > + PATHSPEC_PREFER_FULL, "", paths.argv); > + /* argv strings are now owned by pathspec */ > + paths.argc = 0; > + argv_array_clear(&paths); This overly intimate knowledge of the internal implementation of argv_array_clear() is rather ugly. > } > } -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html