From d89983e861f68bccda8fc1b68ba4a048d7bbf6fb Mon Sep 17 00:00:00 2001 From: Marcin Henryk Bartkowiak Date: Sat, 3 Oct 2015 20:34:31 +0200 Subject: [PATCH 1/4] Elixir 1.1 support --- lib/array.ex | 55 +++++++++++++++++++++++++++++++++------------ test/array_test.exs | 18 +++++++-------- 2 files changed, 50 insertions(+), 23 deletions(-) diff --git a/lib/array.ex b/lib/array.ex index 4fc9639..ffeaf9c 100644 --- a/lib/array.ex +++ b/lib/array.ex @@ -15,7 +15,7 @@ defmodule Array do Creates a new, extendible array with initial size zero. The default value is the atom nil, not undefined. """ - @spec new() :: t + @spec new() :: t def new() do %Array{content: :array.new({:default, nil})} end @@ -85,7 +85,7 @@ defmodule Array do @doc """ Folds the elements of the array using the given function and initial accumulator value. - The elements are visited in order from the lowest index to the highest. + The elements are visited in order from the lowest index to the highest. If `fun` is not a function, the call raises `ArgumentError`. """ @@ -96,7 +96,7 @@ defmodule Array do @doc """ Folds the elements of the array right-to-left using the given function and initial accumulator value. The elements are visited in order from the highest index to the lowest. - + If `fun` is not a function, the call raises `ArgumentError`. """ @spec foldr(t, acc, (index, element, acc -> acc)) :: acc when acc: var @@ -155,11 +155,35 @@ defmodule Array do @doc """ Gets the value of entry `idx`. If `idx` is not a nonnegative integer, or if the array has - fixed size and `idx` is larger than the maximum index, the call raises `ArgumentError`. + fixed size and `idx` is larger than the maximum index, the returns raises :error """ - @spec get(t, index) :: element - def get(%Array{content: c}, idx), - do: :array.get(idx, c) + @spec fetch(t, index) :: element + def fetch(%Array{content: c}, idx) do + cond do + idx in 0..(:array.size(c) - 1) -> {:ok, :array.get(idx, c)} + true -> :error + end + end + + @doc """ + Gets the value of entry `idx`. If `idx` is not a nonnegative integer, or if the array has + fixed size and `idx` is larger than the maximum index it returns default value. + """ + @spec get(t, index, any) :: element + def get(array, idx, default \\ nil) do + case Array.fetch(array, idx) do + {:ok, value} -> value + :error -> default || Array.default(array) + end + end + + @doc """ + Gets and updates the container’s value for the given key, in a single pass. + """ + def get_and_update(arr, idx, fun) do + {get, update} = fun.(Array.get(arr, idx)) + {get, Array.set(arr, idx, update)} + end @doc """ Returns `true` if `arr` appears to be an array, otherwise `false`. @@ -184,7 +208,7 @@ defmodule Array do @doc """ Maps the given function onto each element of the array. The elements are visited in order from the lowest index to the highest. - + If `fun` is not a function, the call raises `ArgumentError`. """ @spec map(t, (index, element -> any)) :: t @@ -260,7 +284,7 @@ defmodule Array do Folds the elements of the array right-to-left using the given function and initial accumulator value, skipping default-valued entries. The elements are visited in order from the highest index to the lowest. - + If `fun` is not a function, the call raises `ArgumentError`. """ @spec sparse_foldr(t, acc, (index, element, acc -> acc)) :: acc when acc: var @@ -270,7 +294,7 @@ defmodule Array do @doc """ Maps the given function onto each element of the array, skipping default-valued entries. The elements are visited in order from the lowest index to the highest. - + If `fun` is not a function, the call raises `ArgumentError`. """ @spec sparse_map(t, (element -> any)) :: t @@ -323,13 +347,16 @@ defmodule Array do end defimpl Access, for: Array do - def get(arr, idx) do - Array.get(arr, idx) + def fetch(arr, idx) do + Array.fetch(arr, idx) + end + + def get(arr, idx, default \\ nil) do + Array.get(arr, idx, default) end def get_and_update(arr, idx, fun) do - {get, update} = fun.(Array.get(arr, idx)) - {get, Array.set(arr, idx, update)} + Array.get_and_update(arr, idx, fun) end end diff --git a/test/array_test.exs b/test/array_test.exs index 5d8af8b..7cabaa1 100644 --- a/test/array_test.exs +++ b/test/array_test.exs @@ -27,9 +27,7 @@ defmodule ArrayTest do assert nil == Array.get(a, 9) - assert_raise ArgumentError, fn -> - Array.get(a, 10) - end + assert nil == Array.get(a, 10) a = Array.set(a, 0, 1) assert 1 == Array.get(a, 0) @@ -87,7 +85,7 @@ defmodule ArrayTest do test "fix" do a = Array.new() a = Array.set(a, 100, 0) - + a = Array.fix(a) assert_raise ArgumentError, fn -> Array.set(a, 101, 0) @@ -293,22 +291,24 @@ defmodule ArrayTest do end end - test "get/set" do + test "get/fetch/set" do a = Array.new() a = Array.set(a, 5, 10) assert nil == Array.get(a, 4) + assert {:ok, nil} == Array.fetch(a, 4) assert 10 == Array.get(a, 5) + assert {:ok, 10} == Array.fetch(a, 5) assert nil == Array.get(a, 6) + assert :error == Array.fetch(a, 6) a = Array.set(a, 0, 100) assert 100 == Array.get(a, 0) assert_raise ArgumentError, fn -> Array.set(a, -1, 1000) end - assert_raise ArgumentError, fn -> - Array.get(a, -1) - end + assert nil == Array.get(a, -1) + assert :error == Array.fetch(a, -1) end test "size" do @@ -405,7 +405,7 @@ defmodule ArrayTest do test "to_erlang_array" do a = Array.from_list([1,2,3]) ea = Array.to_erlang_array(a) - + assert :array.is_array(ea) assert 3 == :array.size(ea) assert 1 == :array.get(0, ea) From 539cdc36ec40505ab8209cf5dea91cf2cc8192c8 Mon Sep 17 00:00:00 2001 From: Marcin Henryk Bartkowiak Date: Sat, 3 Oct 2015 20:39:14 +0200 Subject: [PATCH 2/4] Improved docs --- lib/array.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/array.ex b/lib/array.ex index ffeaf9c..65d640f 100644 --- a/lib/array.ex +++ b/lib/array.ex @@ -155,7 +155,7 @@ defmodule Array do @doc """ Gets the value of entry `idx`. If `idx` is not a nonnegative integer, or if the array has - fixed size and `idx` is larger than the maximum index, the returns raises :error + fixed size and `idx` is larger than the maximum index, the call returns :error """ @spec fetch(t, index) :: element def fetch(%Array{content: c}, idx) do @@ -167,7 +167,7 @@ defmodule Array do @doc """ Gets the value of entry `idx`. If `idx` is not a nonnegative integer, or if the array has - fixed size and `idx` is larger than the maximum index it returns default value. + fixed size and `idx` is larger than the maximum index it returns `default` or array's default value. """ @spec get(t, index, any) :: element def get(array, idx, default \\ nil) do From 1d1290624c9360874cb85093d8268e1b8f540e34 Mon Sep 17 00:00:00 2001 From: Marcin Henryk Bartkowiak Date: Sat, 3 Oct 2015 20:45:43 +0200 Subject: [PATCH 3/4] Removed implementation of the Access protocol --- lib/array.ex | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/lib/array.ex b/lib/array.ex index 65d640f..1486495 100644 --- a/lib/array.ex +++ b/lib/array.ex @@ -346,20 +346,6 @@ defmodule Array do do: :array.to_orddict(c) end -defimpl Access, for: Array do - def fetch(arr, idx) do - Array.fetch(arr, idx) - end - - def get(arr, idx, default \\ nil) do - Array.get(arr, idx, default) - end - - def get_and_update(arr, idx, fun) do - Array.get_and_update(arr, idx, fun) - end -end - defimpl Enumerable, for: Array do def count(arr), do: {:ok, Array.size(arr)} From a670d8ba8c89521216f397b7970477ccb21e23c0 Mon Sep 17 00:00:00 2001 From: Marcin Henryk Bartkowiak Date: Sun, 4 Oct 2015 12:50:59 +0200 Subject: [PATCH 4/4] Bugfix --- lib/array.ex | 1 + test/array_test.exs | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/array.ex b/lib/array.ex index 1486495..cd89853 100644 --- a/lib/array.ex +++ b/lib/array.ex @@ -160,6 +160,7 @@ defmodule Array do @spec fetch(t, index) :: element def fetch(%Array{content: c}, idx) do cond do + :array.size(c) == 0 -> :error idx in 0..(:array.size(c) - 1) -> {:ok, :array.get(idx, c)} true -> :error end diff --git a/test/array_test.exs b/test/array_test.exs index 7cabaa1..ce8f60e 100644 --- a/test/array_test.exs +++ b/test/array_test.exs @@ -309,6 +309,10 @@ defmodule ArrayTest do end assert nil == Array.get(a, -1) assert :error == Array.fetch(a, -1) + + a = Array.from_list([]) + assert :error == Array.fetch(a, 0) + assert 0 == Array.get(a, 0, 0) end test "size" do @@ -423,7 +427,7 @@ defmodule ArrayTest do assert [{0, 1}, {1, 2}, {2, 3}] == Array.to_orddict(a) end - test "Access.get" do + test "Access.fetch" do a = Array.from_list([1,2,3]) assert 1 == a[0] assert 2 == a[1]