-module(glib@map). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([size/1, is_empty/1, keys/1, values/1, entries/1, to_string/2, get/2, contains_key/2, remove/2, list_size/1, full_count/1, new_with_size_and_load/2, new_with_size/1, new/0, clear/1, put/3]). -export_type([entry/1, map_/1]). -type entry(GYH) :: {entry, binary(), GYH}. -opaque map_(GYI) :: {map, glib@treelist:tree_list(gleam@option:option(entry(GYI))), integer(), integer(), integer(), boolean()}. -spec size(map_(any())) -> integer(). size(Map) -> erlang:element(5, Map). -spec is_empty(map_(any())) -> boolean(). is_empty(Map) -> size(Map) =:= 0. -spec keys(map_(any())) -> list(binary()). keys(Map) -> _pipe = glib@treelist:to_iterator(erlang:element(2, Map)), _pipe@1 = gleam@iterator:filter_map(_pipe, fun(E) -> case E of none -> {error, nil}; {some, En} -> {ok, erlang:element(2, En)} end end), gleam@iterator:to_list(_pipe@1). -spec values(map_(GZZ)) -> list(GZZ). values(Map) -> _pipe = glib@treelist:to_iterator(erlang:element(2, Map)), _pipe@1 = gleam@iterator:filter_map(_pipe, fun(E) -> case E of none -> {error, nil}; {some, En} -> {ok, erlang:element(3, En)} end end), gleam@iterator:to_list(_pipe@1). -spec entries(map_(HAC)) -> list({binary(), HAC}). entries(Map) -> _pipe = glib@treelist:to_iterator(erlang:element(2, Map)), _pipe@1 = gleam@iterator:filter_map(_pipe, fun(E) -> case E of none -> {error, nil}; {some, En} -> {ok, {erlang:element(2, En), erlang:element(3, En)}} end end), gleam@iterator:to_list(_pipe@1). -spec to_string(map_(HAF), fun((HAF) -> binary())) -> {ok, binary()} | {error, nil}. to_string(Map, Value_to_string) -> {ok, <<<<"{"/utf8, (gleam@string:join( begin _pipe = glib@treelist:to_iterator( erlang:element(2, Map) ), _pipe@1 = gleam@iterator:filter_map( _pipe, fun(Opt) -> case Opt of none -> {error, Opt}; {some, E} -> {ok, <<<<<<<<"\""/utf8, (erlang:element( 2, E ))/binary>>/binary, "\""/utf8>>/binary, ":"/utf8>>/binary, (Value_to_string( erlang:element(3, E) ))/binary>>} end end ), gleam@iterator:to_list(_pipe@1) end, <<","/utf8>> ))/binary>>/binary, "}"/utf8>>}. -spec do_remove(map_(HAJ), integer(), HAJ) -> {ok, {gleam@option:option(HAJ), map_(HAJ)}} | {error, nil}. do_remove(Map, Index, Value) -> gleam@result:'try'( glib@treelist:set(erlang:element(2, Map), Index, none), fun(Entry) -> New_map = erlang:setelement( 5, erlang:setelement(2, Map, Entry), erlang:element(5, Map) - 1 ), {ok, {{some, Value}, New_map}} end ). -spec find_gap(map_(any()), binary(), integer(), integer()) -> {ok, {integer(), boolean()}} | {error, nil}. find_gap(Map, Key, Last_position, Position) -> gleam@result:'try'( glib@treelist:get(erlang:element(2, Map), Position), fun(Entry) -> case Entry of none -> {ok, {Position, false}}; {some, E} -> case erlang:element(2, E) =:= Key of true -> {ok, {Position, true}}; false -> case Position of Position@1 when Position@1 =:= Last_position -> {ok, {-1, false}}; 0 -> find_gap( Map, Key, Last_position, erlang:element(3, Map) - 1 ); Position@2 -> find_gap( Map, Key, Last_position, Position@2 - 1 ) end end end end ). -spec find_key( map_(HAZ), binary(), integer(), integer(), fun((integer(), HAZ) -> HBB) ) -> {ok, gleam@option:option(HBB)} | {error, nil}. find_key(Map, Key, Last_position, Position, Ret_fn) -> gleam@result:'try'( glib@treelist:get(erlang:element(2, Map), Position), fun(Entry) -> case Entry of none -> {ok, none}; {some, E} -> case erlang:element(2, E) =:= Key of true -> {ok, {some, Ret_fn(Position, erlang:element(3, E))}}; false -> case Position of Position@1 when Position@1 =:= Last_position -> {ok, none}; 0 -> find_key( Map, Key, Last_position, erlang:element(3, Map) - 1, Ret_fn ); Position@2 -> find_key( Map, Key, Last_position, Position@2 - 1, Ret_fn ) end end end end ). -spec ret_value(integer(), HBF) -> HBF. ret_value(_, Value) -> Value. -spec ret_exists(integer(), any()) -> boolean(). ret_exists(_, _) -> true. -spec ret_index_and_value(integer(), HBH) -> {integer(), HBH}. ret_index_and_value(Index, Value) -> {Index, Value}. -spec prepend_none(integer(), list(gleam@option:option(entry(HBN)))) -> list(gleam@option:option(entry(HBN))). prepend_none(Times, Acc) -> case Times =< 0 of true -> Acc; false -> prepend_none(Times - 1, [none | Acc]) end. -spec do_repeat(HBS, integer(), list(HBS)) -> list(HBS). do_repeat(A, Times, Acc) -> case Times =< 0 of true -> Acc; false -> do_repeat(A, Times, [A | Acc]) end. -spec fix_hash(integer(), integer()) -> integer(). fix_hash(Map_size, Hash) -> case Map_size of 0 -> 0; Gleam@denominator -> begin _pipe = Hash, gleam@int:absolute_value(_pipe) end rem Gleam@denominator end. -spec calc_hash(integer(), binary()) -> {integer(), integer()}. calc_hash(Map_size, Key) -> Hash_value = glib@hash:hash(Key), {fix_hash(Map_size, Hash_value), Hash_value}. -spec get(map_(GZJ), binary()) -> {ok, gleam@option:option(GZJ)} | {error, nil}. get(Map, Key) -> {Hash, _} = calc_hash(erlang:element(3, Map), Key), gleam@result:'try'( glib@treelist:get(erlang:element(2, Map), Hash), fun(Entry) -> case Entry of none -> {ok, none}; {some, E} -> case erlang:element(2, E) =:= Key of true -> {ok, {some, erlang:element(3, E)}}; false -> find_key(Map, Key, case erlang:element(3, Map) of 0 -> 0; Gleam@denominator -> (Hash + 1) rem Gleam@denominator end, Hash, fun ret_value/2) end end end ). -spec contains_key(map_(any()), binary()) -> boolean(). contains_key(Map, Key) -> {Hash, _} = calc_hash(erlang:element(3, Map), Key), case glib@treelist:get(erlang:element(2, Map), Hash) of {error, _} -> false; {ok, none} -> false; {ok, {some, E}} -> case erlang:element(2, E) =:= Key of true -> true; false -> gleam@option:unwrap( gleam@result:unwrap( find_key(Map, Key, case erlang:element(3, Map) of 0 -> 0; Gleam@denominator -> (Hash + 1) rem Gleam@denominator end, Hash, fun ret_exists/2), none ), false ) end end. -spec remove(map_(GZQ), binary()) -> {ok, {gleam@option:option(GZQ), map_(GZQ)}} | {error, nil}. remove(Map, Key) -> {Hash, _} = calc_hash(erlang:element(3, Map), Key), gleam@result:'try'( glib@treelist:get(erlang:element(2, Map), Hash), fun(Entry) -> case Entry of none -> {ok, {none, Map}}; {some, E} -> case erlang:element(2, E) =:= Key of true -> do_remove(Map, Hash, erlang:element(3, E)); false -> gleam@result:'try'( find_key( Map, Key, case erlang:element(3, Map) of 0 -> 0; Gleam@denominator -> (Hash + 1) rem Gleam@denominator end, Hash, fun ret_index_and_value/2 ), fun(Item) -> case Item of none -> {ok, {none, Map}}; {some, {Index, Value}} -> do_remove(Map, Index, Value) end end ) end end end ). -spec list_size(map_(any())) -> integer(). list_size(Map) -> glib@treelist:size(erlang:element(2, Map)). -spec full_count(map_(any())) -> integer(). full_count(Map) -> _pipe = glib@treelist:to_iterator(erlang:element(2, Map)), gleam@iterator:fold(_pipe, 0, fun(Acc, E) -> case E of none -> Acc; {some, _} -> Acc + 1 end end). -spec new_with_size_and_load(integer(), float()) -> {ok, map_(any())} | {error, nil}. new_with_size_and_load(Size, Load) -> Load@1 = case (Load >= 1.0) orelse (Load < +0.0) of true -> 0.75; false -> Load end * 100.0, Size@1 = case Size < 1 of true -> 1; false -> Size end, gleam@result:'try'( glib@treelist:repeat(none, Size@1), fun(Backing_list) -> {ok, {map, Backing_list, Size@1, gleam@float:round(Load@1), 0, false}} end ). -spec new_with_size(integer()) -> {ok, map_(any())} | {error, nil}. new_with_size(Size) -> new_with_size_and_load(Size, 0.75). -spec new() -> {ok, map_(any())} | {error, nil}. new() -> new_with_size(11). -spec clear(map_(GYV)) -> {ok, map_(GYV)} | {error, nil}. clear(Previous_map) -> new_with_size_and_load( erlang:element(3, Previous_map), gleam@int:to_float(erlang:element(4, Previous_map)) / 100.0 ). -spec basic_rehash(map_(HBI), integer()) -> {ok, map_(HBI)} | {error, nil}. basic_rehash(Map, New_size) -> gleam@result:'try'( new_with_size_and_load( New_size, gleam@int:to_float(erlang:element(4, Map)) / 100.0 ), fun(New_map) -> _pipe = glib@treelist:to_iterator(erlang:element(2, Map)), gleam@iterator:try_fold( _pipe, erlang:setelement(6, New_map, true), fun(Map@1, Entry) -> case Entry of {some, Entry@1} -> put( Map@1, erlang:element(2, Entry@1), erlang:element(3, Entry@1) ); none -> {ok, Map@1} end end ) end ). -spec put(map_(GZE), binary(), GZE) -> {ok, map_(GZE)} | {error, nil}. put(Map, Key, Value) -> {Hash, Original_hash} = calc_hash(erlang:element(3, Map), Key), gleam@result:'try'( glib@treelist:get(erlang:element(2, Map), Hash), fun(Entry) -> gleam@result:'try'(case Entry of {some, E} when erlang:element(2, E) =:= Key -> {ok, {Map, Hash, true}}; _ -> gleam@result:'try'( check_capacity(Map, Original_hash), fun(_use0) -> {Map@1, New_hash} = _use0, New_hash@1 = gleam@option:unwrap(New_hash, Hash), gleam@result:'try'( find_gap( Map@1, Key, case erlang:element(3, Map@1) of 0 -> 0; Gleam@denominator -> (New_hash@1 + 1) rem Gleam@denominator end, New_hash@1 ), fun(_use0@1) -> {Entry_pos, Overwrite} = _use0@1, {ok, {Map@1, Entry_pos, Overwrite}} end ) end ) end, fun(_use0@2) -> {Map@2, Entry_pos@1, Overwrite@1} = _use0@2, gleam@result:'try'( glib@treelist:set( erlang:element(2, Map@2), Entry_pos@1, {some, {entry, Key, Value}} ), fun(Inner) -> {ok, erlang:setelement( 5, erlang:setelement(2, Map@2, Inner), case Overwrite@1 of true -> erlang:element(5, Map@2); false -> erlang:element(5, Map@2) + 1 end )} end ) end) end ). -spec check_capacity(map_(HAP), integer()) -> {ok, {map_(HAP), gleam@option:option(integer())}} | {error, nil}. check_capacity(Map, Original_hash) -> case {erlang:element(6, Map), erlang:element(5, Map) >= ((erlang:element(3, Map) * erlang:element( 4, Map )) div 100)} of {false, true} -> gleam@result:'try'( basic_rehash(Map, (erlang:element(3, Map) * 2) + 1), fun(New_map) -> {ok, {erlang:setelement(6, New_map, false), {some, fix_hash( erlang:element(3, New_map), Original_hash )}}} end ); {_, _} -> {ok, {Map, none}} end.