src/gleeam_code@internal@tree_builder.erl

-module(gleeam_code@internal@tree_builder).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/gleeam_code/internal/tree_builder.gleam").
-export([tree_from_level_order/1, list_from_list/1]).
-export_type([tree_node/0, list_node/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 tree_node() :: {tree_node,
        integer(),
        gleam@option:option(tree_node()),
        gleam@option:option(tree_node())}.

-type list_node() :: {list_node, integer(), gleam@option:option(list_node())}.

-file("src/gleeam_code/internal/tree_builder.gleam", 64).
?DOC(false).
-spec take_next(list(gleam@option:option(integer()))) -> {gleam@option:option(integer()),
    list(gleam@option:option(integer()))}.
take_next(Values) ->
    case Values of
        [] ->
            {none, []};

        [V | Rest] ->
            {V, Rest}
    end.

-file("src/gleeam_code/internal/tree_builder.gleam", 23).
?DOC(false).
-spec bfs_assign(
    list(integer()),
    list(gleam@option:option(integer())),
    list({gleam@option:option(integer()), integer(), integer()}),
    integer()
) -> {list({gleam@option:option(integer()), integer(), integer()}),
    list(gleam@option:option(integer()))}.
bfs_assign(Queue, Remaining, Flat, Next_idx) ->
    case Queue of
        [] ->
            {Flat, Remaining};

        [Parent_idx | Rest_queue] ->
            {Left_val, After_left} = take_next(Remaining),
            {Right_val, After_right} = take_next(After_left),
            {Left_idx, Flat2, Queue2, Idx2} = case Left_val of
                none ->
                    {-1, Flat, Rest_queue, Next_idx};

                {some, _} ->
                    {Next_idx,
                        lists:append(Flat, [{Left_val, -1, -1}]),
                        lists:append(Rest_queue, [Next_idx]),
                        Next_idx + 1}
            end,
            {Right_idx, Flat3, Queue3, Idx3} = case Right_val of
                none ->
                    {-1, Flat2, Queue2, Idx2};

                {some, _} ->
                    {Idx2,
                        lists:append(Flat2, [{Right_val, -1, -1}]),
                        lists:append(Queue2, [Idx2]),
                        Idx2 + 1}
            end,
            Flat4 = gleam@list:index_map(
                Flat3,
                fun(Entry, I) -> case I =:= Parent_idx of
                        true ->
                            {erlang:element(1, Entry), Left_idx, Right_idx};

                        false ->
                            Entry
                    end end
            ),
            bfs_assign(Queue3, After_right, Flat4, Idx3)
    end.

-file("src/gleeam_code/internal/tree_builder.gleam", 71).
?DOC(false).
-spec build_tree_from_flat(
    list({gleam@option:option(integer()), integer(), integer()}),
    integer()
) -> gleam@option:option(tree_node()).
build_tree_from_flat(Flat, Idx) ->
    case Idx < 0 of
        true ->
            none;

        false ->
            case gleam@list:drop(Flat, Idx) of
                [] ->
                    none;

                [{none, _, _} | _] ->
                    none;

                [{{some, Val}, Left_idx, Right_idx} | _] ->
                    Left = build_tree_from_flat(Flat, Left_idx),
                    Right = build_tree_from_flat(Flat, Right_idx),
                    {some, {tree_node, Val, Left, Right}}
            end
    end.

-file("src/gleeam_code/internal/tree_builder.gleam", 12).
?DOC(false).
-spec tree_from_level_order(list(gleam@option:option(integer()))) -> gleam@option:option(tree_node()).
tree_from_level_order(Values) ->
    case Values of
        [] ->
            none;

        [none | _] ->
            none;

        [{some, Root_val} | Rest] ->
            {Flat, _} = bfs_assign([0], Rest, [{{some, Root_val}, -1, -1}], 1),
            build_tree_from_flat(Flat, 0)
    end.

-file("src/gleeam_code/internal/tree_builder.gleam", 97).
?DOC(false).
-spec do_list_from_list(list(integer())) -> list_node().
do_list_from_list(Values) ->
    case Values of
        [] ->
            erlang:error(#{gleam_error => panic,
                    message => <<"unreachable: empty list"/utf8>>,
                    file => <<?FILEPATH/utf8>>,
                    module => <<"gleeam_code/internal/tree_builder"/utf8>>,
                    function => <<"do_list_from_list"/utf8>>,
                    line => 99});

        [X] ->
            {list_node, X, none};

        [X@1 | Rest] ->
            {list_node, X@1, {some, do_list_from_list(Rest)}}
    end.

-file("src/gleeam_code/internal/tree_builder.gleam", 90).
?DOC(false).
-spec list_from_list(list(integer())) -> gleam@option:option(list_node()).
list_from_list(Values) ->
    case Values of
        [] ->
            none;

        _ ->
            {some, do_list_from_list(Values)}
    end.