Skip to content

Commit ba76845

Browse files
committed
Delay flattening the list during encoding when possible
1 parent f3f5399 commit ba76845

File tree

1 file changed

+36
-8
lines changed

1 file changed

+36
-8
lines changed

lib/hashids.ex

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -275,47 +275,48 @@ defmodule Hashids do
275275
skey = Stream.concat(rkey, alphabet) |> Enum.take(a_len)
276276
enc_alphabet = Helpers.consistent_shuffle(alphabet, skey)
277277
{last, last_len} = Helpers.encode(num, enc_alphabet, a_len)
278-
{ret ++ last, last_len, enc_alphabet, last}
278+
{[ret | last], last_len, enc_alphabet, last}
279279
end
280280

281281
defp seps_step([char|_], i, num, ret, seps, seps_len) do
282282
index = rem(num, char+i) |> rem(seps_len)
283-
ret ++ [Enum.at(seps, index)]
283+
[ret, Enum.at(seps, index)]
284284
end
285285

286286

287-
defp extend_precipher1([char|_]=precipher, p_len, min_len, num_cksm, guards, g_len)
287+
defp extend_precipher1(precipher, p_len, min_len, num_cksm, guards, g_len)
288288
when p_len < min_len
289289
do
290+
char = nested_list_at(precipher, 0)
290291
index = rem(num_cksm + char, g_len)
291292
guard = Enum.at(guards, index)
292293
{[guard|precipher], p_len+1}
293294
end
294295
defp extend_precipher1(precipher, p_len, _, _, _, _), do: {precipher, p_len}
295296

296-
defp extend_precipher2([_,_,char2|_]=precipher, p_len, min_len, num_cksm, guards, g_len)
297+
defp extend_precipher2(precipher, p_len, min_len, num_cksm, guards, g_len)
297298
when p_len < min_len
298299
do
300+
char2 = nested_list_at(precipher, 2)
299301
index = rem(num_cksm + char2, g_len)
300302
guard = Enum.at(guards, index)
301-
{precipher ++ [guard], p_len+1}
303+
{[precipher, guard], p_len+1}
302304
end
303305
defp extend_precipher2(precipher, p_len, _, _, _, _), do: {precipher, p_len}
304306

305-
306307
defp extend_cipher(cipher, c_len, min_len, alphabet, a_len)
307308
when c_len < min_len
308309
do
309310
new_alphabet = Helpers.consistent_shuffle(alphabet, alphabet)
310311
half_len = div(a_len, 2)
311312
{left, right} = Enum.split(new_alphabet, half_len)
312313

313-
new_cipher = List.flatten([right, cipher], left)
314+
new_cipher = [right, cipher | left]
314315
new_c_len = c_len + a_len
315316

316317
excess = new_c_len - min_len
317318
if excess > 0 do
318-
new_cipher |> Enum.drop(div(excess, 2)) |> Enum.take(min_len)
319+
new_cipher |> List.flatten |> Enum.drop(div(excess, 2)) |> Enum.take(min_len)
319320
else
320321
extend_cipher(new_cipher, new_c_len, min_len, new_alphabet, a_len)
321322
end
@@ -332,4 +333,31 @@ defmodule Hashids do
332333
number = Helpers.decode(String.to_char_list(part), dec_alphabet, a_len)
333334
decode_parts(rest, rkey, dec_alphabet, a_len, [number|acc])
334335
end
336+
337+
338+
defp nested_list_at(list, i) when is_integer(i) and i >= 0 do
339+
try do
340+
do_nested_list_at(list, i)
341+
raise "Index out of bounds"
342+
catch
343+
:throw, result -> result
344+
end
345+
end
346+
347+
defp do_nested_list_at([h|rest], i) when is_list(h) do
348+
new_i = do_nested_list_at(h, i)
349+
do_nested_list_at(rest, new_i)
350+
end
351+
352+
defp do_nested_list_at([h|_], 0) do
353+
throw h
354+
end
355+
356+
defp do_nested_list_at([_|rest], i) do
357+
do_nested_list_at(rest, i-1)
358+
end
359+
360+
defp do_nested_list_at([], i) do
361+
i
362+
end
335363
end

0 commit comments

Comments
 (0)