Skip to content

Commit b9ef56d

Browse files
author
José Valim
committed
Merge pull request #859 from yrashk/insert-delete-element
Add insert_elem/3 and delete_elem/2 functions
2 parents 1ffda62 + 0fad188 commit b9ef56d

File tree

5 files changed

+112
-16
lines changed

5 files changed

+112
-16
lines changed

lib/elixir/lib/file.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ defmodule File do
271271
path. Returns `:ok` or `{ :error, reason }`.
272272
"""
273273
def write_stat(path, File.Stat[] = stat, opts // []) do
274-
F.write_file_info(path, setelem(stat, 0, :file_info), opts)
274+
F.write_file_info(path, set_elem(stat, 0, :file_info), opts)
275275
end
276276

277277
@doc """

lib/elixir/lib/hash_dict.ex

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -399,29 +399,29 @@ defmodule HashDict do
399399
defp node_put(node, 0, hash, key, value) do
400400
pos = bucket_index(hash)
401401
{ new, count } = bucket_put(elem(node, pos), key, value)
402-
{ setelem(node, pos, new), count }
402+
{ set_elem(node, pos, new), count }
403403
end
404404

405405
defp node_put(node, depth, hash, key, value) do
406406
pos = bucket_index(hash)
407407
{ new, count } = node_put(elem(node, pos), depth - 1, bucket_next(hash), key, value)
408-
{ setelem(node, pos, new), count }
408+
{ set_elem(node, pos, new), count }
409409
end
410410

411411
# Deletes a key from the bucket
412412
defp node_delete(node, 0, hash, key) do
413413
pos = bucket_index(hash)
414414
case bucket_delete(elem(node, pos), key) do
415415
{ _, 0 } -> { node, 0 }
416-
{ new, -1 } -> { setelem(node, pos, new), -1 }
416+
{ new, -1 } -> { set_elem(node, pos, new), -1 }
417417
end
418418
end
419419

420420
defp node_delete(node, depth, hash, key) do
421421
pos = bucket_index(hash)
422422
case node_delete(elem(node, pos), depth - 1, bucket_next(hash), key) do
423423
{ _, 0 } -> { node, 0 }
424-
{ new, -1 } -> { setelem(node, pos, new), -1 }
424+
{ new, -1 } -> { set_elem(node, pos, new), -1 }
425425
end
426426
end
427427

@@ -477,7 +477,7 @@ defmodule HashDict do
477477
defp node_relocate(node // unquote(node_escaped), bucket, n) do
478478
:lists.foldl fn { key, value }, acc ->
479479
pos = key |> bucket_hash() |> bucket_nth_index(n)
480-
setelem(acc, pos, bucket_put!(elem(acc, pos), key, value))
480+
set_elem(acc, pos, bucket_put!(elem(acc, pos), key, value))
481481
end, node, bucket
482482
end
483483
end

lib/elixir/lib/kernel.ex

Lines changed: 93 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1926,26 +1926,114 @@ defmodule Kernel do
19261926
end
19271927
19281928
@doc """
1929-
Define setelem to set Tuple element according to Elixir conventions
1929+
Define set_elem to set Tuple element according to Elixir conventions
19301930
(i.e. it expects the tuple as first argument, zero-index based).
19311931
1932-
It is implemented as a macro so it can be used in guards.
1933-
19341932
## Example
19351933
19361934
iex> tuple = { :foo, :bar, 3 }
1937-
...> setelem(tuple, 0, :baz)
1935+
...> set_elem(tuple, 0, :baz)
19381936
{ :baz, :bar, 3 }
19391937
19401938
"""
1941-
defmacro setelem(tuple, index, value) when is_integer(index) do
1939+
defmacro set_elem(tuple, index, value) when is_integer(index) do
19421940
quote do: :erlang.setelement(unquote(index + 1), unquote(tuple), unquote(value))
19431941
end
19441942
1943+
defmacro set_elem(tuple, index, value) do
1944+
quote do: :erlang.setelement(unquote(index) + 1, unquote(tuple), unquote(value))
1945+
end
1946+
1947+
@doc false
19451948
defmacro setelem(tuple, index, value) do
1949+
IO.puts "setelem is deprecated, please use set_elem instead\n#{Exception.format_stacktrace(__CALLER__.stacktrace)}"
19461950
quote do: :erlang.setelement(unquote(index) + 1, unquote(tuple), unquote(value))
19471951
end
19481952
1953+
@doc """
1954+
Define insert_elem to insert element into a tuple according to
1955+
Elixir conventions (i.e. it expects the tuple as first argument,
1956+
zero-index based).
1957+
1958+
Please note that in versions of Erlang prior to R16B there is no BIF
1959+
for this operation and it is emulated by converting the tuple to a list
1960+
and back and is, therefore, inefficient.
1961+
1962+
## Example
1963+
1964+
iex> tuple = { :bar, :baz }
1965+
...> insert_elem(tuple, 0, :foo)
1966+
{ :foo, :bar, :baz }
1967+
"""
1968+
defmacro insert_elem(tuple, index, value) when is_integer(index) do
1969+
case :proplists.get_value(:insert_element,
1970+
:proplists.get_value(:exports, :erlang.module_info,[])) do
1971+
3 ->
1972+
quote do: :erlang.insert_element(unquote(index + 1), unquote(tuple), unquote(value))
1973+
:undefined ->
1974+
do_insert_elem(tuple, index, value)
1975+
end
1976+
end
1977+
defmacro insert_elem(tuple, index, value) do
1978+
case :proplists.get_value(:insert_element,
1979+
:proplists.get_value(:exports, :erlang.module_info,[])) do
1980+
3 ->
1981+
quote do: :erlang.insert_element(unquote(index) + 1, unquote(tuple), unquote(value))
1982+
:undefined ->
1983+
do_insert_elem(tuple, index, value)
1984+
end
1985+
end
1986+
1987+
defp do_insert_elem(tuple, index, value) do
1988+
quote do
1989+
{h, t} = :lists.split(unquote(index),
1990+
tuple_to_list(unquote(tuple)))
1991+
list_to_tuple(h ++ [unquote(value)|t])
1992+
end
1993+
end
1994+
1995+
@doc """
1996+
Define delete_elem to delete element from a tuple according to
1997+
Elixir conventions (i.e. it expects the tuple as first argument,
1998+
zero-index based).
1999+
2000+
Please note that in versions of Erlang prior to R16B there is no BIF
2001+
for this operation and it is emulated by converting the tuple to a list
2002+
and back and is, therefore, inefficient.
2003+
2004+
## Example
2005+
2006+
iex> tuple = { :foo, :bar, :baz }
2007+
...> delete_elem(tuple, 0)
2008+
{ :bar, :baz }
2009+
"""
2010+
defmacro delete_elem(tuple, index) when is_integer(index) do
2011+
case :proplists.get_value(:delete_element,
2012+
:proplists.get_value(:exports, :erlang.module_info,[])) do
2013+
2 ->
2014+
quote do: :erlang.delete_element(unquote(index + 1), unquote(tuple))
2015+
:undefined ->
2016+
do_delete_elem(tuple, index)
2017+
end
2018+
end
2019+
defmacro delete_elem(tuple, index) do
2020+
case :proplists.get_value(:delete_element,
2021+
:proplists.get_value(:exports, :erlang.module_info,[])) do
2022+
2 ->
2023+
quote do: :erlang.delete_element(unquote(index) + 1, unquote(tuple))
2024+
:undefined ->
2025+
do_delete_elem(tuple, index)
2026+
end
2027+
end
2028+
2029+
defp do_delete_elem(tuple, index) do
2030+
quote do
2031+
{h, [_|t]} = :lists.split(unquote(index),
2032+
tuple_to_list(unquote(tuple)))
2033+
list_to_tuple(h ++ t)
2034+
end
2035+
end
2036+
19492037
@doc """
19502038
Provides an integer division macro according to Erlang semantics.
19512039
Raises an error if one of the arguments is not an integer.

lib/elixir/lib/record.ex

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -445,19 +445,19 @@ defmodule Record do
445445
# end
446446
#
447447
# def :atime.(value, record) do
448-
# setelem(record, 1, value)
448+
# set_elem(record, 1, value)
449449
# end
450450
#
451451
# def :mtime.(record) do
452-
# setelem(record, 2, value)
452+
# set_elem(record, 2, value)
453453
# end
454454
#
455455
# def :atime.(callback, record) do
456-
# setelem(record, 1, callback.(elem(record, 1)))
456+
# set_elem(record, 1, callback.(elem(record, 1)))
457457
# end
458458
#
459459
# def :mtime.(callback, record) do
460-
# setelem(record, 2, callback.(elem(record, 2)))
460+
# set_elem(record, 2, callback.(elem(record, 2)))
461461
# end
462462
#
463463
defp accessors([{ :__exception__, _ }|t], 1) do

lib/elixir/test/elixir/tuple_test.exs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,15 @@ defmodule TupleTest do
88
end
99

1010
test :setelem do
11-
assert setelem({ :a, :b, :c }, 1, :d) == { :a, :d, :c }
11+
assert set_elem({ :a, :b, :c }, 1, :d) == { :a, :d, :c }
12+
end
13+
14+
test :insert_elem do
15+
assert insert_elem({ :bar, :baz }, 0, :foo) == { :foo, :bar, :baz }
16+
end
17+
18+
test :delete_elem do
19+
assert delete_elem({ :foo, :bar, :baz }, 0) == { :bar, :baz }
1220
end
1321

1422
test :optional_comma do

0 commit comments

Comments
 (0)