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;