Repository navigation
Optimise integer parsing - #5859
Conversation
fishcakez
commented
Mar 10, 2017
- Use single binary match context
- Do minimal pattern matches and maths
| do_parse(rest, base, parse_digit(char)) | ||
| else | ||
| :error | ||
| digits = [{?0..?9, -?0}, {?A..?Z, 10-?A}, {?a..?z, 10-?a}] |
There was a problem hiding this comment.
We need spaces before/after -.
|
|
||
| for {chars, diff} <- digits, char <- chars do | ||
| defp parse_digits(<<unquote(char), rest::binary>>, base, sign) | ||
| when base > unquote(char+diff) do |
| def parse(binary, base) when is_binary(binary) and base in 2..36 do | ||
| parse_in_base(binary, base) | ||
| def parse(<<bin::binary>>, base) when base in 2..36 do | ||
| parse_sign(bin, base) |
There was a problem hiding this comment.
Would
{sign, rest} = parse_sign(bin)
parse_digits(rest, base, sign)work in the same way? We can keep it a bit more tidy by not calling parse_digits/3 from parse_sign/2. But maybe we do bad stuff with the binary context this way 🤔
There was a problem hiding this comment.
That would lose a binary match context optimisation.
There was a problem hiding this comment.
I feared so. Sad! It makes the code a bit convolute and it's really hard to get why just by reading it. Maybe we can add a comment about why it's done this way, not sure. We could in the meantime rename parse_sign/2 to parse_sign_and_digits/2, wdyt?
There was a problem hiding this comment.
Actually we can keep the single context here. Also ill move the parse_sign/2 logic into parse/2.
| do_parse(rest, base, parse_digit(char)) | ||
| else | ||
| :error | ||
| digits = [{?0..?9, -?0}, {?A..?Z, 10-?A}, {?a..?z, 10-?a}] |
|
I have fixed the spaces. |
|
Simplifed the logic by removing the sign argument. Simple benchmark run as defmodule Bench do
def bench(n) do
{time, _} = :timer.tc(__MODULE__, :test, [n])
div(time, n)
end
def test(n) do
binary = :binary.copy(<<"123456790">>, 100)
_ =for _ <- 1..n do
Integer.parse(binary)
end
:ok
end
end
IO.inspect Bench.bench(1000)x21 faster on OTP 19.2.1 : 4662us -> 222us. |