Current section
Files
Jump to
Current section
Files
src/tote@bag.erl
-module(tote@bag).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([new/0, from_map/1, remove_all/2, copies/2, remove/3, insert/3, from_list/1, update/3, contains/2, is_empty/1, fold/3, size/1, intersect/2, merge/2, subtract/2, map/2, filter/2, to_list/1, to_set/1, to_map/1]).
-export_type([bag/1]).
-opaque bag(GBJ) :: {bag, gleam@dict:dict(GBJ, integer())}.
-spec new() -> bag(any()).
new() ->
{bag, gleam@dict:new()}.
-spec from_map(gleam@dict:dict(GBP, integer())) -> bag(GBP).
from_map(Map) ->
{bag, Map}.
-spec remove_all(bag(GBZ), GBZ) -> bag(GBZ).
remove_all(Bag, Item) ->
{bag, gleam@dict:delete(erlang:element(2, Bag), Item)}.
-spec copies(bag(GCF), GCF) -> integer().
copies(Bag, Item) ->
case gleam@dict:get(erlang:element(2, Bag), Item) of
{ok, Copies} ->
Copies;
{error, nil} ->
0
end.
-spec remove(bag(GBW), integer(), GBW) -> bag(GBW).
remove(Bag, To_remove, Item) ->
To_remove@1 = gleam@int:absolute_value(To_remove),
Item_copies = copies(Bag, Item),
case gleam@int:compare(To_remove@1, Item_copies) of
lt ->
{bag,
gleam@dict:insert(
erlang:element(2, Bag),
Item,
Item_copies - To_remove@1
)};
gt ->
remove_all(Bag, Item);
eq ->
remove_all(Bag, Item)
end.
-spec insert(bag(GBT), integer(), GBT) -> bag(GBT).
insert(Bag, To_add, Item) ->
case gleam@int:compare(To_add, 0) of
lt ->
remove(Bag, To_add, Item);
eq ->
Bag;
gt ->
{bag,
gleam@dict:update(
erlang:element(2, Bag),
Item,
fun(N) -> gleam@option:unwrap(N, 0) + To_add end
)}
end.
-spec from_list(list(GBM)) -> bag(GBM).
from_list(List) ->
gleam@list:fold(List, new(), fun(Bag, Item) -> insert(Bag, 1, Item) end).
-spec update(bag(GCC), GCC, fun((integer()) -> integer())) -> bag(GCC).
update(Bag, Item, Fun) ->
Count = copies(Bag, Item),
New_count = Fun(Count),
case gleam@int:compare(New_count, 0) of
lt ->
remove_all(Bag, Item);
eq ->
remove_all(Bag, Item);
gt ->
_pipe = remove_all(Bag, Item),
insert(_pipe, New_count, Item)
end.
-spec contains(bag(GCH), GCH) -> boolean().
contains(Bag, Item) ->
gleam@dict:has_key(erlang:element(2, Bag), Item).
-spec is_empty(bag(any())) -> boolean().
is_empty(Bag) ->
erlang:element(2, Bag) =:= gleam@dict:new().
-spec fold(bag(GCZ), GDB, fun((GDB, GCZ, integer()) -> GDB)) -> GDB.
fold(Bag, Initial, Fun) ->
gleam@dict:fold(erlang:element(2, Bag), Initial, Fun).
-spec size(bag(any())) -> integer().
size(Bag) ->
fold(Bag, 0, fun(Sum, _, Copies) -> Sum + Copies end).
-spec intersect(bag(GCN), bag(GCN)) -> bag(GCN).
intersect(One, Other) ->
fold(
One,
new(),
fun(Acc, Item, Copies_in_one) -> case copies(Other, Item) of
0 ->
Acc;
Copies_in_other ->
insert(
Acc,
gleam@int:min(Copies_in_one, Copies_in_other),
Item
)
end end
).
-spec merge(bag(GCR), bag(GCR)) -> bag(GCR).
merge(One, Other) ->
fold(
One,
Other,
fun(Acc, Item, Copies_in_one) -> insert(Acc, Copies_in_one, Item) end
).
-spec subtract(bag(GCV), bag(GCV)) -> bag(GCV).
subtract(One, Other) ->
fold(
Other,
One,
fun(Acc, Item, Copies_in_other) ->
remove(Acc, Copies_in_other, Item)
end
).
-spec map(bag(GDC), fun((GDC, integer()) -> GDE)) -> bag(GDE).
map(Bag, Fun) ->
fold(
Bag,
new(),
fun(Acc, Item, Copies) -> insert(Acc, Copies, Fun(Item, Copies)) end
).
-spec filter(bag(GDG), fun((GDG, integer()) -> boolean())) -> bag(GDG).
filter(Bag, Predicate) ->
fold(Bag, new(), fun(Acc, Item, Copies) -> case Predicate(Item, Copies) of
true ->
insert(Acc, Copies, Item);
false ->
Acc
end end).
-spec to_list(bag(GDJ)) -> list({GDJ, integer()}).
to_list(Bag) ->
maps:to_list(erlang:element(2, Bag)).
-spec to_set(bag(GDM)) -> gleam@set:set(GDM).
to_set(Bag) ->
gleam@set:from_list(gleam@dict:keys(erlang:element(2, Bag))).
-spec to_map(bag(GDP)) -> gleam@dict:dict(GDP, integer()).
to_map(Bag) ->
erlang:element(2, Bag).