Skip to main content

src/packkit@internal@fse.erl

-module(packkit@internal@fse).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/packkit/internal/fse.gleam").
-export([predefined_literal_length/0, predefined_match_length/0, predefined_offset/0, predefined_literal_length_log/0, predefined_match_length_log/0, predefined_offset_log/0, high_bit_position/1, build_state_table/2, predefined_literal_length_table/0, predefined_match_length_table/0, predefined_offset_table/0, state_count/1, read_backward_bits/2, read_backward_bits_padded/2, new_backward_reader/1, ll_base/1, ll_extra_bits/1, ml_base/1, ml_extra_bits/1, decode_state/3, distribution_total/1]).
-export_type([state_entry/0, backward_reader/0, fse_error/0]).

-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).

-type state_entry() :: {state_entry, integer(), integer(), integer()}.

-opaque backward_reader() :: {backward_reader,
        integer(),
        integer(),
        list(integer())}.

-type fse_error() :: fse_empty_bitstream | fse_truncated.

-file("src/packkit/internal/fse.gleam", 18).
?DOC(false).
-spec predefined_literal_length() -> list(integer()).
predefined_literal_length() ->
    [4,
        3,
        2,
        2,
        2,
        2,
        2,
        2,
        2,
        2,
        2,
        2,
        2,
        1,
        1,
        1,
        2,
        2,
        2,
        2,
        2,
        2,
        2,
        2,
        2,
        3,
        2,
        1,
        1,
        1,
        1,
        1,
        -1,
        -1,
        -1,
        -1].

-file("src/packkit/internal/fse.gleam", 28).
?DOC(false).
-spec predefined_match_length() -> list(integer()).
predefined_match_length() ->
    [1,
        4,
        3,
        2,
        2,
        2,
        2,
        2,
        2,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        -1,
        -1,
        -1,
        -1,
        -1,
        -1,
        -1].

-file("src/packkit/internal/fse.gleam", 37).
?DOC(false).
-spec predefined_offset() -> list(integer()).
predefined_offset() ->
    [1,
        1,
        1,
        1,
        1,
        1,
        2,
        2,
        2,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        -1,
        -1,
        -1,
        -1,
        -1].

-file("src/packkit/internal/fse.gleam", 45).
?DOC(false).
-spec predefined_literal_length_log() -> integer().
predefined_literal_length_log() ->
    6.

-file("src/packkit/internal/fse.gleam", 49).
?DOC(false).
-spec predefined_match_length_log() -> integer().
predefined_match_length_log() ->
    6.

-file("src/packkit/internal/fse.gleam", 53).
?DOC(false).
-spec predefined_offset_log() -> integer().
predefined_offset_log() ->
    5.

-file("src/packkit/internal/fse.gleam", 92).
?DOC(false).
-spec real_counts(
    list(integer()),
    gleam@dict:dict(integer(), integer()),
    integer()
) -> gleam@dict:dict(integer(), integer()).
real_counts(Normalized, Acc, Symbol) ->
    case Normalized of
        [] ->
            Acc;

        [N | Rest] ->
            Count = case N of
                -1 ->
                    1;

                V ->
                    V
            end,
            real_counts(Rest, gleam@dict:insert(Acc, Symbol, Count), Symbol + 1)
    end.

-file("src/packkit/internal/fse.gleam", 132).
?DOC(false).
-spec place_less_probable(
    list(integer()),
    integer(),
    integer(),
    gleam@dict:dict(integer(), integer())
) -> {gleam@dict:dict(integer(), integer()), integer()}.
place_less_probable(Normalized, Symbol, High_cursor, Acc) ->
    case Normalized of
        [] ->
            {Acc, High_cursor};

        [N | Rest] ->
            case N of
                -1 ->
                    place_less_probable(
                        Rest,
                        Symbol + 1,
                        High_cursor - 1,
                        gleam@dict:insert(Acc, High_cursor, Symbol)
                    );

                _ ->
                    place_less_probable(Rest, Symbol + 1, High_cursor, Acc)
            end
    end.

-file("src/packkit/internal/fse.gleam", 229).
?DOC(false).
-spec advance_cursor(integer(), integer(), integer(), integer()) -> integer().
advance_cursor(Cursor, Mask, Step, High_threshold) ->
    Next = erlang:'band'(Cursor + Step, Mask),
    case Next > High_threshold of
        true ->
            advance_cursor(Next, Mask, Step, High_threshold);

        false ->
            Next
    end.

-file("src/packkit/internal/fse.gleam", 202).
?DOC(false).
-spec place_one_symbol(
    integer(),
    integer(),
    integer(),
    gleam@dict:dict(integer(), integer()),
    integer(),
    integer(),
    integer()
) -> {integer(), gleam@dict:dict(integer(), integer())}.
place_one_symbol(
    Symbol,
    Remaining,
    Cursor,
    Positions,
    Mask,
    Step,
    High_threshold
) ->
    case Remaining of
        0 ->
            {Cursor, Positions};

        _ ->
            Positions@1 = gleam@dict:insert(Positions, Cursor, Symbol),
            New_cursor = advance_cursor(Cursor, Mask, Step, High_threshold),
            place_one_symbol(
                Symbol,
                Remaining - 1,
                New_cursor,
                Positions@1,
                Mask,
                Step,
                High_threshold
            )
    end.

-file("src/packkit/internal/fse.gleam", 154).
?DOC(false).
-spec place_normal(
    list(integer()),
    integer(),
    integer(),
    gleam@dict:dict(integer(), integer()),
    integer(),
    integer(),
    integer()
) -> gleam@dict:dict(integer(), integer()).
place_normal(Normalized, Cursor, Symbol, Positions, Mask, Step, High_threshold) ->
    case Normalized of
        [] ->
            Positions;

        [N | Rest] ->
            case N of
                V when V =< 0 ->
                    place_normal(
                        Rest,
                        Cursor,
                        Symbol + 1,
                        Positions,
                        Mask,
                        Step,
                        High_threshold
                    );

                V@1 ->
                    {New_cursor, Positions@1} = place_one_symbol(
                        Symbol,
                        V@1,
                        Cursor,
                        Positions,
                        Mask,
                        Step,
                        High_threshold
                    ),
                    place_normal(
                        Rest,
                        New_cursor,
                        Symbol + 1,
                        Positions@1,
                        Mask,
                        Step,
                        High_threshold
                    )
            end
    end.

-file("src/packkit/internal/fse.gleam", 112).
?DOC(false).
-spec assign_positions(list(integer()), integer(), integer()) -> gleam@dict:dict(integer(), integer()).
assign_positions(Normalized, _, Table_size) ->
    Mask = Table_size - 1,
    Step = (erlang:'bsr'(Table_size, 1) + erlang:'bsr'(Table_size, 3)) + 3,
    High_threshold = Table_size - 1,
    {Positions, Next_high} = place_less_probable(
        Normalized,
        0,
        High_threshold,
        maps:new()
    ),
    place_normal(Normalized, 0, 0, Positions, Mask, Step, Next_high).

-file("src/packkit/internal/fse.gleam", 287).
?DOC(false).
-spec high_bit_position(integer()) -> integer().
high_bit_position(Value) ->
    case Value of
        N when N =< 1 ->
            0;

        _ ->
            1 + high_bit_position(erlang:'bsr'(Value, 1))
    end.

-file("src/packkit/internal/fse.gleam", 237).
?DOC(false).
-spec build_entries(
    gleam@dict:dict(integer(), integer()),
    gleam@dict:dict(integer(), integer()),
    gleam@dict:dict(integer(), integer()),
    integer(),
    integer(),
    integer(),
    gleam@dict:dict(integer(), state_entry())
) -> gleam@dict:dict(integer(), state_entry()).
build_entries(
    Positions,
    Counts,
    Symbol_next,
    Accuracy_log,
    Table_size,
    State_index,
    Acc
) ->
    case State_index >= Table_size of
        true ->
            Acc;

        false ->
            Symbol = case gleam_stdlib:map_get(Positions, State_index) of
                {ok, V} ->
                    V;

                {error, _} ->
                    0
            end,
            Count = case gleam_stdlib:map_get(Counts, Symbol) of
                {ok, V@1} ->
                    V@1;

                {error, _} ->
                    1
            end,
            Next_value = case gleam_stdlib:map_get(Symbol_next, Symbol) of
                {ok, V@2} ->
                    V@2;

                {error, _} ->
                    Count
            end,
            Nb_bits = Accuracy_log - high_bit_position(Next_value),
            Baseline = erlang:'bsl'(Next_value, Nb_bits) - Table_size,
            Entry = {state_entry, Symbol, Nb_bits, Baseline},
            build_entries(
                Positions,
                Counts,
                gleam@dict:insert(Symbol_next, Symbol, Next_value + 1),
                Accuracy_log,
                Table_size,
                State_index + 1,
                gleam@dict:insert(Acc, State_index, Entry)
            )
    end.

-file("src/packkit/internal/fse.gleam", 71).
?DOC(false).
-spec build_state_table(list(integer()), integer()) -> gleam@dict:dict(integer(), state_entry()).
build_state_table(Normalized, Accuracy_log) ->
    Table_size = erlang:'bsl'(1, Accuracy_log),
    Position_dict = assign_positions(Normalized, Accuracy_log, Table_size),
    Symbol_counts = real_counts(Normalized, maps:new(), 0),
    build_entries(
        Position_dict,
        Symbol_counts,
        maps:new(),
        Accuracy_log,
        Table_size,
        0,
        maps:new()
    ).

-file("src/packkit/internal/fse.gleam", 295).
?DOC(false).
-spec predefined_literal_length_table() -> gleam@dict:dict(integer(), state_entry()).
predefined_literal_length_table() ->
    build_state_table(
        predefined_literal_length(),
        predefined_literal_length_log()
    ).

-file("src/packkit/internal/fse.gleam", 303).
?DOC(false).
-spec predefined_match_length_table() -> gleam@dict:dict(integer(), state_entry()).
predefined_match_length_table() ->
    build_state_table(predefined_match_length(), predefined_match_length_log()).

-file("src/packkit/internal/fse.gleam", 308).
?DOC(false).
-spec predefined_offset_table() -> gleam@dict:dict(integer(), state_entry()).
predefined_offset_table() ->
    build_state_table(predefined_offset(), predefined_offset_log()).

-file("src/packkit/internal/fse.gleam", 313).
?DOC(false).
-spec state_count(integer()) -> integer().
state_count(Accuracy_log) ->
    erlang:'bsl'(1, Accuracy_log).

-file("src/packkit/internal/fse.gleam", 412).
?DOC(false).
-spec refill_backward(backward_reader(), integer()) -> backward_reader().
refill_backward(Reader, Needed) ->
    case erlang:element(3, Reader) >= Needed of
        true ->
            Reader;

        false ->
            case erlang:element(4, Reader) of
                [Byte | Rest] ->
                    New_buffer = erlang:'bor'(
                        erlang:'bsl'(erlang:element(2, Reader), 8),
                        Byte
                    ),
                    refill_backward(
                        {backward_reader,
                            New_buffer,
                            erlang:element(3, Reader) + 8,
                            Rest},
                        Needed
                    );

                [] ->
                    Reader
            end
    end.

-file("src/packkit/internal/fse.gleam", 357).
?DOC(false).
-spec read_backward_bits(backward_reader(), integer()) -> {ok,
        {integer(), backward_reader()}} |
    {error, fse_error()}.
read_backward_bits(Reader, Count) ->
    Reader@1 = refill_backward(Reader, Count),
    case erlang:element(3, Reader@1) >= Count of
        false ->
            {error, fse_truncated};

        true ->
            Shift = erlang:element(3, Reader@1) - Count,
            Mask = erlang:'bsl'(1, Count) - 1,
            Value = erlang:'band'(
                erlang:'bsr'(erlang:element(2, Reader@1), Shift),
                Mask
            ),
            Leftover_mask = erlang:'bsl'(1, Shift) - 1,
            {ok,
                {Value,
                    {backward_reader,
                        erlang:'band'(
                            erlang:element(2, Reader@1),
                            Leftover_mask
                        ),
                        Shift,
                        erlang:element(4, Reader@1)}}}
    end.

-file("src/packkit/internal/fse.gleam", 387).
?DOC(false).
-spec read_backward_bits_padded(backward_reader(), integer()) -> {ok,
        {integer(), backward_reader()}} |
    {error, fse_error()}.
read_backward_bits_padded(Reader, Count) ->
    Reader@1 = refill_backward(Reader, Count),
    case erlang:element(3, Reader@1) >= Count of
        true ->
            read_backward_bits(Reader@1, Count);

        false ->
            case erlang:element(3, Reader@1) of
                0 ->
                    {error, fse_empty_bitstream};

                Available ->
                    Pad = Count - Available,
                    Mask = erlang:'bsl'(1, Available) - 1,
                    Value = begin
                        _pipe = erlang:'band'(erlang:element(2, Reader@1), Mask),
                        erlang:'bsl'(_pipe, Pad)
                    end,
                    {ok,
                        {Value,
                            {backward_reader, 0, 0, erlang:element(4, Reader@1)}}}
            end
    end.

-file("src/packkit/internal/fse.gleam", 434).
?DOC(false).
-spec bytes_to_reverse_list(bitstring(), list(integer())) -> list(integer()).
bytes_to_reverse_list(Bytes, Acc) ->
    case Bytes of
        <<B, Rest/binary>> ->
            bytes_to_reverse_list(Rest, [B | Acc]);

        _ ->
            Acc
    end.

-file("src/packkit/internal/fse.gleam", 329).
?DOC(false).
-spec new_backward_reader(bitstring()) -> {ok, backward_reader()} |
    {error, fse_error()}.
new_backward_reader(Bytes) ->
    Bytes_rev = bytes_to_reverse_list(Bytes, []),
    case Bytes_rev of
        [] ->
            {error, fse_empty_bitstream};

        [Last | Rest] ->
            High = high_bit_position(Last),
            case Last =:= 0 of
                true ->
                    {error, fse_empty_bitstream};

                false ->
                    Bits_below = High,
                    Mask = erlang:'bsl'(1, Bits_below) - 1,
                    Initial = erlang:'band'(Last, Mask),
                    {ok, {backward_reader, Initial, Bits_below, Rest}}
            end
    end.

-file("src/packkit/internal/fse.gleam", 447).
?DOC(false).
-spec ll_base(integer()) -> integer().
ll_base(Code) ->
    case Code of
        N when (N >= 0) andalso (N =< 15) ->
            N;

        16 ->
            16;

        17 ->
            18;

        18 ->
            20;

        19 ->
            22;

        20 ->
            24;

        21 ->
            28;

        22 ->
            32;

        23 ->
            40;

        24 ->
            48;

        25 ->
            64;

        26 ->
            128;

        27 ->
            256;

        28 ->
            512;

        29 ->
            1024;

        30 ->
            2048;

        31 ->
            4096;

        32 ->
            8192;

        33 ->
            16384;

        34 ->
            32768;

        35 ->
            65536;

        _ ->
            0
    end.

-file("src/packkit/internal/fse.gleam", 475).
?DOC(false).
-spec ll_extra_bits(integer()) -> integer().
ll_extra_bits(Code) ->
    case Code of
        N when (N >= 0) andalso (N =< 15) ->
            0;

        N@1 when (N@1 >= 16) andalso (N@1 =< 19) ->
            1;

        N@2 when (N@2 >= 20) andalso (N@2 =< 21) ->
            2;

        N@3 when (N@3 >= 22) andalso (N@3 =< 23) ->
            3;

        24 ->
            4;

        25 ->
            6;

        26 ->
            7;

        27 ->
            8;

        28 ->
            9;

        29 ->
            10;

        30 ->
            11;

        31 ->
            12;

        32 ->
            13;

        33 ->
            14;

        34 ->
            15;

        35 ->
            16;

        _ ->
            0
    end.

-file("src/packkit/internal/fse.gleam", 501).
?DOC(false).
-spec ml_base(integer()) -> integer().
ml_base(Code) ->
    case Code of
        N when (N >= 0) andalso (N =< 31) ->
            3 + N;

        32 ->
            35;

        33 ->
            37;

        34 ->
            39;

        35 ->
            41;

        36 ->
            43;

        37 ->
            47;

        38 ->
            51;

        39 ->
            59;

        40 ->
            67;

        41 ->
            83;

        42 ->
            99;

        43 ->
            131;

        44 ->
            259;

        45 ->
            515;

        46 ->
            1027;

        47 ->
            2051;

        48 ->
            4099;

        49 ->
            8195;

        50 ->
            16387;

        51 ->
            32771;

        52 ->
            65539;

        _ ->
            3
    end.

-file("src/packkit/internal/fse.gleam", 530).
?DOC(false).
-spec ml_extra_bits(integer()) -> integer().
ml_extra_bits(Code) ->
    case Code of
        N when (N >= 0) andalso (N =< 31) ->
            0;

        N@1 when (N@1 >= 32) andalso (N@1 =< 35) ->
            1;

        N@2 when (N@2 >= 36) andalso (N@2 =< 37) ->
            2;

        N@3 when (N@3 >= 38) andalso (N@3 =< 39) ->
            3;

        40 ->
            4;

        41 ->
            4;

        42 ->
            5;

        43 ->
            7;

        44 ->
            8;

        45 ->
            9;

        46 ->
            10;

        47 ->
            11;

        48 ->
            12;

        49 ->
            13;

        50 ->
            14;

        51 ->
            15;

        52 ->
            16;

        _ ->
            0
    end.

-file("src/packkit/internal/fse.gleam", 556).
?DOC(false).
-spec decode_state(
    gleam@dict:dict(integer(), state_entry()),
    integer(),
    backward_reader()
) -> {ok, {integer(), integer(), backward_reader()}} | {error, fse_error()}.
decode_state(Table, State, Reader) ->
    Entry = case gleam_stdlib:map_get(Table, State) of
        {ok, E} ->
            E;

        {error, _} ->
            {state_entry, 0, 0, 0}
    end,
    gleam@result:'try'(
        read_backward_bits(Reader, erlang:element(3, Entry)),
        fun(_use0) ->
            {Extra, Reader@1} = _use0,
            {ok,
                {erlang:element(2, Entry),
                    erlang:element(4, Entry) + Extra,
                    Reader@1}}
        end
    ).

-file("src/packkit/internal/fse.gleam", 571).
?DOC(false).
-spec distribution_total(list(integer())) -> integer().
distribution_total(Normalized) ->
    gleam@list:fold(Normalized, 0, fun(Acc, N) -> case N of
                -1 ->
                    Acc + 1;

                V ->
                    Acc + V
            end end).