Repository navigation
Optimize Integer.parse/2 by matching digit ranges - #16037
Conversation
Replacing the 62 unrolled character clauses with range guards and a base-10 fast path eliminates a 75-entry indirect jump table across 36 branch targets, allowing the JIT to fuse bounds checks into is_in_range and use tagless, overflow-free arithmetic with the 2..36 base type bounds. Matching the first digit directly in count_digits/2 also avoids bitstring position backtracking on unsigned inputs, while the count == byte_size(binary) fast path skips :erlang.split_binary/2 and its tuple/sub-binary allocation when the entire binary is parsed. Assisted-by: Antigravity:Gemini-4-Argon
|
Assisted-by: Claude Code 2.1.311:claude-opus-5-5 Independent verification of this PR on a different machine (AMD Ryzen 7 7735HS, Elixir 1.20.4, OTP 29.1.1, JIT). Correctness: fuzzed Benchmark: the script from the description plus a few extra inputs, run twice with longer settings (2s warmup / 5s time, then 3s warmup / 15s time). Speedup of the PR over the baseline:
Faster or equal on every input in both runs. Short all-digit inputs are consistently 1.25–1.65x; long inputs vary run to run (bignum allocation/GC) but were always ≥1.2x. Short inputs with a remainder are roughly even, as expected since the Suggestion: the existing assert Integer.parse("78", 8) === {7, "8"}
assert Integer.parse("fg", 16) === {15, "g"}
assert Integer.parse("FF", 16) === {255, ""}
assert Integer.parse("zZ", 36) === {1295, ""}
assert Integer.parse("9", 9) === :error
assert Integer.parse("-g", 16) === :error
assert Integer.parse("Zz", 35) === :errorMinor: the |
Assisted-by: Antigravity:Gemini-4-Argon
Faster or same speed.
Lower or same memory usage.
.beam size same (slightly smaller)
Bench:
Results: