parse_config: use getline. BIG speedup with glibc (~40%).

function                                             old     new   delta
config_read                                          559     604     +45
getline                                                -      23     +23
config_close                                          29      49     +20
find_pair                                            169     187     +18
showmode                                             330     338      +8
hash_find                                            233     234      +1
builtin_umask                                        133     132      -1
lzo1x_optimize                                      1434    1429      -5
test_main                                            253     247      -6
buffer_fill_and_print                                196     179     -17
create_J                                            1849    1826     -23
config_free_data                                      37       -     -37
------------------------------------------------------------------------------
(add/remove: 3/1 grow/shrink: 5/5 up/down: 138/-89)            Total: 26 bytes

Signed-off-by: Timo Teras <timo.teras@iki.fi>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Timo Teras 2011-06-20 09:49:56 +02:00 committed by Denys Vlasenko
parent e12e0acb92
commit adcabf3235
2 changed files with 44 additions and 49 deletions

View File

@ -1184,8 +1184,9 @@ enum {
}; };
typedef struct parser_t { typedef struct parser_t {
FILE *fp; FILE *fp;
char *line;
char *data; char *data;
char *line, *nline;
size_t line_alloc, nline_alloc;
int lineno; int lineno;
} parser_t; } parser_t;
parser_t* config_open(const char *filename) FAST_FUNC; parser_t* config_open(const char *filename) FAST_FUNC;

View File

@ -83,60 +83,55 @@ parser_t* FAST_FUNC config_open(const char *filename)
return config_open2(filename, fopen_or_warn_stdin); return config_open2(filename, fopen_or_warn_stdin);
} }
static void config_free_data(parser_t *parser)
{
free(parser->line);
parser->line = NULL;
if (PARSE_KEEP_COPY) { /* compile-time constant */
free(parser->data);
parser->data = NULL;
}
}
void FAST_FUNC config_close(parser_t *parser) void FAST_FUNC config_close(parser_t *parser)
{ {
if (parser) { if (parser) {
config_free_data(parser); if (PARSE_KEEP_COPY) /* compile-time constant */
free(parser->data);
fclose(parser->fp); fclose(parser->fp);
free(parser->line);
free(parser->nline);
free(parser); free(parser);
} }
} }
/* This function reads an entire line from a text file, up to a newline /* This function reads an entire line from a text file,
* or NUL byte, exclusive. It returns a malloc'ed char*. * up to a newline, exclusive.
* *lineno is incremented for each line.
* Trailing '\' is recognized as line continuation. * Trailing '\' is recognized as line continuation.
* Returns NULL if EOF/error. * Returns -1 if EOF/error.
*/ */
static char* get_line_with_continuation(FILE *file, int *lineno) static int get_line_with_continuation(parser_t *parser)
{ {
int ch; ssize_t len, nlen;
unsigned idx = 0; char *line;
char *linebuf = NULL;
while ((ch = getc(file)) != EOF) { len = getline(&parser->line, &parser->line_alloc, parser->fp);
/* grow the line buffer as necessary */ if (len <= 0)
if (!(idx & 0xff)) return len;
linebuf = xrealloc(linebuf, idx + 0x101);
if (ch == '\n') line = parser->line;
ch = '\0'; for (;;) {
linebuf[idx] = (char) ch; parser->lineno++;
if (ch == '\0') { if (line[len - 1] == '\n')
(*lineno)++; len--;
if (idx == 0 || linebuf[idx-1] != '\\') if (len == 0 || line[len - 1] != '\\')
break; break;
idx--; /* go back to '/' */ len--;
continue;
nlen = getline(&parser->nline, &parser->nline_alloc, parser->fp);
if (nlen <= 0)
break;
if (parser->line_alloc < len + nlen + 1) {
parser->line_alloc = len + nlen + 1;
line = parser->line = xrealloc(line, parser->line_alloc);
} }
idx++; memcpy(&line[len], parser->nline, nlen);
len += nlen;
} }
if (ch == EOF) {
/* handle corner case when the file is not ended with '\n' */ line[len] = '\0';
(*lineno)++; return len;
if (linebuf)
linebuf[idx] = '\0';
}
return linebuf;
} }
@ -176,15 +171,14 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const
ntokens = (uint8_t)flags; ntokens = (uint8_t)flags;
mintokens = (uint8_t)(flags >> 8); mintokens = (uint8_t)(flags >> 8);
again: again:
memset(tokens, 0, sizeof(tokens[0]) * ntokens); memset(tokens, 0, sizeof(tokens[0]) * ntokens);
config_free_data(parser);
/* Read one line (handling continuations with backslash) */ /* Read one line (handling continuations with backslash) */
line = get_line_with_continuation(parser->fp, &parser->lineno); if (get_line_with_continuation(parser) < 0)
if (line == NULL)
return 0; return 0;
parser->line = line;
line = parser->line;
/* Skip token in the start of line? */ /* Skip token in the start of line? */
if (flags & PARSE_TRIM) if (flags & PARSE_TRIM)
@ -193,8 +187,10 @@ again:
if (line[0] == '\0' || line[0] == delims[0]) if (line[0] == '\0' || line[0] == delims[0])
goto again; goto again;
if (flags & PARSE_KEEP_COPY) if (flags & PARSE_KEEP_COPY) {
free(parser->data);
parser->data = xstrdup(line); parser->data = xstrdup(line);
}
/* Tokenize the line */ /* Tokenize the line */
t = 0; t = 0;
@ -240,8 +236,6 @@ again:
parser->lineno, t, mintokens); parser->lineno, t, mintokens);
if (flags & PARSE_MIN_DIE) if (flags & PARSE_MIN_DIE)
xfunc_die(); xfunc_die();
if (flags & PARSE_KEEP_COPY)
free(parser->data);
goto again; goto again;
} }