Skip to content

Commit 7f701bf

Browse files
committed
Merge pull request #1211 from pguyot/w26/add-list-keystore
Fix a bug where x0 and x1 were corrupted by failing guards * Also simplify implementation of `lists:keyreplace/4` (which this bug affects) * Also add `lists:keystore/4` These changes are made under both the "Apache 2.0" and the "GNU Lesser General Public License 2.1 or later" license terms (dual license). SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
2 parents c50ac17 + c4461e1 commit 7f701bf

File tree

7 files changed

+406
-334
lines changed

7 files changed

+406
-334
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1515
- Support for setting channel used by network driver wifi access point.
1616
- Support for `maps:iterator/2` and `~kp` with `io_lib:format/2` that were introduced with OTP26.
1717
- Support for `erlang:apply/2`
18+
- Support for `lists:keystore/4`
1819

1920
### Changed
2021

@@ -32,6 +33,7 @@ in ESP-IDF Kconfig options.
3233
See issue [#1193](https://github.com/atomvm/AtomVM/issues/1193).
3334
- Fix error that is raised when a function is undefined
3435
- Fix a bug that could yield crashes when functions are sent in messages
36+
- Fix bug where failing guards would corrupt x0 and x1
3537

3638
## [0.6.2] - 25-05-2024
3739

libs/estdlib/src/lists.erl

Lines changed: 41 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
keyfind/3,
4242
keymember/3,
4343
keyreplace/4,
44+
keystore/4,
4445
keytake/3,
4546
foldl/3,
4647
foldr/3,
@@ -280,31 +281,48 @@ keymember(K, I, [_H | T]) ->
280281
%% @end
281282
%%-----------------------------------------------------------------------------
282283
-spec keyreplace(
283-
K :: term(),
284-
I :: pos_integer(),
285-
L :: list(tuple()),
286-
NewTuple :: {NewKey :: term(), Val :: term()}
287-
) -> boolean().
288-
keyreplace(K, I, L, NewTuple) ->
289-
keyreplace(K, I, L, L, NewTuple, []).
284+
Key :: term(),
285+
N :: pos_integer(),
286+
TupleList :: [tuple()],
287+
NewTuple :: tuple()
288+
) -> [tuple()].
289+
keyreplace(Key, N, TupleList, NewTuple) when is_tuple(NewTuple) ->
290+
case keyreplace(Key, N, TupleList, TupleList, NewTuple, []) of
291+
{false, _Reversed} -> TupleList;
292+
{value, Updated} -> Updated
293+
end.
290294

291295
%% @private
292-
keyreplace(_K, _I, [], OrigL, _NewTuple, _NewList) ->
293-
OrigL;
294-
keyreplace(K, I, [H | T], L, NewTuple, NewList) when is_tuple(H) andalso is_tuple(NewTuple) ->
295-
case I =< tuple_size(H) of
296-
true ->
297-
case element(I, H) of
298-
K ->
299-
?MODULE:reverse(NewList, [NewTuple | T]);
300-
_ ->
301-
keyreplace(K, I, T, L, NewTuple, [H | NewList])
302-
end;
303-
false ->
304-
keyreplace(K, I, T, L, NewTuple, [H | NewList])
305-
end;
306-
keyreplace(K, I, [H | T], L, NewTuple, NewList) ->
307-
keyreplace(K, I, T, L, NewTuple, [H | NewList]).
296+
keyreplace(_Key, _N, [], _OrigL, _NewTuple, Acc) ->
297+
{false, Acc};
298+
keyreplace(Key, N, [H | Tail], _OrigL, NewTuple, Acc) when element(N, H) =:= Key ->
299+
{value, ?MODULE:reverse(Acc, [NewTuple | Tail])};
300+
keyreplace(Key, N, [H | Tail], OrigL, NewTuple, Acc) ->
301+
keyreplace(Key, N, Tail, OrigL, NewTuple, [H | Acc]).
302+
303+
%%-----------------------------------------------------------------------------
304+
%% @param Key the key to match
305+
%% @param N the position in the tuple to compare (1..tuple_size)
306+
%% @param TupleList the list of tuples from which to find the element
307+
%% @param NewTuple the tuple to add to the list
308+
%% @returns An updated TupleList where the first occurrence of `Key' has been
309+
%% replaced with `NewTuple'.
310+
%% @doc Searches the list of tuples `TupleList' for a tuple whose `N'th
311+
%% element compares equal to `Key', replaces it with `NewTuple' if
312+
%% found. If not found, append `NewTuple' to `TupleList'.
313+
%% @end
314+
%%-----------------------------------------------------------------------------
315+
-spec keystore(
316+
Key :: term(),
317+
N :: pos_integer(),
318+
TupleList :: [tuple()],
319+
NewTuple :: tuple()
320+
) -> [tuple()].
321+
keystore(Key, N, TupleList, NewTuple) when is_tuple(NewTuple) ->
322+
case keyreplace(Key, N, TupleList, TupleList, NewTuple, []) of
323+
{false, Reversed} -> ?MODULE:reverse(Reversed, [NewTuple]);
324+
{value, Updated} -> Updated
325+
end.
308326

309327
%%-----------------------------------------------------------------------------
310328
%% @param Key the key to match

0 commit comments

Comments
 (0)