Avoid a useless prefix lookup in strbuf_expand()
Currently, the --pretty=format prefix is looked up in a tight loop in strbuf_expand(), if prefix is found it is then used as argument for format_commit_item() that does another search by a switch statement to select the proper operation. Because the switch statement is already able to discard unknown matches we don't need the prefix lookup before to call format_commit_item(). Signed-off-by: Marco Costalba <mcostalba@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Marco Costalba committed
Feb 9, 2008 at 15:40 UTC
c3a670de50589dedf2d9b83305e8bd0ff63a1a60
3 files changed
+83
-108
pretty.c
+73
-95
@@ -282,59 +282,59 @@ static char *logmsg_reencode(const struct commit *commit,
282
return out;
283
}
284
285
-static void format_person_part(struct strbuf *sb, char part,
285
+static size_t format_person_part(struct strbuf *sb, char part,
286
const char *msg, int len)
287
{
288
+ /* currently all placeholders have same length */
289
+ const int placeholder_len = 2;
290
int start, end, tz = 0;
289
- unsigned long date;
291
+ unsigned long date = 0;
292
char *ep;
293
292
- /* parse name */
294
+ /* advance 'end' to point to email start delimiter */
295
for (end = 0; end < len && msg[end] != '<'; end++)
296
; /* do nothing */
297
+
298
/*
296
- * If it does not even have a '<' and '>', that is
297
- * quite a bogus commit author and we discard it;
298
- * this is in line with add_user_info() that is used
299
- * in the normal codepath. When end points at the '<'
300
- * that we found, it should have matching '>' later,
301
- * which means start (beginning of email address) must
302
- * be strictly below len.
299
+ * When end points at the '<' that we found, it should have
300
+ * matching '>' later, which means 'end' must be strictly
301
+ * below len - 1.
302
*/
304
- start = end + 1;
305
- if (start >= len - 1)
306
- return;
307
- while (end > 0 && isspace(msg[end - 1]))
308
- end--;
303
+ if (end >= len - 2)
304
+ goto skip;
305
+
306
if (part == 'n') { /* name */
307
+ while (end > 0 && isspace(msg[end - 1]))
308
+ end--;
309
strbuf_add(sb, msg, end);
311
- return;
310
+ return placeholder_len;
311
}
312
+ start = ++end; /* save email start position */
313
314
- /* parse email */
315
- for (end = start; end < len && msg[end] != '>'; end++)
314
+ /* advance 'end' to point to email end delimiter */
315
+ for ( ; end < len && msg[end] != '>'; end++)
316
; /* do nothing */
317
318
if (end >= len)
319
- return;
319
+ goto skip;
320
321
if (part == 'e') { /* email */
322
strbuf_add(sb, msg + start, end - start);
323
- return;
323
+ return placeholder_len;
324
}
325
326
- /* parse date */
326
+ /* advance 'start' to point to date start delimiter */
327
for (start = end + 1; start < len && isspace(msg[start]); start++)
328
; /* do nothing */
329
if (start >= len)
330
- return;
330
+ goto skip;
331
date = strtoul(msg + start, &ep, 10);
332
if (msg + start == ep)
333
- return;
333
+ goto skip;
334
335
if (part == 't') { /* date, UNIX timestamp */
336
strbuf_add(sb, msg + start, ep - (msg + start));
337
- return;
337
+ return placeholder_len;
338
}
339
340
/* parse tz */
@@ -349,17 +349,28 @@ static void format_person_part(struct strbuf *sb, char part,
349
switch (part) {
350
case 'd': /* date */
351
strbuf_addstr(sb, show_date(date, tz, DATE_NORMAL));
352
- return;
352
+ return placeholder_len;
353
case 'D': /* date, RFC2822 style */
354
strbuf_addstr(sb, show_date(date, tz, DATE_RFC2822));
355
- return;
355
+ return placeholder_len;
356
case 'r': /* date, relative */
357
strbuf_addstr(sb, show_date(date, tz, DATE_RELATIVE));
358
- return;
358
+ return placeholder_len;
359
case 'i': /* date, ISO 8601 */
360
strbuf_addstr(sb, show_date(date, tz, DATE_ISO8601));
361
- return;
361
+ return placeholder_len;
362
}
363
+
364
+skip:
365
+ /*
366
+ * bogus commit, 'sb' cannot be updated, but we still need to
367
+ * compute a valid return value.
368
+ */
369
+ if (part == 'n' || part == 'e' || part == 't' || part == 'd'
370
+ || part == 'D' || part == 'r' || part == 'i')
371
+ return placeholder_len;
372
+
373
+ return 0; /* unknown placeholder */
374
}
375
376
struct chunk {
@@ -440,7 +451,7 @@ static void parse_commit_header(struct format_commit_context *context)
451
context->commit_header_parsed = 1;
452
}
453
443
-static void format_commit_item(struct strbuf *sb, const char *placeholder,
454
+static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
455
void *context)
456
{
457
struct format_commit_context *c = context;
@@ -451,23 +462,23 @@ static void format_commit_item(struct strbuf *sb, const char *placeholder,
462
/* these are independent of the commit */
463
switch (placeholder[0]) {
464
case 'C':
454
- switch (placeholder[3]) {
455
- case 'd': /* red */
465
+ if (!prefixcmp(placeholder + 1, "red")) {
466
strbuf_addstr(sb, "\033[31m");
457
- return;
458
- case 'e': /* green */
467
+ return 4;
468
+ } else if (!prefixcmp(placeholder + 1, "green")) {
469
strbuf_addstr(sb, "\033[32m");
460
- return;
461
- case 'u': /* blue */
470
+ return 6;
471
+ } else if (!prefixcmp(placeholder + 1, "blue")) {
472
strbuf_addstr(sb, "\033[34m");
463
- return;
464
- case 's': /* reset color */
473
+ return 5;
474
+ } else if (!prefixcmp(placeholder + 1, "reset")) {
475
strbuf_addstr(sb, "\033[m");
466
- return;
467
- }
476
+ return 6;
477
+ } else
478
+ return 0;
479
case 'n': /* newline */
480
strbuf_addch(sb, '\n');
470
- return;
481
+ return 1;
482
}
483
484
/* these depend on the commit */
@@ -477,34 +488,34 @@ static void format_commit_item(struct strbuf *sb, const char *placeholder,
488
switch (placeholder[0]) {
489
case 'H': /* commit hash */
490
strbuf_addstr(sb, sha1_to_hex(commit->object.sha1));
480
- return;
491
+ return 1;
492
case 'h': /* abbreviated commit hash */
493
if (add_again(sb, &c->abbrev_commit_hash))
483
- return;
494
+ return 1;
495
strbuf_addstr(sb, find_unique_abbrev(commit->object.sha1,
496
DEFAULT_ABBREV));
497
c->abbrev_commit_hash.len = sb->len - c->abbrev_commit_hash.off;
487
- return;
498
+ return 1;
499
case 'T': /* tree hash */
500
strbuf_addstr(sb, sha1_to_hex(commit->tree->object.sha1));
490
- return;
501
+ return 1;
502
case 't': /* abbreviated tree hash */
503
if (add_again(sb, &c->abbrev_tree_hash))
493
- return;
504
+ return 1;
505
strbuf_addstr(sb, find_unique_abbrev(commit->tree->object.sha1,
506
DEFAULT_ABBREV));
507
c->abbrev_tree_hash.len = sb->len - c->abbrev_tree_hash.off;
497
- return;
508
+ return 1;
509
case 'P': /* parent hashes */
510
for (p = commit->parents; p; p = p->next) {
511
if (p != commit->parents)
512
strbuf_addch(sb, ' ');
513
strbuf_addstr(sb, sha1_to_hex(p->item->object.sha1));
514
}
504
- return;
515
+ return 1;
516
case 'p': /* abbreviated parent hashes */
517
if (add_again(sb, &c->abbrev_parent_hashes))
507
- return;
518
+ return 1;
519
for (p = commit->parents; p; p = p->next) {
520
if (p != commit->parents)
521
strbuf_addch(sb, ' ');
@@ -513,14 +524,14 @@ static void format_commit_item(struct strbuf *sb, const char *placeholder,
524
}
525
c->abbrev_parent_hashes.len = sb->len -
526
c->abbrev_parent_hashes.off;
516
- return;
527
+ return 1;
528
case 'm': /* left/right/bottom */
529
strbuf_addch(sb, (commit->object.flags & BOUNDARY)
530
? '-'
531
: (commit->object.flags & SYMMETRIC_LEFT)
532
? '<'
533
: '>');
523
- return;
534
+ return 1;
535
}
536
537
/* For the rest we have to parse the commit header. */
@@ -528,66 +539,33 @@ static void format_commit_item(struct strbuf *sb, const char *placeholder,
539
parse_commit_header(c);
540
541
switch (placeholder[0]) {
531
- case 's':
542
+ case 's': /* subject */
543
strbuf_add(sb, msg + c->subject.off, c->subject.len);
533
- return;
534
- case 'a':
535
- format_person_part(sb, placeholder[1],
544
+ return 1;
545
+ case 'a': /* author ... */
546
+ return format_person_part(sb, placeholder[1],
547
msg + c->author.off, c->author.len);
537
- return;
538
- case 'c':
539
- format_person_part(sb, placeholder[1],
548
+ case 'c': /* committer ... */
549
+ return format_person_part(sb, placeholder[1],
550
msg + c->committer.off, c->committer.len);
541
- return;
542
- case 'e':
551
+ case 'e': /* encoding */
552
strbuf_add(sb, msg + c->encoding.off, c->encoding.len);
544
- return;
545
- case 'b':
553
+ return 1;
554
+ case 'b': /* body */
555
strbuf_addstr(sb, msg + c->body_off);
547
- return;
556
+ return 1;
557
}
558
+ return 0; /* unknown placeholder */
559
}
560
561
void format_commit_message(const struct commit *commit,
562
const void *format, struct strbuf *sb)
563
{
554
- const char *placeholders[] = {
555
- "H", /* commit hash */
556
- "h", /* abbreviated commit hash */
557
- "T", /* tree hash */
558
- "t", /* abbreviated tree hash */
559
- "P", /* parent hashes */
560
- "p", /* abbreviated parent hashes */
561
- "an", /* author name */
562
- "ae", /* author email */
563
- "ad", /* author date */
564
- "aD", /* author date, RFC2822 style */
565
- "ar", /* author date, relative */
566
- "at", /* author date, UNIX timestamp */
567
- "ai", /* author date, ISO 8601 */
568
- "cn", /* committer name */
569
- "ce", /* committer email */
570
- "cd", /* committer date */
571
- "cD", /* committer date, RFC2822 style */
572
- "cr", /* committer date, relative */
573
- "ct", /* committer date, UNIX timestamp */
574
- "ci", /* committer date, ISO 8601 */
575
- "e", /* encoding */
576
- "s", /* subject */
577
- "b", /* body */
578
- "Cred", /* red */
579
- "Cgreen", /* green */
580
- "Cblue", /* blue */
581
- "Creset", /* reset color */
582
- "n", /* newline */
583
- "m", /* left/right/bottom */
584
- NULL
585
- };
564
struct format_commit_context context;
565
566
memset(&context, 0, sizeof(context));
567
context.commit = commit;
590
- strbuf_expand(sb, format, placeholders, format_commit_item, &context);
568
+ strbuf_expand(sb, format, format_commit_item, &context);
569
}
570
571
static void pp_header(enum cmit_fmt fmt,
strbuf.c
+8
-11
@@ -146,11 +146,12 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
146
strbuf_setlen(sb, sb->len + len);
147
}
148
149
-void strbuf_expand(struct strbuf *sb, const char *format,
150
- const char **placeholders, expand_fn_t fn, void *context)
149
+void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn,
150
+ void *context)
151
{
152
for (;;) {
153
- const char *percent, **p;
153
+ const char *percent;
154
+ size_t consumed;
155
156
percent = strchrnul(format, '%');
157
strbuf_add(sb, format, percent - format);
@@ -158,14 +159,10 @@ void strbuf_expand(struct strbuf *sb, const char *format,
159
break;
160
format = percent + 1;
161
161
- for (p = placeholders; *p; p++) {
162
- if (!prefixcmp(format, *p))
163
- break;
164
- }
165
- if (*p) {
166
- fn(sb, *p, context);
167
- format += strlen(*p);
168
- } else
162
+ consumed = fn(sb, format, context);
163
+ if (consumed)
164
+ format += consumed;
165
+ else
166
strbuf_addch(sb, '%');
167
}
168
}
strbuf.h
+2
-2
@@ -103,8 +103,8 @@ static inline void strbuf_addbuf(struct strbuf *sb, struct strbuf *sb2) {
103
}
104
extern void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len);
105
106
-typedef void (*expand_fn_t) (struct strbuf *sb, const char *placeholder, void *context);
107
-extern void strbuf_expand(struct strbuf *sb, const char *format, const char **placeholders, expand_fn_t fn, void *context);
106
+typedef size_t (*expand_fn_t) (struct strbuf *sb, const char *placeholder, void *context);
107
+extern void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn, void *context);
108
109
__attribute__((format(printf,2,3)))
110
extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...);