From: "René Scharfe" <rene.scharfe@lsrfire.ath.cx>
To: Marco Costalba <mcostalba@gmail.com>
Cc: Git Mailing List <git@vger.kernel.org>,
Junio C Hamano <gitster@pobox.com>,
Johannes Schindelin <Johannes.Schindelin@gmx.de>
Subject: Re: [PATCH] Avoid a useless prefix lookup in strbuf_expand()
Date: Thu, 03 Jan 2008 01:45:17 +0100 [thread overview]
Message-ID: <477C301D.7060509@lsrfire.ath.cx> (raw)
In-Reply-To: <e5bfff550801021027i6d6a399cob96ae3c840661884@mail.gmail.com>
Marco Costalba schrieb:
> If we go on complex stuff then we can bite the bullet and use a text
> matcher state machine, but again, I still think that the best way is
> to avoid the 99% unusless loop and use only a (slightly) beefed up
> switch case instead.
>
> I would think you agree with me that searching if a string is found in
> a string vector then pass the _same_ string to another function that
> (practically) redoes *the same* check using a switch statement is not
> the best optimization one can think about.
The loop makes implementing the callback function a bit easier, since
you don't need to cover all cases; the input is already checked by
strbuf_expand().
Anyway, here's your patch again with a few small changes: the
placeholders array is gone as you suggested, the cases for %Cx, %ax and
%cx are check for unknown placeholders and the callback function returns
the number of bytes it consumed as size_t.
All in all: less code, slightly more complex callback functions (needs
to return the length of the consumed placeholder or 0 if the input
doesn't match a placeholder) and increased speed. I have to admit that
I start to like it. :-)
I tried to cover all cases of valid and invalid input; did I miss any?
René
pretty.c | 143 ++++++++++++++++++++++++++------------------------------------
strbuf.c | 19 ++++-----
strbuf.h | 4 +-
3 files changed, 70 insertions(+), 96 deletions(-)
diff --git a/pretty.c b/pretty.c
index 5b1078b..c0e9c8a 100644
--- a/pretty.c
+++ b/pretty.c
@@ -282,8 +282,8 @@ static char *logmsg_reencode(const struct commit *commit,
return out;
}
-static void format_person_part(struct strbuf *sb, char part,
- const char *msg, int len)
+static size_t format_person_part(struct strbuf *sb, char part,
+ const char *msg, int len)
{
int start, end, tz = 0;
unsigned long date;
@@ -297,36 +297,36 @@ static void format_person_part(struct strbuf *sb, char part,
end--;
if (part == 'n') { /* name */
strbuf_add(sb, msg, end);
- return;
+ return 1;
}
if (start >= len)
- return;
+ return 1;
/* parse email */
for (end = start + 1; end < len && msg[end] != '>'; end++)
; /* do nothing */
if (end >= len)
- return;
+ return 1;
if (part == 'e') { /* email */
strbuf_add(sb, msg + start, end - start);
- return;
+ return 1;
}
/* parse date */
for (start = end + 1; start < len && isspace(msg[start]); start++)
; /* do nothing */
if (start >= len)
- return;
+ return 1;
date = strtoul(msg + start, &ep, 10);
if (msg + start == ep)
- return;
+ return 1;
if (part == 't') { /* date, UNIX timestamp */
strbuf_add(sb, msg + start, ep - (msg + start));
- return;
+ return 1;
}
/* parse tz */
@@ -341,17 +341,19 @@ static void format_person_part(struct strbuf *sb, char part,
switch (part) {
case 'd': /* date */
strbuf_addstr(sb, show_date(date, tz, DATE_NORMAL));
- return;
+ return 1;
case 'D': /* date, RFC2822 style */
strbuf_addstr(sb, show_date(date, tz, DATE_RFC2822));
- return;
+ return 1;
case 'r': /* date, relative */
strbuf_addstr(sb, show_date(date, tz, DATE_RELATIVE));
- return;
+ return 1;
case 'i': /* date, ISO 8601 */
strbuf_addstr(sb, show_date(date, tz, DATE_ISO8601));
- return;
+ return 1;
}
+
+ return 0; /* unknown person part */
}
struct chunk {
@@ -432,8 +434,8 @@ static void parse_commit_header(struct format_commit_context *context)
context->commit_header_parsed = 1;
}
-static void format_commit_item(struct strbuf *sb, const char *placeholder,
- void *context)
+static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
+ void *context)
{
struct format_commit_context *c = context;
const struct commit *commit = c->commit;
@@ -443,23 +445,23 @@ static void format_commit_item(struct strbuf *sb, const char *placeholder,
/* these are independent of the commit */
switch (placeholder[0]) {
case 'C':
- switch (placeholder[3]) {
- case 'd': /* red */
+ if (!prefixcmp(placeholder + 1, "red")) {
strbuf_addstr(sb, "\033[31m");
- return;
- case 'e': /* green */
+ return 4;
+ } else if (!prefixcmp(placeholder + 1, "green")) {
strbuf_addstr(sb, "\033[32m");
- return;
- case 'u': /* blue */
+ return 6;
+ } else if (!prefixcmp(placeholder + 1, "blue")) {
strbuf_addstr(sb, "\033[34m");
- return;
- case 's': /* reset color */
+ return 5;
+ } else if (!prefixcmp(placeholder + 1, "reset")) {
strbuf_addstr(sb, "\033[m");
- return;
- }
+ return 6;
+ } else
+ return 0;
case 'n': /* newline */
strbuf_addch(sb, '\n');
- return;
+ return 1;
}
/* these depend on the commit */
@@ -469,34 +471,34 @@ static void format_commit_item(struct strbuf *sb, const char *placeholder,
switch (placeholder[0]) {
case 'H': /* commit hash */
strbuf_addstr(sb, sha1_to_hex(commit->object.sha1));
- return;
+ return 1;
case 'h': /* abbreviated commit hash */
if (add_again(sb, &c->abbrev_commit_hash))
- return;
+ return 1;
strbuf_addstr(sb, find_unique_abbrev(commit->object.sha1,
DEFAULT_ABBREV));
c->abbrev_commit_hash.len = sb->len - c->abbrev_commit_hash.off;
- return;
+ return 1;
case 'T': /* tree hash */
strbuf_addstr(sb, sha1_to_hex(commit->tree->object.sha1));
- return;
+ return 1;
case 't': /* abbreviated tree hash */
if (add_again(sb, &c->abbrev_tree_hash))
- return;
+ return 1;
strbuf_addstr(sb, find_unique_abbrev(commit->tree->object.sha1,
DEFAULT_ABBREV));
c->abbrev_tree_hash.len = sb->len - c->abbrev_tree_hash.off;
- return;
+ return 1;
case 'P': /* parent hashes */
for (p = commit->parents; p; p = p->next) {
if (p != commit->parents)
strbuf_addch(sb, ' ');
strbuf_addstr(sb, sha1_to_hex(p->item->object.sha1));
}
- return;
+ return 1;
case 'p': /* abbreviated parent hashes */
if (add_again(sb, &c->abbrev_parent_hashes))
- return;
+ return 1;
for (p = commit->parents; p; p = p->next) {
if (p != commit->parents)
strbuf_addch(sb, ' ');
@@ -505,14 +507,14 @@ static void format_commit_item(struct strbuf *sb, const char *placeholder,
}
c->abbrev_parent_hashes.len = sb->len -
c->abbrev_parent_hashes.off;
- return;
+ return 1;
case 'm': /* left/right/bottom */
strbuf_addch(sb, (commit->object.flags & BOUNDARY)
? '-'
: (commit->object.flags & SYMMETRIC_LEFT)
? '<'
: '>');
- return;
+ return 1;
}
/* For the rest we have to parse the commit header. */
@@ -520,66 +522,41 @@ static void format_commit_item(struct strbuf *sb, const char *placeholder,
parse_commit_header(c);
switch (placeholder[0]) {
- case 's':
+ case 's': /* subject */
strbuf_add(sb, msg + c->subject.off, c->subject.len);
- return;
- case 'a':
- format_person_part(sb, placeholder[1],
- msg + c->author.off, c->author.len);
- return;
- case 'c':
- format_person_part(sb, placeholder[1],
- msg + c->committer.off, c->committer.len);
- return;
- case 'e':
+ return 1;
+ case 'a': /* author ... */
+ if (format_person_part(sb, placeholder[1],
+ msg + c->author.off,
+ c->author.len))
+ return 2;
+ else
+ return 0;
+ case 'c': /* committer ... */
+ if (format_person_part(sb, placeholder[1],
+ msg + c->committer.off,
+ c->committer.len))
+ return 2;
+ else
+ return 0;
+ case 'e': /* encoding */
strbuf_add(sb, msg + c->encoding.off, c->encoding.len);
- return;
- case 'b':
+ return 1;
+ case 'b': /* body */
strbuf_addstr(sb, msg + c->body_off);
- return;
+ return 1;
}
+ return 0; /* unknown placeholder */
}
void format_commit_message(const struct commit *commit,
const void *format, struct strbuf *sb)
{
- const char *placeholders[] = {
- "H", /* commit hash */
- "h", /* abbreviated commit hash */
- "T", /* tree hash */
- "t", /* abbreviated tree hash */
- "P", /* parent hashes */
- "p", /* abbreviated parent hashes */
- "an", /* author name */
- "ae", /* author email */
- "ad", /* author date */
- "aD", /* author date, RFC2822 style */
- "ar", /* author date, relative */
- "at", /* author date, UNIX timestamp */
- "ai", /* author date, ISO 8601 */
- "cn", /* committer name */
- "ce", /* committer email */
- "cd", /* committer date */
- "cD", /* committer date, RFC2822 style */
- "cr", /* committer date, relative */
- "ct", /* committer date, UNIX timestamp */
- "ci", /* committer date, ISO 8601 */
- "e", /* encoding */
- "s", /* subject */
- "b", /* body */
- "Cred", /* red */
- "Cgreen", /* green */
- "Cblue", /* blue */
- "Creset", /* reset color */
- "n", /* newline */
- "m", /* left/right/bottom */
- NULL
- };
struct format_commit_context context;
memset(&context, 0, sizeof(context));
context.commit = commit;
- strbuf_expand(sb, format, placeholders, format_commit_item, &context);
+ strbuf_expand(sb, format, format_commit_item, &context);
}
static void pp_header(enum cmit_fmt fmt,
diff --git a/strbuf.c b/strbuf.c
index b9b194b..7bb087c 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -137,11 +137,12 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
strbuf_setlen(sb, sb->len + len);
}
-void strbuf_expand(struct strbuf *sb, const char *format,
- const char **placeholders, expand_fn_t fn, void *context)
+void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn,
+ void *context)
{
for (;;) {
- const char *percent, **p;
+ const char *percent;
+ size_t consumed;
percent = strchrnul(format, '%');
strbuf_add(sb, format, percent - format);
@@ -149,14 +150,10 @@ void strbuf_expand(struct strbuf *sb, const char *format,
break;
format = percent + 1;
- for (p = placeholders; *p; p++) {
- if (!prefixcmp(format, *p))
- break;
- }
- if (*p) {
- fn(sb, *p, context);
- format += strlen(*p);
- } else
+ consumed = fn(sb, format, context);
+ if (consumed)
+ format += consumed;
+ else
strbuf_addch(sb, '%');
}
}
diff --git a/strbuf.h b/strbuf.h
index 36d61db..faec229 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -103,8 +103,8 @@ static inline void strbuf_addbuf(struct strbuf *sb, struct strbuf *sb2) {
}
extern void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len);
-typedef void (*expand_fn_t) (struct strbuf *sb, const char *placeholder, void *context);
-extern void strbuf_expand(struct strbuf *sb, const char *format, const char **placeholders, expand_fn_t fn, void *context);
+typedef size_t (*expand_fn_t) (struct strbuf *sb, const char *placeholder, void *context);
+extern void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn, void *context);
__attribute__((format(printf,2,3)))
extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...);
next prev parent reply other threads:[~2008-01-03 0:46 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-12-30 13:46 [PATCH] Avoid a useless prefix lookup in strbuf_expand() Marco Costalba
2008-01-02 18:11 ` René Scharfe
[not found] ` <e5bfff550801021027i6d6a399cob96ae3c840661884@mail.gmail.com>
2008-01-03 0:45 ` René Scharfe [this message]
2008-01-03 9:08 ` Junio C Hamano
2008-01-03 10:06 ` Marco Costalba
-- strict thread matches above, loose matches on Subject: below --
2008-01-06 0:10 Marco Costalba
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=477C301D.7060509@lsrfire.ath.cx \
--to=rene.scharfe@lsrfire.ath.cx \
--cc=Johannes.Schindelin@gmx.de \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=mcostalba@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).