Each token now carries a small filter of the rule types present in its
memo list, so the common case of a miss no longer walks the list.
--- /dev/null
+Speed up the parser by letting memoization lookups that cannot match return
+immediately.
m->mark = p->mark;
m->next = p->tokens[mark]->memo;
p->tokens[mark]->memo = m;
+ p->tokens[mark]->memo_mask |= 1ULL << (type & 63);
return 0;
}
Token *t = p->tokens[p->mark];
+ if (!(t->memo_mask & (1ULL << (type & 63)))) {
+ return 0;
+ }
+
for (Memo *m = t->memo; m != NULL; m = m->next) {
if (m->type == type) {
#if defined(Py_DEBUG)
int level;
int lineno, col_offset, end_lineno, end_col_offset;
Memo *memo;
+ // Filter over the rule types present in `memo` (bit `type & 63` is set
+ // for every entry): lets lookups skip walking the list on definite
+ // misses, which are the common case.
+ uint64_t memo_mask;
PyObject *metadata;
} Token;