Packages

A list-like data structure that maintains a selected element

Current section

Files

Jump to
zip_list src zip_list.erl
Raw

src/zip_list.erl

-module(zip_list).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([new/3, singleton/1, from_list/1, from_list_by/2, to_list/1, first/1, jump/2, last/1, next_try/1, next/1, forward/2, next_warp/1, previous_try/1, previous/1, backwards/2, previous_warp/1, append_next/2, append_previous/2, current_map/2, filter/2, index_map/2, map/2, prepend_next/2, prepend_previous/2, remove_try/1, remove/1, remove_backwards/1, replace/2, get_all_next/1, get_all_previous/1, current/1, index/1, get_next/1, get_previous/1, is_first/1, is_last/1, length/1]).
-export_type([zip_list/1]).
-opaque zip_list(MAU) :: {zip_list, list(MAU), MAU, list(MAU)}.
-spec new(list(MAV), MAV, list(MAV)) -> zip_list(MAV).
new(Previous, Current, Next) ->
{zip_list, Previous, Current, Next}.
-spec singleton(MAZ) -> zip_list(MAZ).
singleton(Current) ->
{zip_list, [], Current, []}.
-spec from_list(list(MBB)) -> {ok, zip_list(MBB)} | {error, nil}.
from_list(List) ->
case List of
[] ->
{error, nil};
[Head | Tail] ->
{ok, {zip_list, [], Head, Tail}}
end.
-spec from_list_by_helper(list(MBL), fun((MBL) -> boolean()), list(MBL)) -> {ok,
zip_list(MBL)} |
{error, nil}.
from_list_by_helper(Previous, Predicate, Remaining) ->
case Remaining of
[] ->
{error, nil};
[Head | Tail] ->
case Predicate(Head) of
true ->
{ok, {zip_list, Previous, Head, Tail}};
false ->
from_list_by_helper(
lists:append(Previous, [Head]),
Predicate,
Tail
)
end
end.
-spec from_list_by(list(MBG), fun((MBG) -> boolean())) -> {ok, zip_list(MBG)} |
{error, nil}.
from_list_by(List, Predicate) ->
from_list_by_helper([], Predicate, List).
-spec to_list(zip_list(MBR)) -> list(MBR).
to_list(Zip_list) ->
lists:append(
erlang:element(2, Zip_list),
[erlang:element(3, Zip_list) | erlang:element(4, Zip_list)]
).
-spec first(zip_list(MBX)) -> zip_list(MBX).
first(Zip_list) ->
{New_current, Previous_tail} = case erlang:element(2, Zip_list) of
[] ->
{erlang:element(3, Zip_list), []};
[Head | Tail] ->
{Head, Tail}
end,
{zip_list,
[],
New_current,
lists:append(
Previous_tail,
[erlang:element(3, Zip_list) | erlang:element(4, Zip_list)]
)}.
-spec jump(zip_list(MCD), integer()) -> zip_list(MCD).
jump(Zip_list, Index) ->
{First, Second} = begin
_pipe = Zip_list,
_pipe@1 = to_list(_pipe),
gleam@list:split(_pipe@1, Index)
end,
{Previous, Current, Next} = case {lists:reverse(First), Second} of
{[], []} ->
{erlang:element(2, Zip_list),
erlang:element(3, Zip_list),
erlang:element(4, Zip_list)};
{_, [Head | Tail]} ->
{First, Head, Tail};
{[Head@1 | Tail@1], []} ->
{lists:reverse(Tail@1), Head@1, Second}
end,
{zip_list, Previous, Current, Next}.
-spec last(zip_list(MCG)) -> zip_list(MCG).
last(Zip_list) ->
{New_current, Next_tail} = case lists:reverse(erlang:element(4, Zip_list)) of
[] ->
{erlang:element(3, Zip_list), []};
[Head | Tail] ->
{Head, lists:reverse(Tail)}
end,
{zip_list,
lists:append(
erlang:element(2, Zip_list),
[erlang:element(3, Zip_list) | Next_tail]
),
New_current,
[]}.
-spec next_try(zip_list(MCM)) -> {ok, zip_list(MCM)} | {error, nil}.
next_try(Zip_list) ->
case erlang:element(4, Zip_list) of
[] ->
{error, nil};
[Head | Tail] ->
{ok,
{zip_list,
lists:append(
erlang:element(2, Zip_list),
[erlang:element(3, Zip_list)]
),
Head,
Tail}}
end.
-spec next(zip_list(MCJ)) -> zip_list(MCJ).
next(Zip_list) ->
case next_try(Zip_list) of
{ok, New_zip_list} ->
New_zip_list;
{error, _} ->
Zip_list
end.
-spec forward(zip_list(MCA), integer()) -> zip_list(MCA).
forward(Zip_list, Times) ->
gleam@bool:guard(
erlang:element(4, Zip_list) =:= [],
Zip_list,
fun() -> case Times of
0 ->
Zip_list;
_ ->
forward(next(Zip_list), Times - 1)
end end
).
-spec next_warp(zip_list(MCR)) -> zip_list(MCR).
next_warp(Zip_list) ->
case next_try(Zip_list) of
{ok, New_zip_list} ->
New_zip_list;
{error, _} ->
first(Zip_list)
end.
-spec previous_try(zip_list(MCX)) -> {ok, zip_list(MCX)} | {error, nil}.
previous_try(Zip_list) ->
Previous_reversed = lists:reverse(erlang:element(2, Zip_list)),
case Previous_reversed of
[] ->
{error, nil};
[Head | Tail] ->
{ok,
{zip_list,
lists:reverse(Tail),
Head,
[erlang:element(3, Zip_list) | erlang:element(4, Zip_list)]}}
end.
-spec previous(zip_list(MCU)) -> zip_list(MCU).
previous(Zip_list) ->
case previous_try(Zip_list) of
{ok, New_zip_list} ->
New_zip_list;
{error, _} ->
Zip_list
end.
-spec backwards(zip_list(MBU), integer()) -> zip_list(MBU).
backwards(Zip_list, Times) ->
gleam@bool:guard(
erlang:element(2, Zip_list) =:= [],
Zip_list,
fun() -> case Times of
0 ->
Zip_list;
_ ->
backwards(previous(Zip_list), Times - 1)
end end
).
-spec previous_warp(zip_list(MDC)) -> zip_list(MDC).
previous_warp(Zip_list) ->
case previous_try(Zip_list) of
{ok, New_zip_list} ->
New_zip_list;
{error, _} ->
last(Zip_list)
end.
-spec append_next(zip_list(MDF), list(MDF)) -> zip_list(MDF).
append_next(Zip_list, Next) ->
{zip_list,
erlang:element(2, Zip_list),
erlang:element(3, Zip_list),
lists:append(erlang:element(4, Zip_list), Next)}.
-spec append_previous(zip_list(MDJ), list(MDJ)) -> zip_list(MDJ).
append_previous(Zip_list, Previous) ->
{zip_list,
lists:append(erlang:element(2, Zip_list), Previous),
erlang:element(3, Zip_list),
erlang:element(4, Zip_list)}.
-spec current_map(zip_list(MDN), fun((MDN, boolean()) -> MDN)) -> zip_list(MDN).
current_map(Zip_list, F) ->
F_with_flag = fun(Element) -> F(Element, false) end,
{zip_list,
gleam@list:map(erlang:element(2, Zip_list), F_with_flag),
F(erlang:element(3, Zip_list), true),
gleam@list:map(erlang:element(4, Zip_list), F_with_flag)}.
-spec filter(zip_list(MDQ), fun((MDQ) -> boolean())) -> {ok, zip_list(MDQ)} |
{error, nil}.
filter(Zip_list, F) ->
Filtered_previous = gleam@list:filter(erlang:element(2, Zip_list), F),
Filtered_next = gleam@list:filter(erlang:element(4, Zip_list), F),
Filtered_current = case F(erlang:element(3, Zip_list)) of
true ->
{ok, erlang:element(3, Zip_list)};
false ->
{error, nil}
end,
case Filtered_current of
{ok, Current} ->
{ok, {zip_list, Filtered_previous, Current, Filtered_next}};
{error, _} ->
case {lists:reverse(Filtered_previous), Filtered_next} of
{[], []} ->
{error, nil};
{_, [Head | Tail]} ->
{ok, {zip_list, Filtered_previous, Head, Tail}};
{[Head@1 | Tail@1], []} ->
{ok,
{zip_list, lists:reverse(Tail@1), Head@1, Filtered_next}}
end
end.
-spec index_map(zip_list(MDV), fun((MDV, integer()) -> MDX)) -> zip_list(MDX).
index_map(Zip_list, F) ->
Previous_length = erlang:length(erlang:element(2, Zip_list)),
{zip_list,
gleam@list:index_map(erlang:element(2, Zip_list), F),
F(erlang:element(3, Zip_list), Previous_length),
gleam@list:index_map(
erlang:element(4, Zip_list),
fun(Element, Index) -> F(Element, (Index + Previous_length) + 1) end
)}.
-spec map(zip_list(MDZ), fun((MDZ) -> MEB)) -> zip_list(MEB).
map(Zip_list, F) ->
{zip_list,
gleam@list:map(erlang:element(2, Zip_list), F),
F(erlang:element(3, Zip_list)),
gleam@list:map(erlang:element(4, Zip_list), F)}.
-spec prepend_next(zip_list(MED), list(MED)) -> zip_list(MED).
prepend_next(Zip_list, Next) ->
{zip_list,
erlang:element(2, Zip_list),
erlang:element(3, Zip_list),
lists:append(Next, erlang:element(4, Zip_list))}.
-spec prepend_previous(zip_list(MEH), list(MEH)) -> zip_list(MEH).
prepend_previous(Zip_list, Previous) ->
{zip_list,
lists:append(Previous, erlang:element(2, Zip_list)),
erlang:element(3, Zip_list),
erlang:element(4, Zip_list)}.
-spec remove_try(zip_list(MER)) -> {ok, zip_list(MER)} | {error, nil}.
remove_try(Zip_list) ->
case {erlang:element(4, Zip_list),
lists:reverse(erlang:element(2, Zip_list))} of
{[], []} ->
{error, nil};
{[Head | Tail], _} ->
{ok,
erlang:setelement(4, erlang:setelement(3, Zip_list, Head), Tail)};
{_, [Head@1 | Tail@1]} ->
{ok,
erlang:setelement(
2,
erlang:setelement(3, Zip_list, Head@1),
lists:reverse(Tail@1)
)}
end.
-spec remove(zip_list(MEL)) -> zip_list(MEL).
remove(Zip_list) ->
case remove_try(Zip_list) of
{ok, New_zip_list} ->
New_zip_list;
{error, _} ->
Zip_list
end.
-spec remove_backwards(zip_list(MEO)) -> zip_list(MEO).
remove_backwards(Zip_list) ->
case remove_try(Zip_list) of
{ok, New_zip_list} ->
previous(New_zip_list);
{error, _} ->
Zip_list
end.
-spec replace(zip_list(MEW), MEW) -> zip_list(MEW).
replace(Zip_list, New_current) ->
erlang:setelement(3, Zip_list, New_current).
-spec get_all_next(zip_list(MEZ)) -> list(MEZ).
get_all_next(Zip_list) ->
erlang:element(4, Zip_list).
-spec get_all_previous(zip_list(MFC)) -> list(MFC).
get_all_previous(Zip_list) ->
erlang:element(2, Zip_list).
-spec current(zip_list(MFF)) -> MFF.
current(Zip_list) ->
erlang:element(3, Zip_list).
-spec index(zip_list(any())) -> integer().
index(Zip_list) ->
erlang:length(erlang:element(2, Zip_list)).
-spec get_next(zip_list(MFJ)) -> {ok, MFJ} | {error, nil}.
get_next(Zip_list) ->
case erlang:element(4, Zip_list) of
[] ->
{error, nil};
[Head | _] ->
{ok, Head}
end.
-spec get_previous(zip_list(MFN)) -> {ok, MFN} | {error, nil}.
get_previous(Zip_list) ->
case lists:reverse(erlang:element(2, Zip_list)) of
[] ->
{error, nil};
[Head | _] ->
{ok, Head}
end.
-spec is_first(zip_list(any())) -> boolean().
is_first(Zip_list) ->
gleam@list:is_empty(erlang:element(2, Zip_list)).
-spec is_last(zip_list(any())) -> boolean().
is_last(Zip_list) ->
gleam@list:is_empty(erlang:element(4, Zip_list)).
-spec length(zip_list(any())) -> integer().
length(Zip_list) ->
(erlang:length(erlang:element(2, Zip_list)) + 1) + erlang:length(
erlang:element(4, Zip_list)
).