diff --git a/src/scanner-utils.c b/src/scanner-utils.c index 8aafb528f..2a4db6c7d 100644 --- a/src/scanner-utils.c +++ b/src/scanner-utils.c @@ -31,16 +31,32 @@ scanner_token_location(struct scanner *s) * https://lemire.me/blog/2017/02/14/how-fast-can-you-count-lines/ * https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/blob/master/2017/02/14/newlines.c * This is the fastest portable one for me, and it's simple. + * + * To avoid rescanning on each call, cache the previously found position + * and start from that on the next call. This is effective as long as the + * tokens go forward. */ - size_t line = 1, column; + size_t line, column; size_t line_pos = 0; - const char *ptr = s->s; + if (s->cached_pos > s->token_pos) { + s->cached_pos = 0; + s->cached_loc.line = s->cached_loc.column = 1; + } + line = s->cached_loc.line; + const char *ptr = s->s + s->cached_pos; const char *last = s->s + s->token_pos; while ((ptr = memchr(ptr, '\n', last - ptr))) { line++; ptr++; line_pos = ptr - s->s; } - column = s->token_pos - line_pos + 1; - return (struct scanner_loc){.line = line, .column = column}; + if (line == s->cached_loc.line) { + column = s->cached_loc.column + (s->token_pos - s->cached_pos); + } else { + column = s->token_pos - line_pos + 1; + } + struct scanner_loc loc = {.line = line, .column = column}; + s->cached_pos = s->token_pos; + s->cached_loc = loc; + return loc; } diff --git a/src/scanner-utils.h b/src/scanner-utils.h index 6ab37451b..e2ef6c378 100644 --- a/src/scanner-utils.h +++ b/src/scanner-utils.h @@ -67,6 +67,9 @@ struct scanner { size_t buf_pos; /* The position of the start of the current token. */ size_t token_pos; + /* Cached values used by scanner_token_location. */ + size_t cached_pos; + struct scanner_loc cached_loc; const char *file_name; struct xkb_context *ctx; void *priv; @@ -106,6 +109,8 @@ scanner_init(struct scanner *s, struct xkb_context *ctx, s->len = len; s->pos = 0; s->token_pos = 0; + s->cached_pos = 0; + s->cached_loc.line = s->cached_loc.column = 1; s->file_name = file_name; s->ctx = ctx; s->priv = priv;