Current section
Files
Jump to
Current section
Files
src/glib@map.erl
-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.