Skip to content

Commit

Permalink
diff: preparse --diff-filter string argument
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
gitster committed Jul 17, 2013
1 parent 08578fa commit 1ecc1cb
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 8 deletions.
63 changes: 56 additions & 7 deletions diff.c
Original file line number Diff line number Diff line change
Expand Up @@ -3496,6 +3496,53 @@ static int parse_submodule_opt(struct diff_options *options, const char *value)
return 1;
}

static const char diff_status_letters[] = {
DIFF_STATUS_ADDED,
DIFF_STATUS_COPIED,
DIFF_STATUS_DELETED,
DIFF_STATUS_MODIFIED,
DIFF_STATUS_RENAMED,
DIFF_STATUS_TYPE_CHANGED,
DIFF_STATUS_UNKNOWN,
DIFF_STATUS_UNMERGED,
DIFF_STATUS_FILTER_AON,
DIFF_STATUS_FILTER_BROKEN,
'\0',
};

static unsigned int filter_bit['Z' + 1];

static void prepare_filter_bits(void)
{
int i;

if (!filter_bit[DIFF_STATUS_ADDED]) {
for (i = 0; diff_status_letters[i]; i++)
filter_bit[(int) diff_status_letters[i]] = (1 << i);
}
}

static unsigned filter_bit_tst(char status, const struct diff_options *opt)
{
return opt->filter & filter_bit[(int) status];
}

static int parse_diff_filter_opt(const char *optarg, struct diff_options *opt)
{
int i, optch;

prepare_filter_bits();
for (i = 0; (optch = optarg[i]) != '\0'; i++) {
unsigned int bit;

bit = (0 <= optch && optch <= 'Z') ? filter_bit[optch] : 0;
if (!bit)
continue; /* ignore unknown ones, like we always have */
opt->filter |= bit;
}
return 0;
}

int diff_opt_parse(struct diff_options *options, const char **av, int ac)
{
const char *arg = av[0];
Expand Down Expand Up @@ -3717,7 +3764,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
return argcount;
}
else if ((argcount = parse_long_opt("diff-filter", av, &optarg))) {
options->filter = optarg;
int offending = parse_diff_filter_opt(optarg, options);
if (offending)
die("unknown change class '%c' in --diff-filter=%s",
offending, optarg);
return argcount;
}
else if (!strcmp(arg, "--abbrev"))
Expand Down Expand Up @@ -4513,26 +4563,25 @@ static int match_filter(const struct diff_options *options, const struct diff_fi
{
return (((p->status == DIFF_STATUS_MODIFIED) &&
((p->score &&
strchr(options->filter, DIFF_STATUS_FILTER_BROKEN)) ||
filter_bit_tst(DIFF_STATUS_FILTER_BROKEN, options)) ||
(!p->score &&
strchr(options->filter, DIFF_STATUS_MODIFIED)))) ||
filter_bit_tst(DIFF_STATUS_MODIFIED, options)))) ||
((p->status != DIFF_STATUS_MODIFIED) &&
strchr(options->filter, p->status)));
filter_bit_tst(p->status, options)));
}

static void diffcore_apply_filter(struct diff_options *options)
{
int i;
struct diff_queue_struct *q = &diff_queued_diff;
struct diff_queue_struct outq;
const char *filter = options->filter;

DIFF_QUEUE_CLEAR(&outq);

if (!filter)
if (!options->filter)
return;

if (strchr(filter, DIFF_STATUS_FILTER_AON)) {
if (filter_bit_tst(DIFF_STATUS_FILTER_AON, options)) {
int found;
for (i = found = 0; !found && i < q->nr; i++) {
if (match_filter(options, q->queue[i]))
Expand Down
5 changes: 4 additions & 1 deletion diff.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,15 @@ enum diff_words_type {
};

struct diff_options {
const char *filter;
const char *orderfile;
const char *pickaxe;
const char *single_follow;
const char *a_prefix, *b_prefix;
unsigned flags;

/* diff-filter bits */
unsigned int filter;

int use_color;
int context;
int interhunkcontext;
Expand Down

0 comments on commit 1ecc1cb

Please sign in to comment.