Compare header names case-insensitively without allocating - #49
Merged
Merged
Conversation
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.
header-lookupandheader-valueslower-cased every request header name on every call:String.ascii-to-loweron each key, so two allocations per header per lookup.Precondition.evaluatemakes up to four lookups, andRequest.headerandif-range-matches?make more, so a plain GET paid this many times over.This compares names case-insensitively in place instead: lengths first, then byte by byte with A–Z folded to a–z, the same folding
tolowerdoes in the C locale. It allocates nothing.Behaviour is unchanged. Old against new,
header-lookupandheader-valuesboth, gave 0 divergences over 135,137 queries. The header maps were built from every name of up to three bytes overa,A,z,Z,-,@,[,`and{, which are the bytes on either side of both letter ranges, plus two names with bytes above 127. The check catches a planted bug at either end of the folding range: not foldingZgives 707 divergences, folding[gives 976.Timing. Median of three runs, 200,000 calls each, on an M1 Max, against the headers of a typical browser GET (nine headers):
masterheader-lookup, header absent-O0-O1-O2-O3-Os--optimizeheader-values, header present-O0-O1-O2-O3-Os--optimizeThrough web 0.12.0's
web-build-response, from-O1up, a build with this change and carpentry-org/time#33'sstrptimechange is 0.4–0.5 µs faster on a plain GET and 0.1–0.2 µs faster on anIf-Modified-Sincerequest than one without them. The two changes were not measured apart there.Tests. Run with
-Werror: 516 passed, 0 failed. No test changed.anglerandcarp-fmt --check, both built from their current HEADs, are clean.carp -x gendocs.carpsucceeds.Request.parsestill lower-cases each header name once, to findCookie. It is not a lookup and is left alone here.