Speed up lookup by ~13% (template callbacks + root dispatch table)#17
Merged
Conversation
…able Two format-neutral changes to the read path (the byte code is unchanged and stays fully compatible): - matcher::match takes its output/prefix callbacks as template parameters instead of std::function, so no std::function is constructed per query and the calls inline. exact/common-prefix search on /usr/share/dict/words drop ~13%. - Each matcher precomputes a 256-entry label->address dispatch table for the root state at construction time, replacing the root's jump table binary search (every query passes through the root) with an O(1) lookup. Costs 1KB of memory per matcher; the file is untouched.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two format-neutral optimizations to the read path. The compiled byte code is unchanged (byte-identical output; existing
.fstfiles stay fully compatible), so this only touches how amatchertraverses it.matcher::match. The output/prefix callbacks werestd::function, so every query constructed astd::functionand called through it indirectly. They are now template parameters (withstd::nullptr_tdefaults andif constexprguards), so nothing is allocated per query and the calls inline.map::common_prefix_search/set::common_prefix_searchare templatized to match (lambda callers are unaffected).matchernow precomputes a 256-entrylabel -> addresstable for the root at construction time, making that step O(1). Costs ~1 KB of memory per matcher; the file is untouched.Measurements
benchmark/main.ccon/usr/share/dict/words(235,976 keys, Apple M1 Pro), min of 12 runs:Compiled FST size is identical before/after (1,070,382 bytes for
map<uint32_t>), confirming the byte code is unchanged.Testing
ctest: 36/36 pass.