-module(qrkit@internal@reed_solomon).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/qrkit/internal/reed_solomon.gleam").
-export([gf_exp/1, gf_multiply/2, generator_polynomial/1, encode/2]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(false).
-file("src/qrkit/internal/reed_solomon.gleam", 38).
?DOC(false).
-spec normalise_exponent(integer()) -> integer().
normalise_exponent(Exponent) ->
case Exponent < 0 of
true ->
normalise_exponent(Exponent + 255);
false ->
case Exponent >= 255 of
true ->
normalise_exponent(Exponent - 255);
false ->
Exponent
end
end.
-file("src/qrkit/internal/reed_solomon.gleam", 49).
?DOC(false).
-spec gf_exp_loop(integer(), integer()) -> integer().
gf_exp_loop(Exponent, Value) ->
gleam@bool:guard(
Exponent =< 0,
Value,
fun() ->
Shifted = erlang:'bsl'(Value, 1),
Reduced = case erlang:'band'(Shifted, 16#100) /= 0 of
true ->
erlang:'bxor'(Shifted, 16#11D);
false ->
Shifted
end,
gf_exp_loop(Exponent - 1, erlang:'band'(Reduced, 16#FF))
end
).
-file("src/qrkit/internal/reed_solomon.gleam", 34).
?DOC(false).
-spec gf_exp(integer()) -> integer().
gf_exp(Exponent) ->
gf_exp_loop(normalise_exponent(Exponent), 1).
-file("src/qrkit/internal/reed_solomon.gleam", 59).
?DOC(false).
-spec gf_multiply_loop(integer(), integer(), integer()) -> integer().
gf_multiply_loop(A, B, Acc) ->
gleam@bool:guard(
B =:= 0,
Acc,
fun() ->
Next_acc = case erlang:'band'(B, 1) =:= 1 of
true ->
erlang:'bxor'(Acc, A);
false ->
Acc
end,
Shifted = erlang:'bsl'(A, 1),
Next_a = case erlang:'band'(Shifted, 16#100) /= 0 of
true ->
erlang:'bxor'(Shifted, 16#11D);
false ->
Shifted
end,
gf_multiply_loop(
erlang:'band'(Next_a, 16#FF),
erlang:'bsr'(B, 1),
Next_acc
)
end
).
-file("src/qrkit/internal/reed_solomon.gleam", 30).
?DOC(false).
-spec gf_multiply(integer(), integer()) -> integer().
gf_multiply(A, B) ->
gf_multiply_loop(A, B, 0).
-file("src/qrkit/internal/reed_solomon.gleam", 97).
?DOC(false).
-spec do_poly_row(
list(integer()),
integer(),
integer(),
integer(),
list(integer())
) -> list(integer()).
do_poly_row(Right, Left_coefficient, Left_index, Right_index, Acc) ->
case Right of
[] ->
Acc;
[Coefficient | Rest] ->
Index = Left_index + Right_index,
Previous = qrkit@internal@util:at_or(Acc, Index, 0),
Value = erlang:'bxor'(
Previous,
gf_multiply(Left_coefficient, Coefficient)
),
do_poly_row(
Rest,
Left_coefficient,
Left_index,
Right_index + 1,
qrkit@internal@util:replace_at(Acc, Index, Value)
)
end.
-file("src/qrkit/internal/reed_solomon.gleam", 82).
?DOC(false).
-spec do_poly_multiply(
list(integer()),
list(integer()),
integer(),
list(integer())
) -> list(integer()).
do_poly_multiply(Left, Right, Left_index, Acc) ->
case Left of
[] ->
Acc;
[Coefficient | Rest] ->
Next = do_poly_row(Right, Coefficient, Left_index, 0, Acc),
do_poly_multiply(Rest, Right, Left_index + 1, Next)
end.
-file("src/qrkit/internal/reed_solomon.gleam", 77).
?DOC(false).
-spec poly_multiply(list(integer()), list(integer())) -> list(integer()).
poly_multiply(Left, Right) ->
Size = (erlang:length(Left) + erlang:length(Right)) - 1,
do_poly_multiply(Left, Right, 0, qrkit@internal@util:repeat(0, Size)).
-file("src/qrkit/internal/reed_solomon.gleam", 13).
?DOC(false).
-spec do_generator_polynomial(integer(), list(integer())) -> list(integer()).
do_generator_polynomial(Degree, Polynomial) ->
gleam@bool:guard(
Degree =< 0,
Polynomial,
fun() ->
Exponent = erlang:length(Polynomial) - 1,
Factor = [1, gf_exp(Exponent)],
do_generator_polynomial(
Degree - 1,
poly_multiply(Polynomial, Factor)
)
end
).
-file("src/qrkit/internal/reed_solomon.gleam", 9).
?DOC(false).
-spec generator_polynomial(integer()) -> list(integer()).
generator_polynomial(Degree) ->
do_generator_polynomial(Degree, [1]).
-file("src/qrkit/internal/reed_solomon.gleam", 140).
?DOC(false).
-spec do_poly_mod_step(
list(integer()),
list(integer()),
integer(),
integer(),
list(integer())
) -> list(integer()).
do_poly_mod_step(Dividend, Divisor, Lead, Index, Acc) ->
case {Dividend, Divisor} of
{[Left | Left_rest], [Right | Right_rest]} ->
Value = erlang:'bxor'(Left, gf_multiply(Right, Lead)),
do_poly_mod_step(
Left_rest,
Right_rest,
Lead,
Index + 1,
[Value | Acc]
);
{Remaining, []} ->
_pipe = lists:reverse(Acc),
lists:append(_pipe, Remaining);
{[], _} ->
lists:reverse(Acc)
end.
-file("src/qrkit/internal/reed_solomon.gleam", 157).
?DOC(false).
-spec trim_leading_zeros(list(integer())) -> list(integer()).
trim_leading_zeros(Values) ->
case Values of
[0 | Rest] ->
trim_leading_zeros(Rest);
_ ->
Values
end.
-file("src/qrkit/internal/reed_solomon.gleam", 125).
?DOC(false).
-spec poly_mod(list(integer()), list(integer())) -> list(integer()).
poly_mod(Dividend, Divisor) ->
case erlang:length(Dividend) < erlang:length(Divisor) of
true ->
trim_leading_zeros(Dividend);
false ->
case Dividend of
[] ->
[];
[Lead | _] ->
Reduced = do_poly_mod_step(Dividend, Divisor, Lead, 0, []),
poly_mod(trim_leading_zeros(Reduced), Divisor)
end
end.
-file("src/qrkit/internal/reed_solomon.gleam", 21).
?DOC(false).
-spec encode(list(integer()), integer()) -> list(integer()).
encode(Data, Degree) ->
Generator = generator_polynomial(Degree),
Padded = lists:append(Data, qrkit@internal@util:repeat(0, Degree)),
Remainder = poly_mod(Padded, Generator),
Padding = qrkit@internal@util:repeat(0, Degree - erlang:length(Remainder)),
lists:append(Padding, Remainder).