diff: preparse --diff-filter string argument

Instead of running strchr() on the list of status characters over and over again, parse the --diff-filter option into bitfields and use the bits to see if the change to the filepair matches the status requested. Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Jul 17, 2013 at 15:05 UTC 1ecc1cbd3a7642c4f517d086d7b45d6341172dfe
2 files changed +60 -8
diff.c
+56 -7
@@ -3496,6 +3496,53 @@ static int parse_submodule_opt(struct diff_options *options, const char *value)
3496 return 1;
3497 }
3498
3499 +static const char diff_status_letters[] = {
3500 + DIFF_STATUS_ADDED,
3501 + DIFF_STATUS_COPIED,
3502 + DIFF_STATUS_DELETED,
3503 + DIFF_STATUS_MODIFIED,
3504 + DIFF_STATUS_RENAMED,
3505 + DIFF_STATUS_TYPE_CHANGED,
3506 + DIFF_STATUS_UNKNOWN,
3507 + DIFF_STATUS_UNMERGED,
3508 + DIFF_STATUS_FILTER_AON,
3509 + DIFF_STATUS_FILTER_BROKEN,
3510 + '\0',
3511 +};
3512 +
3513 +static unsigned int filter_bit['Z' + 1];
3514 +
3515 +static void prepare_filter_bits(void)
3516 +{
3517 + int i;
3518 +
3519 + if (!filter_bit[DIFF_STATUS_ADDED]) {
3520 + for (i = 0; diff_status_letters[i]; i++)
3521 + filter_bit[(int) diff_status_letters[i]] = (1 << i);
3522 + }
3523 +}
3524 +
3525 +static unsigned filter_bit_tst(char status, const struct diff_options *opt)
3526 +{
3527 + return opt->filter & filter_bit[(int) status];
3528 +}
3529 +
3530 +static int parse_diff_filter_opt(const char *optarg, struct diff_options *opt)
3531 +{
3532 + int i, optch;
3533 +
3534 + prepare_filter_bits();
3535 + for (i = 0; (optch = optarg[i]) != '\0'; i++) {
3536 + unsigned int bit;
3537 +
3538 + bit = (0 <= optch && optch <= 'Z') ? filter_bit[optch] : 0;
3539 + if (!bit)
3540 + continue; /* ignore unknown ones, like we always have */
3541 + opt->filter |= bit;
3542 + }
3543 + return 0;
3544 +}
3545 +
3546 int diff_opt_parse(struct diff_options *options, const char **av, int ac)
3547 {
3548 const char *arg = av[0];
@@ -3717,7 +3764,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
3764 return argcount;
3765 }
3766 else if ((argcount = parse_long_opt("diff-filter", av, &optarg))) {
3720 - options->filter = optarg;
3767 + int offending = parse_diff_filter_opt(optarg, options);
3768 + if (offending)
3769 + die("unknown change class '%c' in --diff-filter=%s",
3770 + offending, optarg);
3771 return argcount;
3772 }
3773 else if (!strcmp(arg, "--abbrev"))
@@ -4513,11 +4563,11 @@ static int match_filter(const struct diff_options *options, const struct diff_fi
4563 {
4564 return (((p->status == DIFF_STATUS_MODIFIED) &&
4565 ((p->score &&
4516 - strchr(options->filter, DIFF_STATUS_FILTER_BROKEN)) ||
4566 + filter_bit_tst(DIFF_STATUS_FILTER_BROKEN, options)) ||
4567 (!p->score &&
4518 - strchr(options->filter, DIFF_STATUS_MODIFIED)))) ||
4568 + filter_bit_tst(DIFF_STATUS_MODIFIED, options)))) ||
4569 ((p->status != DIFF_STATUS_MODIFIED) &&
4520 - strchr(options->filter, p->status)));
4570 + filter_bit_tst(p->status, options)));
4571 }
4572
4573 static void diffcore_apply_filter(struct diff_options *options)
@@ -4525,14 +4575,13 @@ static void diffcore_apply_filter(struct diff_options *options)
4575 int i;
4576 struct diff_queue_struct *q = &diff_queued_diff;
4577 struct diff_queue_struct outq;
4528 - const char *filter = options->filter;
4578
4579 DIFF_QUEUE_CLEAR(&outq);
4580
4532 - if (!filter)
4581 + if (!options->filter)
4582 return;
4583
4535 - if (strchr(filter, DIFF_STATUS_FILTER_AON)) {
4584 + if (filter_bit_tst(DIFF_STATUS_FILTER_AON, options)) {
4585 int found;
4586 for (i = found = 0; !found && i < q->nr; i++) {
4587 if (match_filter(options, q->queue[i]))
diff.h
+4 -1
@@ -103,12 +103,15 @@ enum diff_words_type {
103 };
104
105 struct diff_options {
106 - const char *filter;
106 const char *orderfile;
107 const char *pickaxe;
108 const char *single_follow;
109 const char *a_prefix, *b_prefix;
110 unsigned flags;
111 +
112 + /* diff-filter bits */
113 + unsigned int filter;
114 +
115 int use_color;
116 int context;
117 int interhunkcontext;