Commit 73eb9a8
Avoid per-entry array allocation in Request#build_headers
`build_headers` walked the env with `each_header.with_object(...)`. Because
`Enumerator#with_object` hands the block a single value plus the memo, the
two values `each_header` yields (`k`, `v`) get boxed into a throwaway
`[k, v]` Array on every iteration — which the `|(k, v), headers|` destructure
then immediately unpacks. That is one array allocated, packed, destructured,
and discarded per request header.
Drop `with_object` for a plain `each_header do |k, v|` block writing into a
pre-built `Grape::Util::Header`. `k` and `v` arrive as separate block args
(normal multi-value yield), so no array is boxed, and the accumulator is just
a closed-over local.
Output is byte-identical (`each_header` is `Rack::Request::Env#each_header`,
i.e. full env iteration; the `HTTP_` filter is unchanged). `build_headers`
runs lazily, only when an endpoint reads `headers`.
Measured on a request with ~30 headers: ~43% fewer objects (37 -> 21 per
call) and ~1.36x faster, with the array packing — not the Enumerator object
itself — accounting for the entire gap.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>1 parent 6995daf commit 73eb9a8
2 files changed
Lines changed: 8 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
| 5 | + | |
5 | 6 | | |
6 | 7 | | |
7 | 8 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
177 | 177 | | |
178 | 178 | | |
179 | 179 | | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
180 | 184 | | |
181 | | - | |
| 185 | + | |
| 186 | + | |
182 | 187 | | |
183 | 188 | | |
184 | 189 | | |
185 | 190 | | |
186 | 191 | | |
| 192 | + | |
187 | 193 | | |
188 | 194 | | |
189 | 195 | | |
0 commit comments