Skip to content

Commit

Permalink
Bump version to 1.2.0: ErlangArray.from_raw / ErlangArray.to_raw
Browse files Browse the repository at this point in the history
  • Loading branch information
Qqwy committed Sep 5, 2021
1 parent be39e46 commit 4586fa2
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 19 deletions.
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,10 +288,32 @@ You can look at the source code of `Arrays.CommonProtocolImplementations` for so

## Changelog

- 1.2.0 - Adds `ErlangArray.from_raw/1` and `ErlangArray.to_raw/1` for interop with `:array`-records created/consumed by other code.
- 1.1.0 - Improved README and general usage examples. Introduces `Arrays.concat/1`, `Arrays.concat/2`, `Arrays.slice/2`, `Arrays.slice/3`.
- 1.0.0 - Stable release. Mayor overhaul, 100% test coverage, 100% documentation.
- 0.1.0 - Initial version.

## Roadmap

- [x] Add some simple benchmarks
- [x] Appending a single element
- [x] Random element access
- [x] Random element update
- [x] Concatenate two collections
- [x] Add `from_raw` and `to_raw` functions to ErlangArray to work with pre-existing code that operates on the raw `:array` record itself.
- [ ] Add more benchmarks:
- [ ] Resizing collection (smaller)
- [ ] Resizing collection (larger)
- [ ] Removing a single element
- [ ] Removing all elements one-by-one until the array is empty
- [ ] Potentially add more helper functionality to `Arrays`, such as `sort`, `swap`, `shuffle`, `split`.
- [ ] Look into adding a [persistent bit-partitioned vector trie ('Hickey trie')](https://hypirion.com/musings/understanding-persistent-vector-pt-1)
implementation (potentially based on [persistent_vector](https://github.com/dimagog/persistent_vector)).
- [ ] Look into adding a NIF-based immutable array implementation,
such as [im-rs](immutable.rs)'s [RRB-Vector](https://docs.rs/im/15.0.0/im/struct.Vector.html),
where besides being extra performant because of being close to the metal, having access to the reference-count might allow extra optimizations ([in-place mutation](https://docs.rs/im/15.0.0/im/#in-place-mutation) is possible when you know that there is only one variable referencing the array). This is a bit of a long shot, but it might be very worthwhile.


----

## Benchmarks
Expand Down
28 changes: 14 additions & 14 deletions lib/arrays.ex
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,20 @@ contents = quote do
- The full Access calls are supported,
- Variants of many common `Enum`-like functions that keep the result an array (rather than turning it into a list), are available.
iex> words = Arrays.new(["the", "quick", "brown", "fox", "jumps", "over", "the", "lazy", "dog"])
##{@current_default_array}<["the", "quick", "brown", "fox", "jumps", "over", "the", "lazy", "dog"]>
iex> Arrays.size(words) # Runs in constant-time
9
iex> words[3] # Indexing is fast
"fox"
iex> words = put_in(words[2], "purple") # All of `Access` is supported
##{@current_default_array}<["the", "quick", "purple", "fox", "jumps", "over", "the", "lazy", "dog"]>
iex> Arrays.map(words, &String.upcase/1) # Map a function, keep result an array
##{@current_default_array}<["THE", "QUICK", "PURPLE", "FOX", "JUMPS", "OVER", "THE", "LAZY", "DOG"]>
iex> lengths = Arrays.map(words, &String.length/1)
##{@current_default_array}<[3, 5, 6, 3, 5, 4, 3, 4, 3]>
iex> Arrays.reduce(lengths, 0, &Kernel.+/2) # `reduce_right` is supported as well.
36
iex> words = Arrays.new(["the", "quick", "brown", "fox", "jumps", "over", "the", "lazy", "dog"])
##{@current_default_array}<["the", "quick", "brown", "fox", "jumps", "over", "the", "lazy", "dog"]>
iex> Arrays.size(words) # Runs in constant-time
9
iex> words[3] # Indexing is fast
"fox"
iex> words = put_in(words[2], "purple") # All of `Access` is supported
##{@current_default_array}<["the", "quick", "purple", "fox", "jumps", "over", "the", "lazy", "dog"]>
iex> Arrays.map(words, &String.upcase/1) # Map a function, keep result an array
##{@current_default_array}<["THE", "QUICK", "PURPLE", "FOX", "JUMPS", "OVER", "THE", "LAZY", "DOG"]>
iex> lengths = Arrays.map(words, &String.length/1)
##{@current_default_array}<[3, 5, 6, 3, 5, 4, 3, 4, 3]>
iex> Arrays.reduce(lengths, 0, &Kernel.+/2) # `reduce_right` is supported as well.
36
Concatenating arrays:
Expand Down
27 changes: 25 additions & 2 deletions lib/arrays/implementations/erlang_array.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,43 @@ defmodule Arrays.Implementations.ErlangArray do
Common operations like element access thus take O(log10(n)) time.
Note that when no custom default value is specified,
`nil` will be used, rather than `:array`'s default of `:undefined`.
"""

@behaviour Arrays.Behaviour

alias __MODULE__

defstruct contents: :array.new([fixed: false, default: nil])
defstruct contents: :array.new([default: nil])

@impl Arrays.Behaviour
def empty(options) do
contents = :array.new([fixed: false, default: nil] ++ options)
contents = :array.new([default: nil] ++ options)
%ErlangArray{contents: contents}
end

@doc """
Create an `%ErlangArray{}`-struct from an `:array`-record.
iex> :array.new([]) |> ErlangArray.from_raw()
#Arrays.Implementations.ErlangArray<[]>
"""
def from_raw(raw_array) do
%ErlangArray{contents: raw_array}
end

@doc """
Turn an %ErlangArray{}-struct back into an `:array`-record.
iex> Arrays.new([1, 2, 3], implementation: Arrays.Implementations.ErlangArray) |> ErlangArray.to_raw()
{:array, 3, 10, nil, {1, 2, 3, nil, nil, nil, nil, nil, nil, nil}}
"""
def to_raw(%ErlangArray{contents: contents}) do
contents
end

if Code.ensure_loaded?(FunLand.Mappable) do
Module.eval_quoted(__MODULE__,
quote do
Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ defmodule Arrays.Mixfile do
def project do
[
app: :arrays,
version: "1.1.0",
version: "1.2.0",
elixir: "~> 1.7",
elixirc_paths: elixirc_paths(Mix.env()),
start_permanent: Mix.env() == :prod,
Expand Down
5 changes: 4 additions & 1 deletion test/implementations/erlang_array_test.exs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
defmodule Implementations.ErlangArrayTest do
defmodule Arrays.Implementations.ErlangArrayTest do
use ExUnit.Case, async: true

describe "Arrays module (with ErlangArray as implementation)" do
alias Arrays.Test.Support.Arrays.DoctestErlangArray, as: Arrays
doctest Arrays, except: [empty: 1]
end

alias Arrays.Implementations.ErlangArray
doctest Arrays.Implementations.ErlangArray
end
5 changes: 4 additions & 1 deletion test/implementations/map_array_test.exs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
defmodule Implementations.MapArrayTest do
defmodule Arrays.Implementations.MapArrayTest do
use ExUnit.Case, async: true

alias Arrays.Implementations.MapArray
doctest Arrays.Implementations.MapArray
end

0 comments on commit 4586fa2

Please sign in to comment.