Skip to content

Avoid intermediate lists in URI query decoding - #15949

Closed
dkuku wants to merge 1 commit into
elixir-lang:mainfrom
dkuku:dk_avoid_intermediate_lists_in_query_decoder
Closed

dkuku wants to merge 1 commit into
elixir-lang:mainfrom
dkuku:dk_avoid_intermediate_lists_in_query_decoder

Conversation

@dkuku

@dkuku dkuku commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Instead of calling :binary.split/2 twice per key-value pair (once on & and once on =), decode query parameters directly using binary pattern matching (parse_next_key/4 and parse_next_val/5) and binary_part/3.

This eliminates 2 intermediate 2-element list allocations per query pair in URI.query_decoder/2 and URI.decode_query/1,2,3.

Passing sliced sub-binaries directly into decode_with_encoding/2 also opens the door to a future fast path in URI.decode/1 and URI.decode_www_form/1 (e.g. returning the sub-binary directly without copying or decoding when no percent escapes or plus signs are present).

Benchmarks (Benchee, OTP 29)

URI.decode_query
  • typical (4 params): 1.10M ips (0.91 μs) vs Baseline 0.50M ips (2.02 μs) — 2.22x faster
  • encoded (3 params): 868K ips (1.15 μs) vs Baseline 735K ips (1.36 μs) — 1.18x faster
  • large (30 params): 49.9K ips (20.04 μs) vs Baseline 40.8K ips (24.51 μs) — 1.22x faster, 1.06x less memory
URI.query_decoder |> Enum.to_list
  • typical (4 params): 893K ips (1.12 μs) vs Baseline 598K ips (1.67 μs) — 1.49x faster
  • encoded (3 params): 874K ips (1.14 μs) vs Baseline 728K ips (1.37 μs) — 1.20x faster
  • large (30 params): 67.0K ips (14.93 μs) vs Baseline 60.1K ips (16.64 μs) — 1.11x faster, 1.14x less memory

Assisted-by: Antigravity:Gemini 3.8 Flash

Instead of calling :binary.split/2 twice per key-value pair
(once on "&" and once on "="), decode query parameters directly
using binary pattern matching and binary_part/3.

This eliminates 2 intermediate list allocations per query pair
in URI.query_decoder/2 and URI.decode_query/1,2,3.

Assisted-by: Antigravity:Gemini 3.8 Flash
@josevalim

Copy link
Copy Markdown
Member

Thanks but I will stick to the current patch. It is simpler and it can leverage simd. I also have patches to OTP that optimize split so it may get faster in future versions!

@josevalim josevalim closed this Sep 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants