3333 member /2 ,
3434 delete /2 ,
3535 reverse /1 ,
36+ reverse /2 ,
3637 foreach /2 ,
3738 keydelete /3 ,
3839 keyfind /3 ,
@@ -111,28 +112,56 @@ delete(E, L) ->
111112
112113% % @private
113114delete (_ , [], Accum ) ->
114- reverse (Accum );
115+ ? MODULE : reverse (Accum );
115116delete (E , [E | T ], Accum ) ->
116- reverse (Accum ) ++ T ;
117+ ? MODULE : reverse (Accum ) ++ T ;
117118delete (E , [H | T ], Accum ) ->
118119 delete (E , T , [H | Accum ]).
119120
120121% %-----------------------------------------------------------------------------
121122% % @param L the list to reverse
122123% % @returns the elements of L in reverse order
123- % % @doc Reverse the elements of L.
124+ % % @equiv lists:reverse(L, [])
124125% % @end
125126% %-----------------------------------------------------------------------------
126- -spec reverse (list ()) -> list ().
127- reverse (L ) ->
128- % % TODO this should be done in unit time in a BIF
129- reverse (L , []).
127+ -spec reverse (L :: list ()) -> list ().
128+ reverse (_L ) ->
129+ erlang :nif_error (undefined ).
130130
131- % % @private
132- reverse ([], Accum ) ->
133- Accum ;
134- reverse ([H | T ], Accum ) ->
135- reverse (T , [H | Accum ]).
131+ % %-----------------------------------------------------------------------------
132+ % % @param L the list to reverse
133+ % % @param T the tail to append to the reversed list
134+ % % @returns the elements of L in reverse order followed by T
135+ % % @doc Reverse the elements of L, folled by T.
136+ % % If T is not a list or not a proper list, it is appended anyway and the result
137+ % % will be an improper list.
138+ % %
139+ % % Following Erlang/OTP tradition, `lists:reverse/1,2` is a nif. It computes
140+ % % the length and then allocates memory for the list at once (2 * n terms).
141+ % %
142+ % % While this is much faster with AtomVM as allocations are expensive with
143+ % % default heap growth strategy, it can consume more memory until the list
144+ % % passed is garbage collected, as opposed to a recursive implementation where
145+ % % the process garbage collect part of the input list during the reversal.
146+ % %
147+ % % Consequently, tail-recursive implementations calling `lists:reverse/2`
148+ % % can be as expensive or more expensive in memory than list comprehensions or
149+ % % non-tail recursive versions depending on the number of terms saved on the
150+ % % stack between calls.
151+ % %
152+ % % For example, a non-tail recursive join/2 implementation requires two terms
153+ % % on stack for each iteration, so when it returns it will use
154+ % % `n * 3' (stack) + `n * 4' (result list)
155+ % % a tail recursive version will use, on last iteration:
156+ % % `n * 4' (reversed list) + n * 4' (result list)
157+ % % @end
158+ % %-----------------------------------------------------------------------------
159+ -spec reverse
160+ (L :: nonempty_list (E ), T :: list (E )) -> nonempty_list (E );
161+ (L :: nonempty_list (), T :: any ()) -> maybe_improper_list ();
162+ (L :: [], T ) -> T when T :: any ().
163+ reverse (_L , _T ) ->
164+ erlang :nif_error (undefined ).
136165
137166% %-----------------------------------------------------------------------------
138167% % @param Fun the predicate to evaluate
@@ -162,13 +191,13 @@ keydelete(K, I, L) ->
162191
163192% % @private
164193keydelete (_K , _I , [], L ) ->
165- reverse (L );
194+ ? MODULE : reverse (L );
166195keydelete (K , I , [H | T ], L2 ) when is_tuple (H ) ->
167196 case I =< tuple_size (H ) of
168197 true ->
169198 case element (I , H ) of
170199 K ->
171- reverse (L2 ) ++ T ;
200+ ? MODULE : reverse (L2 , T ) ;
172201 _ ->
173202 keydelete (K , I , T , [H | L2 ])
174203 end ;
@@ -256,7 +285,7 @@ keyreplace(K, I, [H | T], L, NewTuple, NewList) when is_tuple(H) andalso is_tupl
256285 true ->
257286 case element (I , H ) of
258287 K ->
259- reverse (NewList ) ++ [NewTuple | T ];
288+ ? MODULE : reverse (NewList , [NewTuple | T ]) ;
260289 _ ->
261290 keyreplace (K , I , T , L , NewTuple , [H | NewList ])
262291 end ;
@@ -298,7 +327,7 @@ foldl(Fun, Acc0, [H | T]) ->
298327 List :: list ()
299328) -> Acc1 :: term ().
300329foldr (Fun , Acc0 , List ) ->
301- foldl (Fun , Acc0 , reverse (List )).
330+ foldl (Fun , Acc0 , ? MODULE : reverse (List )).
302331
303332% %-----------------------------------------------------------------------------
304333% % @param Fun the predicate to evaluate
@@ -381,19 +410,8 @@ search(Pred, [H | T]) ->
381410% % @end
382411% %-----------------------------------------------------------------------------
383412-spec filter (Pred :: fun ((Elem :: term ()) -> boolean ()), List :: list ()) -> list ().
384- filter (Pred , L ) ->
385- filter (Pred , L , []).
386-
387- % % @private
388- filter (_Pred , [], Accum ) ->
389- reverse (Accum );
390- filter (Pred , [H | T ], Accum ) ->
391- case Pred (H ) of
392- true ->
393- filter (Pred , T , [H | Accum ]);
394- _ ->
395- filter (Pred , T , Accum )
396- end .
413+ filter (Pred , L ) when is_function (Pred , 1 ) ->
414+ [X || X <- L , Pred (X )].
397415
398416% %-----------------------------------------------------------------------------
399417% % @param Sep the separator
@@ -403,16 +421,16 @@ filter(Pred, [H | T], Accum) ->
403421% % @end
404422% %-----------------------------------------------------------------------------
405423-spec join (Sep :: any (), List :: list ()) -> list ().
406- join (Sep , L ) ->
407- join (L , Sep , []).
424+ join (_Sep , []) ->
425+ [];
426+ join (Sep , [H | Tail ]) ->
427+ [H | join_1 (Sep , Tail )].
408428
409429% % @private
410- join ([], _Sep , Accum ) ->
411- lists :reverse (Accum );
412- join ([E | R ], Sep , []) ->
413- join (R , Sep , [E ]);
414- join ([E | R ], Sep , Accum ) ->
415- join (R , Sep , [E , Sep | Accum ]).
430+ join_1 (Sep , [H | Tail ]) ->
431+ [Sep , H | join_1 (Sep , Tail )];
432+ join_1 (_Sep , []) ->
433+ [].
416434
417435% %-----------------------------------------------------------------------------
418436% % @param From from integer
@@ -424,8 +442,8 @@ join([E | R], Sep, Accum) ->
424442% % @end
425443% %-----------------------------------------------------------------------------
426444-spec seq (From :: integer (), To :: integer ()) -> list ().
427- seq (From , To ) ->
428- seq (From , To , 1 ).
445+ seq (From , To ) when is_integer ( From ) andalso is_integer ( To ) andalso From =< To ->
446+ seq_r (From , To , 1 , [] ).
429447
430448% %-----------------------------------------------------------------------------
431449% % @param From from integer
@@ -447,16 +465,12 @@ seq(From, To, Incr) when
447465seq (To , To , 0 ) ->
448466 [To ];
449467seq (From , To , Incr ) ->
450- seq (From , To , Incr , []).
468+ Last = From + ((To - From ) div Incr ) * Incr ,
469+ seq_r (From , Last , Incr , []).
451470
452471% % @private
453- seq (From , To , Incr , Accum ) when
454- (Incr > 0 andalso From > To ) orelse
455- (Incr < 0 andalso To > From )
456- ->
457- reverse (Accum );
458- seq (From , To , Incr , Accum ) ->
459- seq (From + Incr , To , Incr , [From | Accum ]).
472+ seq_r (From , From , _Incr , Acc ) -> [From | Acc ];
473+ seq_r (From , To , Incr , Acc ) -> seq_r (From , To - Incr , Incr , [To | Acc ]).
460474
461475% %-----------------------------------------------------------------------------
462476% % @param List a list
@@ -523,20 +537,16 @@ unique(Sorted) ->
523537 unique (Sorted , fun (X , Y ) -> X =< Y end ).
524538
525539% % @private
526- unique (Sorted , Fun ) ->
527- unique (Sorted , Fun , []).
528-
529- % % @private
530- unique ([], _Fun , []) ->
540+ unique ([], _Fun ) ->
531541 [];
532- unique ([X ], _Fun , Acc ) ->
533- lists : reverse ([ X | Acc ]) ;
534- unique ([X , Y | Tail ], Fun , Acc ) ->
542+ unique ([X ], _Fun ) ->
543+ [ X ] ;
544+ unique ([X , Y | Tail ], Fun ) ->
535545 case Fun (X , Y ) andalso Fun (Y , X ) of
536546 true ->
537- unique ([Y | Tail ], Fun , Acc );
547+ unique ([Y | Tail ], Fun );
538548 false ->
539- unique ([Y | Tail ], Fun , [ X | Acc ])
549+ [ X | unique ([Y | Tail ], Fun )]
540550 end .
541551
542552% %-----------------------------------------------------------------------------
@@ -563,9 +573,9 @@ duplicate(Count, Elem, Acc) -> duplicate(Count - 1, Elem, [Elem | Acc]).
563573% %-----------------------------------------------------------------------------
564574-spec sublist ([Elem ], integer ()) -> [Elem ].
565575sublist (List , Len ) when is_integer (Len ) andalso Len >= 0 ->
566- sublist0 (List , Len , [] ).
576+ sublist0 (List , Len ).
567577
568578% % @private
569- sublist0 (_List , 0 , Acc ) -> reverse ( Acc ) ;
570- sublist0 ([], _ , Acc ) -> reverse ( Acc ) ;
571- sublist0 ([H | Tail ], Len , Acc ) -> sublist0 (Tail , Len - 1 , [ H | Acc ]) .
579+ sublist0 ([], _Len ) -> [] ;
580+ sublist0 (_ , 0 ) -> [] ;
581+ sublist0 ([H | Tail ], Len ) -> [ H | sublist0 (Tail , Len - 1 )] .
0 commit comments