-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]). -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( " Maps are a structure similar to dict in that they map keys to values.\n" " Duplicate keys cannot exist and a key can map to at most one value\n" " \n" " The Keys are strings, values can be any type but values must be of the same type\n" " \n" " Maps are unordered\n" ). -type entry(HWP) :: {entry, binary(), HWP}. -opaque map_(HWQ) :: {map, glib@treelist:tree_list(gleam@option:option(entry(HWQ))), integer(), integer(), integer(), boolean()}. -file("src/glib/map.gleam", 115). ?DOC( " Determines the size of the map, i.e. the number of key/values\n" " \n" " ## Examples\n" " \n" " ```gleam\n" " new() |> size\n" " // -> 0\n" " ```\n" " \n" " ```gleam\n" " new() |> put(\"key\", \"value\") |> size\n" " // -> 1\n" " ```\n" ). -spec size(map_(any())) -> integer(). size(Map) -> erlang:element(5, Map). -file("src/glib/map.gleam", 97). ?DOC( " Determines whether the map is empty, i.e. contains no key/values\n" " \n" " ## Examples\n" " \n" " ```gleam\n" " new() |> is_empty\n" " // -> True\n" " ```\n" " \n" " ```gleam\n" " new() |> put(\"key\", \"value\") |> is_empty\n" " // -> False\n" " ```\n" ). -spec is_empty(map_(any())) -> boolean(). is_empty(Map) -> size(Map) =:= 0. -file("src/glib/map.gleam", 306). ?DOC( " Returns a list of the keys contained in the map\n" " \n" " ## Examples\n" " \n" " ```gleam\n" " new() |> keys\n" " // -> []\n" " ```\n" " \n" " ``` gleam\n" " new() |> put(\"key\", \"value\") |> keys\n" " // -> [\"key\"]\n" " ```\n" ). -spec keys(map_(any())) -> list(binary()). keys(Map) -> _pipe = glib@treelist:to_iterator(erlang:element(2, Map)), _pipe@1 = gleam@yielder:filter_map(_pipe, fun(E) -> case E of none -> {error, nil}; {some, En} -> {ok, erlang:element(2, En)} end end), gleam@yielder:to_list(_pipe@1). -file("src/glib/map.gleam", 331). ?DOC( " Returns a list of the values contained in the map\n" " \n" " ## Examples\n" " \n" " ```gleam\n" " new() |> values\n" " // -> []\n" " ```\n" " \n" " ``` gleam\n" " new() |> put(\"key\", \"value\") |> values\n" " // -> [\"value\"]\n" " ```\n" ). -spec values(map_(HYH)) -> list(HYH). values(Map) -> _pipe = glib@treelist:to_iterator(erlang:element(2, Map)), _pipe@1 = gleam@yielder:filter_map(_pipe, fun(E) -> case E of none -> {error, nil}; {some, En} -> {ok, erlang:element(3, En)} end end), gleam@yielder:to_list(_pipe@1). -file("src/glib/map.gleam", 356). ?DOC( " Returns a list of the tuples #(key, value) contained in the map\n" " \n" " ## Examples\n" " \n" " ```gleam\n" " new() |> entries\n" " // -> []\n" " ```\n" " \n" " ``` gleam\n" " new() |> put(\"key\", \"value\") |> entries\n" " // -> [#(\"key\", \"value\")]\n" " ```\n" ). -spec entries(map_(HYK)) -> list({binary(), HYK}). entries(Map) -> _pipe = glib@treelist:to_iterator(erlang:element(2, Map)), _pipe@1 = gleam@yielder: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@yielder:to_list(_pipe@1). -file("src/glib/map.gleam", 382). ?DOC( " Returns a string representation of the passed map\n" " Requires a value_to_string fn to generate the output\n" " \n" " ## Examples\n" " \n" " ```gleam\n" " new() |> to_string(fn(v) { v })\n" " // -> {}\n" " ```\n" " \n" " ```gleam\n" " new() |> put(\"key\", \"value\") |> to_string(fn(v) { v })\n" " // -> {\"key\": \"value\"}\n" " ```\n" ). -spec to_string(map_(HYN), fun((HYN) -> 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@yielder: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@yielder:to_list(_pipe@1) end, <<","/utf8>> ))/binary>>/binary, "}"/utf8>>}. -file("src/glib/map.gleam", 404). -spec do_remove(map_(HYR), integer(), HYR) -> {ok, {gleam@option:option(HYR), map_(HYR)}} | {error, nil}. do_remove(Map, Index, Value) -> gleam@result:'try'( glib@treelist:set(erlang:element(2, Map), Index, none), fun(Entry) -> New_map = begin _record = Map, {map, Entry, erlang:element(3, _record), erlang:element(4, _record), erlang:element(5, Map) - 1, erlang:element(6, _record)} end, {ok, {{some, Value}, New_map}} end ). -file("src/glib/map.gleam", 438). -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 ). -file("src/glib/map.gleam", 472). -spec find_key( map_(HZH), binary(), integer(), integer(), fun((integer(), HZH) -> HZJ) ) -> {ok, gleam@option:option(HZJ)} | {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 ). -file("src/glib/map.gleam", 497). -spec ret_value(integer(), HZN) -> HZN. ret_value(_, Value) -> Value. -file("src/glib/map.gleam", 501). -spec ret_exists(integer(), any()) -> boolean(). ret_exists(_, _) -> true. -file("src/glib/map.gleam", 505). -spec ret_index_and_value(integer(), HZP) -> {integer(), HZP}. ret_index_and_value(Index, Value) -> {Index, Value}. -file("src/glib/map.gleam", 622). -spec prepend_none(integer(), list(gleam@option:option(entry(HZV)))) -> list(gleam@option:option(entry(HZV))). prepend_none(Times, Acc) -> case Times =< 0 of true -> Acc; false -> prepend_none(Times - 1, [none | Acc]) end. -file("src/glib/map.gleam", 629). -spec do_repeat(IAA, integer(), list(IAA)) -> list(IAA). do_repeat(A, Times, Acc) -> case Times =< 0 of true -> Acc; false -> do_repeat(A, Times, [A | Acc]) end. -file("src/glib/map.gleam", 636). -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. -file("src/glib/map.gleam", 644). -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}. -file("src/glib/map.gleam", 194). ?DOC( " Retrieves the option wrapped value from the map for the stored key\n" " \n" " The key may not exist so then None is returned\n" " \n" " ## Examples\n" " \n" " ```gleam\n" " new() |> put(\"key\", \"value\") |> get(\"key\")\n" " // -> Ok(\"value\")\n" " ```\n" " \n" " ```gleam\n" " new() |> put(\"key\", \"value\") |> get(\"non-existent\")\n" " // -> None\n" " ```\n" ). -spec get(map_(HXR), binary()) -> {ok, gleam@option:option(HXR)} | {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 ). -file("src/glib/map.gleam", 225). ?DOC( " Returns the existence in the map for the stored key\n" " \n" " \n" " ## Examples\n" " \n" " ```gleam\n" " new() |> put(\"key\", \"value\") |> contains_key(\"key\")\n" " // -> True\n" " ```\n" " \n" " ```gleam\n" " new() |> put(\"key\", \"value\") |> contains_key(\"non-existent\")\n" " // -> False\n" " ```\n" ). -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. -file("src/glib/map.gleam", 262). ?DOC( " Removes the specified key from the map and returns a tuple containing\n" " the removed option wrapped value or None and the altered map without the\n" " specified key\n" " \n" " ## Examples\n" " \n" " ```gleam\n" " new() |> put(\"key\", \"value\") |> remove(\"key\")\n" " // -> #(Some(\"value\"), {})\n" " ```\n" " \n" " ```gleam\n" " new() |> put(\"key\", \"value\") |> remove(\"non-existent\")\n" " // -> #(None, {\"key\": \"value\"})\n" " ```\n" ). -spec remove(map_(HXY), binary()) -> {ok, {gleam@option:option(HXY), map_(HXY)}} | {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 ). -file("src/glib/map.gleam", 651). ?DOC( " Returns the internal storage size of the map\n" " This is mainly for testing use\n" ). -spec list_size(map_(any())) -> integer(). list_size(Map) -> glib@treelist:size(erlang:element(2, Map)). -file("src/glib/map.gleam", 659). ?DOC( " Returns a count of the number of entries in the map\n" " This is used for testing to compare against the cached size\n" " Performs a full iteration of the list incrementing for all Some(_)\n" " entries\n" ). -spec full_count(map_(any())) -> integer(). full_count(Map) -> _pipe = glib@treelist:to_iterator(erlang:element(2, Map)), gleam@yielder:fold(_pipe, 0, fun(Acc, E) -> case E of none -> Acc; {some, _} -> Acc + 1 end end). -file("src/glib/map.gleam", 59). ?DOC( " Creates an empty map with specified size and loading factor\n" " load is a value 0->1 (non-inclusive) which specifies a percentage (e.g. 0.5 is 50%)\n" " at which point the backing list is resized\n" " This should be kept around 0.6-0.8 to avoid either excessive resizing or\n" " excessive key hash collisions\n" ). -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, erlang:round(Load@1), 0, false}} end ). -file("src/glib/map.gleam", 49). ?DOC( " Creates an empty map with specified size\n" " The loading factor is set to default\n" ). -spec new_with_size(integer()) -> {ok, map_(any())} | {error, nil}. new_with_size(Size) -> new_with_size_and_load(Size, 0.75). -file("src/glib/map.gleam", 43). ?DOC( " Creates an empty map\n" " The size and loading factor are set to the default\n" " The size is the starting size for the list that contains the values\n" " The loading factor is the value 0 -> 1 that determines when the\n" " list is resized. This is the percentage of the backing list that is filled.\n" " For example, if the loading factor was 0.5 then when one half of the backing\n" " list is populated, the next addition to the Map will trigger a resize to\n" " ensure the map has usable space\n" ). -spec new() -> {ok, map_(any())} | {error, nil}. new() -> new_with_size(11). -file("src/glib/map.gleam", 76). ?DOC( " Creates a new empty map with the same sizing/loading properties as the\n" " passed map\n" ). -spec clear(map_(HXD)) -> {ok, map_(HXD)} | {error, nil}. clear(Previous_map) -> new_with_size_and_load( erlang:element(3, Previous_map), erlang:float(erlang:element(4, Previous_map)) / 100.0 ). -file("src/glib/map.gleam", 607). -spec basic_rehash(map_(HZQ), integer()) -> {ok, map_(HZQ)} | {error, nil}. basic_rehash(Map, New_size) -> gleam@result:'try'( new_with_size_and_load( New_size, erlang:float(erlang:element(4, Map)) / 100.0 ), fun(New_map) -> _pipe = glib@treelist:to_iterator(erlang:element(2, Map)), gleam@yielder:try_fold( _pipe, begin _record = New_map, {map, erlang:element(2, _record), erlang:element(3, _record), erlang:element(4, _record), erlang:element(5, _record), true} end, 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 ). -file("src/glib/map.gleam", 140). ?DOC( " Inserts a value into the map with the given key\n" " \n" " Will replace value if key already exists\n" " \n" " ## Examples\n" " \n" " ```gleam\n" " new() |> put(\"key\", 999) |> to_string(fn(i) { int.to_string(i) })\n" " // -> {\"key\":999}\n" " ```\n" " \n" " ```gleam\n" " new() |> put(\"key\", 999) |> put(\"key2\", 111) |> to_string(fn(i) { int.to_string(i) })\n" " // -> {\"key\":999, \"key2\":111}\n" " ```\n" " \n" " ```gleam\n" " new() |> put(\"key\", 999) |> put(\"key\", 123) |> to_string(fn(i) { int.to_string(i) })\n" " // -> {\"key\":123}\n" " ```\n" ). -spec put(map_(HXM), binary(), HXM) -> {ok, map_(HXM)} | {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, begin _record = Map@2, {map, Inner, erlang:element(3, _record), erlang:element(4, _record), case Overwrite@1 of true -> erlang:element(5, Map@2); false -> erlang:element(5, Map@2) + 1 end, erlang:element(6, _record)} end} end ) end) end ). -file("src/glib/map.gleam", 421). ?DOC( " Checks whether the current map contains >= load entries\n" " If so return a tuple containing the new resized map and the new hash of the \n" " key we are currently processing\n" " Otherwise just return the a tuple containing the original map and None to signify\n" " no change to the capacity\n" ). -spec check_capacity(map_(HYX), integer()) -> {ok, {map_(HYX), 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, {begin _record = New_map, {map, erlang:element(2, _record), erlang:element(3, _record), erlang:element(4, _record), erlang:element(5, _record), false} end, {some, fix_hash( erlang:element(3, New_map), Original_hash )}}} end ); {_, _} -> {ok, {Map, none}} end.