On 10/29, Junio C Hamano wrote: > Brandon Williams <bmwill@xxxxxxxxxx> writes: > > > We have have reached the limit of the number of flags that can be stored > > s/have have/have/; but bit #9 is unused. > > "We cannot add many more flags even if we wanted to" would be more > flexible and does not take this change hostage to whatever topic > that tries to claim that bit, I would think. I'll tweak the wording a bit. > > > in a single unsigned int. In order to allow for more flags to be added > > to the diff machinery in the future this patch converts the flags to be > > stored in bitfields in 'struct diff_flags'. > > > > Signed-off-by: Brandon Williams <bmwill@xxxxxxxxxx> > > --- > > builtin/commit.c | 7 +++-- > > builtin/log.c | 2 +- > > diff-lib.c | 6 ++-- > > diff.c | 3 +- > > diff.h | 96 +++++++++++++++++++++++++++++++++----------------------- > > sequencer.c | 5 +-- > > 6 files changed, 70 insertions(+), 49 deletions(-) > > > > > diff --git a/diff.h b/diff.h > > index aca150ba2..d58f06106 100644 > > --- a/diff.h > > +++ b/diff.h > > @@ -60,42 +60,59 @@ typedef struct strbuf *(*diff_prefix_fn_t)(struct diff_options *opt, void *data) > > > > #define DIFF_FORMAT_CALLBACK 0x1000 > > > > -#define DIFF_OPT_RECURSIVE (1 << 0) > > -#define DIFF_OPT_TREE_IN_RECURSIVE (1 << 1) > > -#define DIFF_OPT_BINARY (1 << 2) > > -... > > -#define DIFF_OPT_FUNCCONTEXT (1 << 29) > > -#define DIFF_OPT_PICKAXE_IGNORE_CASE (1 << 30) > > -#define DIFF_OPT_DEFAULT_FOLLOW_RENAMES (1U << 31) > > - > > -#define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag) > > -#define DIFF_OPT_TOUCHED(opts, flag) ((opts)->touched_flags & DIFF_OPT_##flag) > > -#define DIFF_OPT_SET(opts, flag) (((opts)->flags |= DIFF_OPT_##flag),((opts)->touched_flags |= DIFF_OPT_##flag)) > > -#define DIFF_OPT_CLR(opts, flag) (((opts)->flags &= ~DIFF_OPT_##flag),((opts)->touched_flags |= DIFF_OPT_##flag)) > > +#define DIFF_FLAGS_INIT { 0 } > > +extern const struct diff_flags diff_flags_cleared; > > This thing is curious. Seeing the scary diff_flags_or(), I would > have expected we'd have diff_flags_clear(&flags). This seemed to make things easier in practice because I was passing some structs by value, let me work with it a bit to see what it looks like when they are passed by reference instead. > > > +struct diff_flags { > > + unsigned RECURSIVE:1; > > + unsigned TREE_IN_RECURSIVE:1; > > + unsigned BINARY:1; > > +... > > + unsigned FUNCCONTEXT:1; > > + unsigned PICKAXE_IGNORE_CASE:1; > > + unsigned DEFAULT_FOLLOW_RENAMES:1; > > +}; > > + > > +static inline struct diff_flags diff_flags_or(struct diff_flags a, > > + struct diff_flags b) > > +{ > > + char *tmp_a = (char *)&a; > > + char *tmp_b = (char *)&b; > > + int i; > > + > > + for (i = 0; i < sizeof(struct diff_flags); i++) > > + tmp_a[i] |= tmp_b[i]; > > + > > + return a; > > +} > > This is doubly scary, but let's see why we need it by looking at the > callers. > > > +#define DIFF_OPT_TST(opts, flag) ((opts)->flags.flag) > > +#define DIFF_OPT_TOUCHED(opts, flag) ((opts)->touched_flags.flag) > > +#define DIFF_OPT_SET(opts, flag) (((opts)->flags.flag = 1),((opts)->touched_flags.flag = 1)) > > +#define DIFF_OPT_CLR(opts, flag) (((opts)->flags.flag = 0),((opts)->touched_flags.flag = 1)) > > These are trivial and straight-forward. > > > + > > #define DIFF_XDL_TST(opts, flag) ((opts)->xdl_opts & XDF_##flag) > > #define DIFF_XDL_SET(opts, flag) ((opts)->xdl_opts |= XDF_##flag) > > #define DIFF_XDL_CLR(opts, flag) ((opts)->xdl_opts &= ~XDF_##flag) > > @@ -122,8 +139,8 @@ struct diff_options { > > const char *a_prefix, *b_prefix; > > const char *line_prefix; > > size_t line_prefix_length; > > - unsigned flags; > > - unsigned touched_flags; > > + struct diff_flags flags; > > + struct diff_flags touched_flags; > > > > /* diff-filter bits */ > > unsigned int filter; > > @@ -388,7 +405,8 @@ extern int diff_result_code(struct diff_options *, int); > > > > extern void diff_no_index(struct rev_info *, int, const char **); > > > > -extern int index_differs_from(const char *def, int diff_flags, int ita_invisible_in_index); > > +extern int index_differs_from(const char *def, struct diff_flags flags, > > + int ita_invisible_in_index); > > OK. I tend to think twice before passing any struct by value (even > something that starts its life as a small/single-word struct), but > let's see how much simpler this allows callers to become. > > > diff --git a/builtin/commit.c b/builtin/commit.c > > index d75b3805e..de08c2594 100644 > > --- a/builtin/commit.c > > +++ b/builtin/commit.c > > @@ -912,11 +912,12 @@ static int prepare_to_commit(const char *index_file, const char *prefix, > > * submodules which were manually staged, which would > > * be really confusing. > > */ > > - int diff_flags = DIFF_OPT_OVERRIDE_SUBMODULE_CONFIG; > > + struct diff_flags flags = DIFF_FLAGS_INIT; > > + flags.OVERRIDE_SUBMODULE_CONFIG = 1; > > if (ignore_submodule_arg && > > !strcmp(ignore_submodule_arg, "all")) > > - diff_flags |= DIFF_OPT_IGNORE_SUBMODULES; > > This couldn't have been done in patches 1+2/3 because DIFF_OPT_SET() > does not take a bare 'flags' but diffopt itself, which was a bit > unfortunate, but the end result after this step becomes a lot more > sensible. > > > - commitable = index_differs_from(parent, diff_flags, 1); > > + flags.IGNORE_SUBMODULES = 1; > > + commitable = index_differs_from(parent, flags, 1); > > OK. > > > diff --git a/builtin/log.c b/builtin/log.c > > index d81a09051..780975ed4 100644 > > --- a/builtin/log.c > > +++ b/builtin/log.c > > @@ -134,7 +134,7 @@ static void cmd_log_init_defaults(struct rev_info *rev) > > > > if (default_date_mode) > > parse_date_format(default_date_mode, &rev->date_mode); > > - rev->diffopt.touched_flags = 0; > > + rev->diffopt.touched_flags = diff_flags_cleared; > > So this structure assignment is a more kosher way to clear > everything than memset(&touched_flags, '\0', sizeof(...)); > I'd still prefer > > diff_flags_clear(&rev->diffopt.touched_flags); > > tough, as it is easy to forget diff_flags_cleared is a singleton > constant specifically created to be assigned for clearing another > flags struct. > > > @@ -546,7 +546,7 @@ int index_differs_from(const char *def, int diff_flags, > > setup_revisions(0, NULL, &rev, &opt); > > DIFF_OPT_SET(&rev.diffopt, QUICK); > > DIFF_OPT_SET(&rev.diffopt, EXIT_WITH_STATUS); > > - rev.diffopt.flags |= diff_flags; > > + rev.diffopt.flags = diff_flags_or(rev.diffopt.flags, flags); > > In a more general case, we cannot know what flags setup_revisions() > gave to rev.diffopt, and because of that we cannot do > > rev.diffopt.flags = diff_flags; > DIFF_OPT_SET(&rev.diffopt, QUICK); > DIFF_OPT_SET(&rev.diffopt, EXIT_WITH_STATUS); > > without using the flags_or() thing. In this codepath, that > currently is not a problem (because we give ac/av = 0/NULL), but it > probably is a good idea to avoid depending on that. > > I still haven't brought myself to like the structure being passed by > value and the singleton diff_flags_cleared thing, but I suspect that > we may get used to them once we start using these. I dunno. > > Thanks. -- Brandon Williams