-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) ).