Skip to content

Commit

Permalink
Stripped out pop from ErlangArray.
Browse files Browse the repository at this point in the history
TODO: Think about how to deal with difference w.r.t. handling of `default`.
  • Loading branch information
Qqwy committed Sep 6, 2021
1 parent a48e81e commit 8a2493a
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 54 deletions.
4 changes: 2 additions & 2 deletions lib/arrays.ex
Original file line number Diff line number Diff line change
Expand Up @@ -141,11 +141,11 @@ contents = quote do
iex> arr = Arrays.new([1, -4, 33, 5])
iex> {33, arr} = pop_in(arr[-2])
** (ArgumentError) There is no efficient implementation possible to remove an element from a random location in an array, so `Access.pop/2` (and returning `:pop` from `Access.get_and_update/3` ) are not supported by Elixir.Arrays.Implementations.MapArray. If you want to remove the last element, use `Arrays.extract/1`.
** (ArgumentError) There is no efficient implementation possible to remove an element from a random location in an array, so `Access.pop/2` (and returning `:pop` from `Access.get_and_update/3` ) are not supported by #{@current_default_array}. If you want to remove the last element, use `Arrays.extract/1`.
iex> arr2 = Arrays.new([10, 20, 30])
iex> {20, arr2} = get_and_update_in(arr2[1], fn _ -> :pop end)
** (ArgumentError) There is no efficient implementation possible to remove an element from a random location in an array, so `Access.pop/2` (and returning `:pop` from `Access.get_and_update/3` ) are not supported by Elixir.Arrays.Implementations.MapArray. If you want to remove the last element, use `Arrays.extract/1`.
** (ArgumentError) There is no efficient implementation possible to remove an element from a random location in an array, so `Access.pop/2` (and returning `:pop` from `Access.get_and_update/3` ) are not supported by #{@current_default_array}. If you want to remove the last element, use `Arrays.extract/1`.
iex> arr2 = Arrays.new([10, 20, 30])
iex> {:ok, {value, arr2}} = Arrays.extract(arr2)
Expand Down
75 changes: 24 additions & 51 deletions lib/arrays/implementations/erlang_array.ex
Original file line number Diff line number Diff line change
Expand Up @@ -88,22 +88,22 @@ defmodule Arrays.Implementations.ErlangArray do
end
end

@undefined_pop_message """
There is no efficient implementation possible to remove an element from a random location in an array, so `Access.pop/2` (and returning `:pop` from `Access.get_and_update/3` ) are not supported by #{inspect(__MODULE__)}. If you want to remove the last element, use `Arrays.extract/1`.
""" |> String.trim

@impl Access
def get_and_update(array = %ErlangArray{contents: contents}, index, function) when index >= 0 do
if index >= :array.size(contents) do
raise ArgumentError
else
value = :array.get(index, contents)

case function.(value) do
:pop ->
value = :array.get(index, contents)
new_contents = fix_contents_after_pop(contents, index, :array.default(contents))
{value, %ErlangArray{array | contents: new_contents}}

{get, new_value} ->
new_contents = :array.set(index, new_value, contents)
{get, %ErlangArray{array | contents: new_contents}}
:pop ->
raise ArgumentError, @undefined_pop_message
end
end
end
Expand All @@ -118,49 +118,8 @@ defmodule Arrays.Implementations.ErlangArray do
end

@impl Access
def pop(array = %ErlangArray{contents: contents}, index) when index >= 0 do
cond do
(index >= :array.size(contents)) ->
raise ArgumentError
(index == :array.size(contents) - 1) ->
# Fast implementation
value = :array.get(index, contents)
new_contents = :array.resize(index, contents)
{value, %ErlangArray{array | contents: new_contents}}
true ->
# Slow implementation
value = :array.get(index, contents)
new_contents = fix_contents_after_pop(contents, index, :array.default(contents))
{value, %ErlangArray{array | contents: new_contents}}
end
end

def pop(array = %ErlangArray{contents: contents}, index) when index < 0 do
if (index < (-:array.size(contents))) do
raise ArgumentError
else
pop(array, index + :array.size(contents))
end
end

defp fix_contents_after_pop(contents, index, default) do
contents
|> do_foldl([], fn key, value, acc ->
cond do
key > index ->
[{key - 1, value} | acc]
key == index ->
acc # Leave out popped element
key < index ->
[{key, value} | acc]
end
end)
|> Enum.reverse()
|> :array.from_orddict(default)
end

defp do_foldl(arr, acc, fun) do
:array.foldl(fun, acc, arr)
def pop(%ErlangArray{}, _index) do
raise ArgumentError, @undefined_pop_message
end

@doc false
Expand Down Expand Up @@ -239,11 +198,25 @@ defmodule Arrays.Implementations.ErlangArray do
end

@impl true
def resize(array = %ErlangArray{contents: contents}, new_size) do
new_contents = :array.resize(new_size, contents)
def resize(array = %ErlangArray{contents: contents}, new_size, default) do
IO.inspect(contents)
changed = change_default(contents, default)
IO.inspect(changed)
new_contents = :array.resize(new_size, changed)
IO.inspect(new_contents)
%ErlangArray{array | contents: new_contents}
end

defp change_default(raw_array, new_default) do
sparse_size = :array.sparse_size(raw_array)
size = :array.size(raw_array)
{:array, a, b, _old_default, vals} = raw_array
new_array = {:array, a, b, new_default, vals}
Enum.reduce(sparse_size..(size - 1), new_array, fn index, arr ->
:array.reset(index, arr)
end)
end

@impl true
def extract(array = %ErlangArray{contents: contents}) do
case :array.size(contents) do
Expand Down
2 changes: 1 addition & 1 deletion lib/arrays/implementations/map_array.ex
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ defmodule Arrays.Implementations.MapArray do
def fetch(%MapArray{}, _index), do: :error

@undefined_pop_message """
There is no efficient implementation possible to remove an element from a random location in an array, so `Access.pop/2` (and returning `:pop` from `Access.get_and_update/3` ) are not supported by #{__MODULE__}. If you want to remove the last element, use `Arrays.extract/1`.
There is no efficient implementation possible to remove an element from a random location in an array, so `Access.pop/2` (and returning `:pop` from `Access.get_and_update/3` ) are not supported by #{inspect(__MODULE__)}. If you want to remove the last element, use `Arrays.extract/1`.
""" |> String.trim

@impl Access
Expand Down

0 comments on commit 8a2493a

Please sign in to comment.