Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 27 additions & 45 deletions lib/stdlib/src/gb_sets.erl
Original file line number Diff line number Diff line change
Expand Up @@ -207,9 +207,9 @@ of one set is also a member of the other set; otherwise, returns `false`.
```erlang
1> Empty = gb_sets:new().
2> S = gb_sets:from_list([a,b]).
3> gb_sets:is_equal(S, S)
3> gb_sets:is_equal(S, S).
true
4> gb_sets:is_equal(S, Empty)
4> gb_sets:is_equal(S, Empty).
false
```
""".
Expand Down Expand Up @@ -380,7 +380,7 @@ does not rebalance the tree.
## Examples

```erlang
1> S0 = gb_sets:from_ordset(lists:seq(1, 100)).
1> S0 = gb_sets:from_list(lists:seq(1, 100)).
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While the usage of from_ordset is not wrong here, it may be confusing to readers. Everybody knows from_list and can intuitively guess at what it does. OTOH, the usage of from_ordset assumes that the reader knows the assumption that the given list is sorted and free of duplicates.

2> Delete = fun(E, Set) -> gb_sets:delete(E, Set) end.
3> S1 = lists:foldl(Delete, S0, lists:seq(1, 50)).
4> gb_sets:size(S1).
Expand Down Expand Up @@ -460,7 +460,7 @@ contain duplicates.
## Examples

```erlang
1> Unordered = [x,y,a,x,y,b,b,z]
1> Unordered = [x,y,a,x,y,b,b,z].
2> gb_sets:to_list(gb_sets:from_list(Unordered)).
[a,b,x,y,z]
```
Expand Down Expand Up @@ -797,10 +797,10 @@ The implementation is very efficient; traversing the whole set using
[`next/1`](`next/1`) is only slightly slower than getting the list of
all elements using `to_list/1` and traversing that. The main advantage
of the iterator approach is that it avoids building the complete list
of all elements to be built in memory at once.
of all elements in memory at once.

```erlang
1> S = gb_sets:from_ordset([1,2,3,4,5]).
1> S = gb_sets:from_list([1,2,3,4,5]).
2> Iter0 = gb_sets:iterator(S, ordered).
3> element(1, gb_sets:next(Iter0)).
1
Expand Down Expand Up @@ -837,25 +837,7 @@ iterator_r({_, _, R} = T, As) ->
iterator_r(nil, As) ->
As.

-doc """
Returns an iterator that can be used for traversing the entries of `Set`; see
`next/1`.

Unlike the iterator returned by `iterator/1` or `iterator/2`, this
iterator starts with the first element greater than or equal to
`Element`.

Equivalent to [`iterator_from(Element, Set, ordered)`](`iterator_from/3`).

## Examples

```erlang
1> S = gb_sets:from_ordset([10,20,30,40,50]).
2> Iter = gb_sets:iterator_from(17, S).
3> element(1, gb_sets:next(Iter)).
20
```
""".
-doc(#{equiv => iterator_from(Element, Set, ordered)}).
-doc(#{since => <<"OTP 18.0">>}).
-spec iterator_from(Element, Set) -> Iter when
Set :: set(Element),
Expand All @@ -865,19 +847,19 @@ iterator_from(Element, Set) ->
iterator_from(Element, Set, ordered).

-doc """
Returns an iterator that can be used for traversing the entries of `Set`; see
`next/1`.

Unlike the iterator returned by `iterator/1` or `iterator/2`, this
iterator starts with the first element greater than or equal to
`Element`.
Returns an iterator over members of `Set` in the given `Order`, starting
from `Element` or, if absent, the first member that follows in the
iteration order, if any; see `next/1`.
Comment on lines +850 to +852
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is easier to read, and that the references to iterator/1,2 are not needed. Also, the passage saying "... the first element greater than or equal to..." in the original text was only correct for the ordered case, while in the reversed case it actually is "... the first element less than or equal to...".


## Examples

```erlang
1> S = gb_sets:from_ordset([10,20,30,40,50]).
2> Iter = gb_sets:iterator_from(17, S, reversed).
3> element(1, gb_sets:next(Iter)).
1> S = gb_sets:from_list([10,20,30,40,50]).
2> Iter1 = gb_sets:iterator_from(17, S, ordered).
3> element(1, gb_sets:next(Iter1)).
20
4> Iter2 = gb_sets:iterator_from(17, S, reversed).
5> element(1, gb_sets:next(Iter2)).
10
```
""".
Expand Down Expand Up @@ -916,7 +898,7 @@ by iterator `Iter1`, and `Iter2` is the new iterator to be used for traversing
the remaining elements, or the atom `none` if no elements remain.

```erlang
1> S = gb_sets:from_ordset([1,2,3,4,5]).
1> S = gb_sets:from_list([1,2,3,4,5]).
2> Iter0 = gb_sets:iterator(S).
3> {Element0, Iter1} = gb_sets:next(Iter0).
4> Element0.
Expand Down Expand Up @@ -955,8 +937,8 @@ next({_, []}) ->
%% If the sets are not very different in size, i.e., if |Y| / |X| >= c *
%% log(|Y|), then the fastest way to do union (and the other similar set
%% operations) is to build the lists of elements, traverse these lists
%% in parallel while building a reversed ackumulator list, and finally
%% rebuild the tree directly from the ackumulator. Other methods of
%% in parallel while building a reversed accumulator list, and finally
%% rebuild the tree directly from the accumulator. Other methods of
%% traversing the elements can be devised, but they all have higher
%% overhead.

Expand Down Expand Up @@ -1035,7 +1017,7 @@ union_1([], S) ->
%% that the same is likely to apply to the next element also,
%% statistically reducing the number of failed tests and automatically
%% adapting to cases of lists having very different lengths. This saves
%% 10-40% of the traversation time compared to a "fixed" strategy,
%% 10-40% of the traversal time compared to a "fixed" strategy,
%% depending on the sizes and contents of the lists.
%%
%% 3) A tail recursive version using `lists:reverse/2' is about 5-10%
Expand Down Expand Up @@ -1092,15 +1074,15 @@ all sets, without duplicates.
```erlang
1> S0 = gb_sets:from_list([a,b,c,d]).
2> S1 = gb_sets:from_list([d,e,f]).
3> S2 = gb_sets:from_list([q,r])
3> S2 = gb_sets:from_list([q,r]).
4> Sets = [S0, S1, S2].
5> Union = gb_sets:union(Sets).
6> gb_sets:to_list(Union).
[a,b,c,d,e,f,q,r]
```
""".
-spec union(SetList) -> Set when
SetList :: [set(Element),...],
SetList :: [set(Element)],
Comment on lines -1103 to +1085
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

union([]) is allowed and results in an empty set, so the argument list may be empty.

Set :: set(Element).

union([S | Ss]) ->
Expand Down Expand Up @@ -1194,7 +1176,7 @@ elements that are present in all sets.
```erlang
1> S0 = gb_sets:from_list([a,b,c,d]).
2> S1 = gb_sets:from_list([d,e,f]).
3> S2 = gb_sets:from_list([q,r])
3> S2 = gb_sets:from_list([q,r]).
4> Sets = [S0, S1, S2].
5> gb_sets:to_list(gb_sets:intersection([S0, S1, S2])).
[]
Expand All @@ -1221,15 +1203,15 @@ Returns `true` if `Set1` and `Set2` are disjoint; otherwise, returns

Two sets are disjoint if they have no elements in common.

This function is equivalent to `gb_sets:intersection(Set1, Set2) =:= []`,
This function is equivalent to `gb_sets:is_empty(gb_sets:intersection(Set1, Set2))`,
Comment on lines -1224 to +1206
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gb_sets:intersection will return a gb_set, not an empty list, so the comparison with [] will always be false even if the two sets are disjoint.

but faster.

## Examples

```erlang
1> S0 = gb_sets:from_list([a,b,c,d]).
2> S1 = gb_sets:from_list([d,e,f]).
3> S2 = gb_sets:from_list([q,r])
3> S2 = gb_sets:from_list([q,r]).
4> gb_sets:is_disjoint(S0, S1).
false
5> gb_sets:is_disjoint(S1, S2).
Expand Down Expand Up @@ -1493,13 +1475,13 @@ value, with `true` being equivalent to `{true, Elem}`.

```erlang
filtermap(Fun, Set1) ->
gb_sets:from_list(lists:filtermap(Fun, Set1)).
gb_sets:from_list(lists:filtermap(Fun, gb_sets:to_list(Set1))).
Comment on lines -1496 to +1478
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assuming that Set1 is a gb_set, lists:filtermap(Fun, Set1) would not work here.

```

## Examples

```erlang
1> S = gb_sets:from_list([2,4,5,6,8,9])
1> S = gb_sets:from_list([2,4,5,6,8,9]).
2> F = fun(X) ->
case X rem 2 of
0 -> {true, X div 2};
Expand Down
6 changes: 3 additions & 3 deletions lib/stdlib/src/lists.erl
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ starting at `N+1` and continuing to the end of the list.
""".
-spec nthtail(N, List) -> Tail when
N :: non_neg_integer(),
List :: [T,...],
List :: [T],
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nthtail(0, []) works and returns [], so empty lists are actually allowed.

Tail :: [T],
T :: term().

Expand Down Expand Up @@ -1894,7 +1894,7 @@ sort(Fun, [X, Y | T]) ->
-doc """
Returns a sorted list formed by merging `List1` and `List2` based on `Fun`.

Both `List1` and`List2` must be sorted according to the
Both `List1` and `List2` must be sorted according to the
[ordering function](`m:lists#ordering_function`) `Fun` before evaluating this
function.

Expand Down Expand Up @@ -2682,7 +2682,7 @@ Combines the operations of `map/2` and `foldr/3` into one pass.
> #### Note {: .info }
>
> Unless the order in which the elements are accumulated is important,
> prefer [`mapfoldl/3`](`mapfoldl/3`) as it is slighly more efficient.
> prefer [`mapfoldl/3`](`mapfoldl/3`) as it is slightly more efficient.

## Examples

Expand Down
21 changes: 10 additions & 11 deletions lib/stdlib/src/ordsets.erl
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,11 @@ Returns a new empty ordered set.
## Examples

```erlang
1> ordsets:new()
1> ordsets:new().
[]
```
""".
-spec new() -> [].
-spec new() -> ordset(none()).
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overlooked?


new() -> [].

Expand Down Expand Up @@ -146,9 +146,9 @@ of one set is also a member of the other set; otherwise, returns `false`.
```erlang
1> Empty = ordsets:new().
2> S = ordsets:from_list([a,b]).
3> ordsets:is_equal(S, S)
3> ordsets:is_equal(S, S).
true
4> ordsets:is_equal(S, Empty)
4> ordsets:is_equal(S, Empty).
false
```
""".
Expand Down Expand Up @@ -305,7 +305,7 @@ all sets, without duplicates.
```erlang
1> S0 = ordsets:from_list([a,b,c,d]).
2> S1 = ordsets:from_list([d,e,f]).
3> S2 = ordsets:from_list([q,r])
3> S2 = ordsets:from_list([q,r]).
4> Sets = [S0, S1, S2].
5> ordsets:union(Sets).
[a,b,c,d,e,f,q,r]
Expand Down Expand Up @@ -363,7 +363,7 @@ elements that are present in all sets.
```erlang
1> S0 = ordsets:from_list([a,b,c,d]).
2> S1 = ordsets:from_list([d,e,f]).
3> S2 = ordsets:from_list([q,r])
3> S2 = ordsets:from_list([q,r]).
4> Sets = [S0, S1, S2].
5> ordsets:intersection([S0, S1, S2]).
[]
Expand Down Expand Up @@ -391,8 +391,7 @@ returns `false`.

Two sets are disjoint if they have no elements in common.

This function is equivalent to `ordsets:intersection(Ordset1, Ordset2)
=:= []`, but faster.
This function is equivalent to `ordsets:is_empty(ordsets:intersection(Ordset1, Ordset2))`, but faster.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While not wrong and the representation backing ordsets is not opaque, I think using lists and ordsets ambiguosly should not be encouraged, but rather the usage of the respective API functions.


## Examples

Expand Down Expand Up @@ -555,13 +554,13 @@ value, with `true` being equivalent to `{true, Elem}`.

```erlang
filtermap(Fun, Ordset1) ->
ordsets:from_list(lists:filtermap(Fun, Ordset1)).
ordsets:from_list(lists:filtermap(Fun, ordsets:to_list(Ordset1))).
```

## Examples

```erlang
1> S = ordsets:from_list([2,4,5,6,8,9])
1> S = ordsets:from_list([2,4,5,6,8,9]).
2> F = fun(X) ->
case X rem 2 of
0 -> {true, X div 2};
Expand All @@ -574,7 +573,7 @@ filtermap(Fun, Ordset1) ->
""".
-doc(#{since => <<"OTP 27.0">>}).
-spec filtermap(Fun, Ordset1) -> Ordset2 when
Fun :: fun((Element1 :: T1) -> boolean | ({true, Element2 :: T2})),
Fun :: fun((Element1 :: T1) -> boolean() | {true, Element2 :: T2}),
Comment on lines -577 to +576
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

boolean (atom) instead of boolean() (type)

Ordset1 :: ordset(T1),
Ordset2 :: ordset(T1 | T2).

Expand Down
30 changes: 16 additions & 14 deletions lib/stdlib/src/queue.erl
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ new() -> {[],[]}. %{RearList,FrontList}
-doc """
Tests if `Term` is a queue and returns `true` if so, otherwise `false`. Note
that the test will return `true` for a term coinciding with the representation
of a queue, even when not constructed by thus module. See also note on
of a queue, even when not constructed by this module. See also note on
[data types](`e:system:data_types.md#no_user_types`).
""".
-doc(#{group => <<"Original API">>}).
Expand Down Expand Up @@ -161,9 +161,11 @@ the queue becomes the head of the list.
_Example:_

```erlang
1> Queue = queue:from_list([1,2,3,4,5]).
1> List = [1, 2, 3, 4, 5].
[1,2,3,4,5]
2> Queue = queue:from_list(List).
{[5,4,3],[1,2]}
2> List == queue:to_list(Queue).
3> List =:= queue:to_list(Queue).
true
```
""".
Expand Down Expand Up @@ -472,7 +474,7 @@ _Example:_
```erlang
1> Queue = queue:from_list([1,2,3,4,5]).
{[5,4,3],[1,2]}
2> Queue = queue:drop(Queue).
2> Queue1 = queue:drop(Queue).
{[5,4,3],[2]}
3> queue:to_list(Queue1).
[2,3,4,5]
Expand Down Expand Up @@ -507,7 +509,7 @@ _Example:_
```erlang
1> Queue = queue:from_list([1,2,3,4,5]).
{[5,4,3],[1,2]}
2> Queue = queue:drop_r(Queue).
2> Queue1 = queue:drop_r(Queue).
{[4,3],[1,2]}
3> queue:to_list(Queue1).
[1,2,3,4]
Expand Down Expand Up @@ -620,7 +622,7 @@ split_r1_to_f2(N, [X|R1], F1, R2, F2) ->
%% filter, or rather filtermap with insert, traverses in queue order
%%
%% Fun(_) -> List: O(length(List) * len(Q))
%% else: O(len(Q)
%% else: O(len(Q))
-doc """
Returns a queue `Q2` that is the result of calling `Fun(Item)` on all items in
`Q1`.
Expand Down Expand Up @@ -721,16 +723,16 @@ queue element at this position is replaced with `NewItem` in the result queue.
_Example 1:_

```erlang
1> Queue = queue:from_list([1,2,3,4,5]).
1> Queue = queue:from_list([1, 2, 3, 4, 5]).
{[5,4,3],[1,2]}
2> Queue1 = queue:filtermap(fun (E) -> E > 2 end, Queue).
{[5],[3,4]}
3> queue:to_list(Queue1).
[3,4,5]
4> Queue1 = queue:filtermap(fun (E) -> {true, E+100} end, Queue).
{"ihg","ef"}
5> queue:to_list(Queue1).
"efghi
4> Queue2 = queue:filtermap(fun (E) -> {true, E - 100} end, Queue).
{[-95,-96,-97],[-99,-98]}
5> queue:to_list(Queue2).
[-99,-98,-97,-96,-95]
Comment on lines -730 to +735
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The result of the filtermap and subsequent to_list calls ended up prettified to "strings", which might be confusing to readers.

```
""".
-doc(#{group => <<"Original API">>,since => <<"OTP 24.0">>}).
Expand Down Expand Up @@ -956,7 +958,7 @@ _Example:_

```erlang
1> Queue = queue:from_list([100,1,2,3,4,5]).
2> Queue1 = queue:delete_with(fun (E) -> E > 0, Queue).
2> Queue1 = queue:delete_with(fun (E) -> E > 0 end, Queue).
3> queue:to_list(Queue1).
[1,2,3,4,5]
```
Expand Down Expand Up @@ -998,7 +1000,7 @@ _Example:_

```erlang
1> Queue = queue:from_list([1,2,3,4,5,100]).
2> Queue1 = queue:delete_with(fun (E) -> E > 10, Queue).
2> Queue1 = queue:delete_with(fun (E) -> E > 10 end, Queue).
3> queue:to_list(Queue1).
[1,2,3,4,5]
```
Expand Down Expand Up @@ -1074,7 +1076,7 @@ delete_with_rear(_, []) ->
%%
%% An alternative would be to balance for equal list length when one side
%% is exhausted. Although this could be better for a general double
%% ended queue, it would more han double the amortized cost for
%% ended queue, it would more than double the amortized cost for
%% the normal case (one way queue).

%% Cons to head
Expand Down
Loading
Loading