-module(metamon@transform@list). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/metamon/transform/list.gleam"). -export([reverse/0, dedupe/0, prepend/1, append/1, shuffle/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( " Standard `Transform(List(a))` constructors used in metamorphic\n" " relations. Each transform is named and deterministic.\n" ). -file("src/metamon/transform/list.gleam", 10). ?DOC(" Reverse the list.\n"). -spec reverse() -> metamon@transform:transform(list(any())). reverse() -> metamon@transform:new(<<"list.reverse"/utf8>>, fun lists:reverse/1). -file("src/metamon/transform/list.gleam", 23). -spec loop_dedupe(list(HPZ), list(HPZ), list(HPZ)) -> list(HPZ). loop_dedupe(Items, Seen, Acc) -> case Items of [] -> lists:reverse(Acc); [First | Rest] -> case gleam@list:contains(Seen, First) of true -> loop_dedupe(Rest, Seen, Acc); false -> loop_dedupe(Rest, [First | Seen], [First | Acc]) end end. -file("src/metamon/transform/list.gleam", 19). -spec dedupe_keep_first(list(HPW)) -> list(HPW). dedupe_keep_first(Items) -> loop_dedupe(Items, [], []). -file("src/metamon/transform/list.gleam", 15). ?DOC(" Drop duplicates, keeping the first occurrence of each element.\n"). -spec dedupe() -> metamon@transform:transform(list(any())). dedupe() -> metamon@transform:new(<<"list.dedupe"/utf8>>, fun dedupe_keep_first/1). -file("src/metamon/transform/list.gleam", 35). ?DOC(" Prepend `value` to the list.\n"). -spec prepend(HQE) -> metamon@transform:transform(list(HQE)). prepend(Value) -> metamon@transform:new( <<"list.prepend"/utf8>>, fun(Items) -> [Value | Items] end ). -file("src/metamon/transform/list.gleam", 40). ?DOC(" Append `value` to the list.\n"). -spec append(HQH) -> metamon@transform:transform(list(HQH)). append(Value) -> metamon@transform:new( <<"list.append"/utf8>>, fun(Items) -> lists:append(Items, [Value]) end ). -file("src/metamon/transform/list.gleam", 62). -spec assign_keys_and_sort(list(HQQ), metamon@generator@seed:seed(), integer()) -> list(HQQ). assign_keys_and_sort(Items, S, Length) -> Keyed = gleam@list:fold( Items, {S, []}, fun(Acc, Value) -> {State, Keyed_acc} = Acc, {Key, Next_state} = metamon@generator@seed:next_int_in( State, 0, Length * 100 ), {Next_state, [{Key, Value} | Keyed_acc]} end ), {_, With_keys} = Keyed, _pipe = With_keys, _pipe@1 = gleam@list:sort( _pipe, fun(Left, Right) -> gleam@int:compare(erlang:element(1, Left), erlang:element(1, Right)) end ), gleam@list:map(_pipe@1, fun(Pair) -> erlang:element(2, Pair) end). -file("src/metamon/transform/list.gleam", 54). -spec shuffle_with(list(HQN), metamon@generator@seed:seed()) -> list(HQN). shuffle_with(Items, S) -> Length = erlang:length(Items), case Length =< 1 of true -> Items; false -> assign_keys_and_sort(Items, S, Length) end. -file("src/metamon/transform/list.gleam", 48). ?DOC( " A deterministic shuffle parametrised by a seed integer. The same\n" " integer always produces the same permutation. Implemented as a\n" " stable sort by random keys (Knuth's \"decorate, sort, undecorate\"\n" " pattern).\n" ). -spec shuffle(integer()) -> metamon@transform:transform(list(any())). shuffle(Seed_value) -> metamon@transform:new( <<<<"list.shuffle("/utf8, (erlang:integer_to_binary(Seed_value))/binary>>/binary, ")"/utf8>>, fun(Items) -> shuffle_with(Items, metamon@generator@seed:seed(Seed_value)) end ).