On Tue, May 28, 2019 at 02:53:59PM -0700, Emily Shaffer wrote:
> > + } else if (skip_prefix(arg, "combine:", &v0)) {
> > + int sub_parse_res = parse_combine_filter(
> > + filter_options, v0, errbuf);
> > + if (sub_parse_res)
> > + return sub_parse_res;
> > + return 0;
>
> Couldn't the three lines above be said more succinctly as "return
> sub_parse_res;"?
Oh yes, that's much better. Don't even need the sub_parse_res variable.
> > +static int digit_value(int c, struct strbuf *errbuf) {
> > + if (c >= '0' && c <= '9')
> > + return c - '0';
> > + if (c >= 'a' && c <= 'f')
> > + return c - 'a' + 10;
> > + if (c >= 'A' && c <= 'F')
> > + return c - 'A' + 10;
>
> I'm sure there's something I'm missing here. But why are you manually
> decoding hex instead of using strtol or sscanf or something?
>
I'll have to give this a try. Thank you for the suggestion.
> > +static int has_reserved_character(
> > + struct strbuf *sub_spec, struct strbuf *errbuf)
> > +{
> > + const char *c = sub_spec->buf;
> > + while (*c) {
> > + if (*c <= ' ' || strchr(RESERVED_NON_WS, *c))
> > + goto found_reserved;
> > + c++;
> > + }
> > +
> > + return 0;
> > +
> > +found_reserved:
>
> What's the value of doing this in a goto instead of embedded in the
> while loop?
>
That's to reduce indentation. Note that if I "inlined" the goto logic in the
while loop, I'd get at least 5 tabs of indentation, and the error message would
be split across a couple lines.
> > +
> > + result = gently_parse_list_objects_filter(filter_options->lhs,
> > + sub_specs[0]->buf,
> > + errbuf) ||
> > + parse_combine_filter(filter_options->rhs,
> > + sub_specs[1]->buf,
> > + errbuf);
>
> I guess you're recursing to combine filter 2 onto filter 1 which has
> been combined onto filter 0 here. But why not just use a list or array?
>
I switched this to use an array at your and Jeff's proddings, and it's much
better now. Thanks! It will be in the next roll-up.
> >
> > void list_objects_filter_release(
> > struct list_objects_filter_options *filter_options)
> > {
> > + if (!filter_options)
> > + return;
> > free(filter_options->filter_spec);
> > free(filter_options->sparse_oid_value);
> > free(filter_options->sparse_path_value);
> > + list_objects_filter_release(filter_options->lhs);
> > + free(filter_options->lhs);
> > + list_objects_filter_release(filter_options->rhs);
> > + free(filter_options->rhs);
>
> Is there a reason that the free shouldn't be included in
> list_objects_filter_release()? Maybe this is a common style guideline
> I've missed, but it seems to me like I'd expect a magic memory cleanup
> function to do it all, and not leave it to me to free.
>
Because there are a couple times the list_objects_filter_options struct is
allocated on the stack or inline in some other struct. This is similar to how
strbuf and other such utility structs are used.
> Jeff H had a comment about this too, but this seems unwieldy for >2
> filters. (I also personally don't like using set index to incidate
> lhs/rhs.) Why not an array of multiple `struct sub`? There's a macro
> utility to generate types and helpers for an array of arbitrary struct
> that may suit...
>
This code is now cleaner that it's using an array.
> > +static enum list_objects_filter_result filter_combine(
> > + struct repository *r,
> > + enum list_objects_filter_situation filter_situation,
> > + struct object *obj,
> > + const char *pathname,
> > + const char *filename,
> > + struct filter_context *ctx)
> > +{
> > + struct filter_combine_data *d = ctx->data;
> > + enum list_objects_filter_result result[2];
> > + enum list_objects_filter_result combined_result = LOFR_ZERO;
> > + int i;
> > +
> > + for (i = 0; i < 2; i++) {
>
> I suppose your lhs and rhs are in sub[0] and sub[1] in part for the sake
> of this loop. But I think it would be easier to understand what is going
> on if you were to perform the loop contents in a helper function (as the
> name of the function would provide some more documentation).
>
Agreed, this is how it will be done in the next roll-up.
> I see that you tested that >2 filters works okay. But by doing it the
> way you have it seems like you're setting up to need recursion all over
> the place to check against all the filters. I suppose I don't see the
> benefit of doing all this recursively, as compared to doing it
> iteratively.
Somehow, the recursive appraoch made more sense to me when I was first writing
the code. But using an array is nicer.