aboutsummaryrefslogtreecommitdiffstats
path: root/lib/stdlib
diff options
context:
space:
mode:
Diffstat (limited to 'lib/stdlib')
-rw-r--r--lib/stdlib/doc/src/ets.xml15
-rw-r--r--lib/stdlib/doc/src/notes.xml15
-rw-r--r--lib/stdlib/src/erl_pp.erl4
-rw-r--r--lib/stdlib/src/io_lib.erl18
-rw-r--r--lib/stdlib/src/io_lib_format.erl27
-rw-r--r--lib/stdlib/src/io_lib_pretty.erl20
-rw-r--r--lib/stdlib/src/stdlib.appup.src8
-rw-r--r--lib/stdlib/test/binary_module_SUITE.erl15
-rw-r--r--lib/stdlib/test/erl_pp_SUITE.erl11
-rw-r--r--lib/stdlib/vsn.mk2
10 files changed, 104 insertions, 31 deletions
diff --git a/lib/stdlib/doc/src/ets.xml b/lib/stdlib/doc/src/ets.xml
index ccccf7de88..622edc072e 100644
--- a/lib/stdlib/doc/src/ets.xml
+++ b/lib/stdlib/doc/src/ets.xml
@@ -188,6 +188,21 @@
is used to keep the table fixated during the entire traversal.</p>
</item>
</list>
+ <p>Traversals using <c>match</c> and <c>select</c> functions may not need to
+ scan the entire table depending on how the key is specified. A match
+ pattern with a <em>fully bound key</em> (without any match variables) will
+ optimize the operation to a single key lookup without any table traversal
+ at all. For <c>ordered_set</c> a <em>partially bound key</em> will limit the
+ traversal to only scan a subset of the table based on term order. A
+ partially bound key is either a list or a tuple with a prefix that is fully
+ bound. Example:</p>
+<pre>
+1> <input>T = ets:new(t,[ordered_set]), ets:insert(T, {"555-1234", "John Smith"}).</input>
+true
+2> <input>%% Efficient search of all with area code 555</input>
+2> <input>ets:match(T,{[$5,$5,$5,$- |'$1'],'$2'}).</input>
+[["1234","John Smith"]]
+</pre>
</section>
<section>
diff --git a/lib/stdlib/doc/src/notes.xml b/lib/stdlib/doc/src/notes.xml
index 7ba19a98ea..993945b9c7 100644
--- a/lib/stdlib/doc/src/notes.xml
+++ b/lib/stdlib/doc/src/notes.xml
@@ -31,6 +31,21 @@
</header>
<p>This document describes the changes made to the STDLIB application.</p>
+<section><title>STDLIB 3.7.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Optimize pretty printing of terms. The slower
+ behaviour was introduced in Erlang/OTP 20. </p>
+ <p>
+ Own Id: OTP-15573 Aux Id: ERIERL-306 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>STDLIB 3.7</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/stdlib/src/erl_pp.erl b/lib/stdlib/src/erl_pp.erl
index dd302a2880..ada3ff5de3 100644
--- a/lib/stdlib/src/erl_pp.erl
+++ b/lib/stdlib/src/erl_pp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -697,6 +697,8 @@ fun_info(Extra) ->
%% BITS:
+bit_grp([], _Opts) ->
+ leaf("<<>>");
bit_grp(Fs, Opts) ->
append([['<<'], [bit_elems(Fs, Opts)], ['>>']]).
diff --git a/lib/stdlib/src/io_lib.erl b/lib/stdlib/src/io_lib.erl
index 8223a52873..2b5a374cf2 100644
--- a/lib/stdlib/src/io_lib.erl
+++ b/lib/stdlib/src/io_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -87,6 +87,8 @@
-export([limit_term/2]).
+-export([chars_length/1]).
+
-export_type([chars/0, latin1_string/0, continuation/0,
fread_error/0, fread_item/0, format_spec/0, chars_limit/0]).
@@ -1131,3 +1133,17 @@ test_limit_map_assoc(K, V, D) ->
test_limit(V, D - 1).
test_limit_bitstring(_, _) -> ok.
+
+-spec chars_length(chars()) -> non_neg_integer().
+%% Optimized for deep lists S such that deep_latin1_char_list(S) is
+%% true. No binaries allowed! It is assumed that $\r is never followed
+%% by $\n if S is an iolist() (string:length() assigns such a
+%% sub-sequence length 1).
+chars_length(S) ->
+ try
+ %% true = deep_latin1_char_list(S),
+ iolist_size(S)
+ catch
+ _:_ ->
+ string:length(S)
+ end.
diff --git a/lib/stdlib/src/io_lib_format.erl b/lib/stdlib/src/io_lib_format.erl
index ab9031573b..d1aa4cd157 100644
--- a/lib/stdlib/src/io_lib_format.erl
+++ b/lib/stdlib/src/io_lib_format.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -248,7 +248,7 @@ count_small([#{control_char := $s}|Cs], #{w := W} = Cnts) ->
count_small(Cs, Cnts#{w := W + 1});
count_small([S|Cs], #{other := Other} = Cnts) when is_list(S);
is_binary(S) ->
- count_small(Cs, Cnts#{other := Other + string:length(S)});
+ count_small(Cs, Cnts#{other := Other + io_lib:chars_length(S)});
count_small([C|Cs], #{other := Other} = Cnts) when is_integer(C) ->
count_small(Cs, Cnts#{other := Other + 1});
count_small([], #{p := P, s := S, w := W, other := Other}) ->
@@ -280,10 +280,15 @@ build_limited([#{control_char := C, args := As, width := F, adjust := Ad,
true -> MaxLen0 div Count0
end,
S = control_limited(C, As, F, Ad, P, Pad, Enc, Str, MaxChars, I),
- Len = string:length(S),
NumOfPs = decr_pc(C, NumOfPs0),
Count = Count0 - 1,
- MaxLen = sub(MaxLen0, Len),
+ MaxLen = if
+ MaxLen0 < 0 -> % optimization
+ MaxLen0;
+ true ->
+ Len = io_lib:chars_length(S),
+ sub(MaxLen0, Len)
+ end,
if
NumOfPs > 0 -> [S|build_limited(Cs, NumOfPs, Count,
MaxLen, indentation(S, I))];
@@ -406,7 +411,7 @@ base(B) when is_integer(B) ->
term(T, none, _Adj, none, _Pad) -> T;
term(T, none, Adj, P, Pad) -> term(T, P, Adj, P, Pad);
term(T, F, Adj, P0, Pad) ->
- L = string:length(T),
+ L = io_lib:chars_length(T),
P = erlang:min(L, case P0 of none -> F; _ -> min(P0, F) end),
if
L > P ->
@@ -713,7 +718,7 @@ fwrite_g(Fl, F, Adj, P, Pad) when P >= 1 ->
end.
-%% iolist_to_chars(iolist()) -> deep_char_list()
+%% iolist_to_chars(iolist()) -> io_lib:chars()
iolist_to_chars([C|Cs]) when is_integer(C), C >= $\000, C =< $\377 ->
[C | iolist_to_chars(Cs)];
@@ -729,7 +734,7 @@ iolist_to_chars(B) when is_binary(B) ->
%% cbinary() | nil())
%% cbinary() :: unicode:unicode_binary() | unicode:latin1_binary()
-%% cdata_to_chars(cdata()) -> io_lib:deep_char_list()
+%% cdata_to_chars(cdata()) -> io_lib:chars()
cdata_to_chars([C|Cs]) when is_integer(C), C >= $\000 ->
[C | cdata_to_chars(Cs)];
@@ -745,7 +750,7 @@ cdata_to_chars(B) when is_binary(B) ->
limit_string(S, F, CharsLimit) when CharsLimit < 0; CharsLimit >= F -> S;
limit_string(S, _F, CharsLimit) ->
- case string:length(S) =< CharsLimit of
+ case io_lib:chars_length(S) =< CharsLimit of
true -> S;
false -> [string:slice(S, 0, sub(CharsLimit, 3)), "..."]
end.
@@ -759,11 +764,11 @@ limit_field(F, CharsLimit) ->
string(S, none, _Adj, none, _Pad) -> S;
string(S, F, Adj, none, Pad) ->
- string_field(S, F, Adj, string:length(S), Pad);
+ string_field(S, F, Adj, io_lib:chars_length(S), Pad);
string(S, none, _Adj, P, Pad) ->
- string_field(S, P, left, string:length(S), Pad);
+ string_field(S, P, left, io_lib:chars_length(S), Pad);
string(S, F, Adj, P, Pad) when F >= P ->
- N = string:length(S),
+ N = io_lib:chars_length(S),
if F > P ->
if N > P ->
adjust(flat_trunc(S, P), chars(Pad, F-P), Adj);
diff --git a/lib/stdlib/src/io_lib_pretty.erl b/lib/stdlib/src/io_lib_pretty.erl
index ba9d9e8434..5483ea87b5 100644
--- a/lib/stdlib/src/io_lib_pretty.erl
+++ b/lib/stdlib/src/io_lib_pretty.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -507,20 +507,20 @@ print_length(#{}=M, _D, _T, _RF, _Enc, _Str) when map_size(M) =:= 0 ->
{"#{}", 3, 0, no_more};
print_length(Atom, _D, _T, _RF, Enc, _Str) when is_atom(Atom) ->
S = write_atom(Atom, Enc),
- {S, string:length(S), 0, no_more};
+ {S, io_lib:chars_length(S), 0, no_more};
print_length(List, D, T, RF, Enc, Str) when is_list(List) ->
%% only flat lists are "printable"
case Str andalso printable_list(List, D, T, Enc) of
true ->
%% print as string, escaping double-quotes in the list
S = write_string(List, Enc),
- {S, string:length(S), 0, no_more};
+ {S, io_lib:chars_length(S), 0, no_more};
{true, Prefix} ->
%% Truncated lists when T < 0 could break some existing code.
S = write_string(Prefix, Enc),
%% NumOfDots = 0 to avoid looping--increasing the depth
%% does not make Prefix longer.
- {[S | "..."], 3 + string:length(S), 0, no_more};
+ {[S | "..."], 3 + io_lib:chars_length(S), 0, no_more};
false ->
case print_length_list(List, D, T, RF, Enc, Str) of
{What, Len, Dots, _More} when Dots > 0 ->
@@ -564,7 +564,7 @@ print_length(<<_/bitstring>> = Bin, D, T, RF, Enc, Str) ->
{[$<,$<,S,$>,$>], 4 + length(S), 0, no_more};
{false, List} when is_list(List) ->
S = io_lib:write_string(List, $"), %"
- {[$<,$<,S,"/utf8>>"], 9 + string:length(S), 0, no_more};
+ {[$<,$<,S,"/utf8>>"], 9 + io_lib:chars_length(S), 0, no_more};
{true, true, Prefix} ->
S = io_lib:write_string(Prefix, $"), %"
More = fun(T1, Dd) ->
@@ -576,7 +576,7 @@ print_length(<<_/bitstring>> = Bin, D, T, RF, Enc, Str) ->
More = fun(T1, Dd) ->
?FUNCTION_NAME(Bin, D+Dd, T1, RF, Enc, Str)
end,
- {[$<,$<,S|"/utf8...>>"], 12 + string:length(S), 3, More};
+ {[$<,$<,S|"/utf8...>>"], 12 + io_lib:chars_length(S), 3, More};
false ->
case io_lib:write_binary(Bin, D, T) of
{S, <<>>} ->
@@ -591,7 +591,7 @@ print_length(<<_/bitstring>> = Bin, D, T, RF, Enc, Str) ->
print_length(Term, _D, _T, _RF, _Enc, _Str) ->
S = io_lib:write(Term),
%% S can contain unicode, so iolist_size(S) cannot be used here
- {S, string:length(S), 0, no_more}.
+ {S, io_lib:chars_length(S), 0, no_more}.
print_length_map(Map, 1, _T, RF, Enc, Str) ->
More = fun(T1, Dd) -> ?FUNCTION_NAME(Map, 1+Dd, T1, RF, Enc, Str) end,
@@ -651,7 +651,7 @@ print_length_record(Tuple, 1, _T, RF, RDefs, Enc, Str) ->
{"{...}", 5, 3, More};
print_length_record(Tuple, D, T, RF, RDefs, Enc, Str) ->
Name = [$# | write_atom(element(1, Tuple), Enc)],
- NameL = string:length(Name),
+ NameL = io_lib:chars_length(Name),
T1 = tsub(T, NameL+2),
L = print_length_fields(RDefs, D - 1, T1, Tuple, 2, RF, Enc, Str),
{Len, Dots} = list_length(L, NameL + 2, 0),
@@ -677,7 +677,7 @@ print_length_fields([Def | Defs], D, T, Tuple, I, RF, Enc, Str) ->
print_length_field(Def, D, T, E, RF, Enc, Str) ->
Name = write_atom(Def, Enc),
- NameL = string:length(Name) + 3,
+ NameL = io_lib:chars_length(Name) + 3,
{_, Len, Dots, _} =
Field = print_length(E, D, tsub(T, NameL), RF, Enc, Str),
{{field, Name, NameL, Field}, NameL + Len, Dots, no_more}.
@@ -738,7 +738,7 @@ printable_list(L, _D, T, _Uni) when T < 0->
io_lib:printable_list(L).
slice(L, N) ->
- try string:length(L) =< N of
+ try io_lib:chars_length(L) =< N of
true ->
all;
false ->
diff --git a/lib/stdlib/src/stdlib.appup.src b/lib/stdlib/src/stdlib.appup.src
index 2a324aef82..9e5d6a3bd8 100644
--- a/lib/stdlib/src/stdlib.appup.src
+++ b/lib/stdlib/src/stdlib.appup.src
@@ -38,7 +38,9 @@
{<<"^3\\.5\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
{<<"^3\\.5\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
{<<"^3\\.6$">>,[restart_new_emulator]},
- {<<"^3\\.6\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}],
+ {<<"^3\\.6\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^3\\.7$">>,[restart_new_emulator]},
+ {<<"^3\\.7\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}],
[{<<"^3\\.4$">>,[restart_new_emulator]},
{<<"^3\\.4\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
{<<"^3\\.4\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
@@ -50,4 +52,6 @@
{<<"^3\\.5\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
{<<"^3\\.5\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
{<<"^3\\.6$">>,[restart_new_emulator]},
- {<<"^3\\.6\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}]}.
+ {<<"^3\\.6\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^3\\.7$">>,[restart_new_emulator]},
+ {<<"^3\\.7\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}]}.
diff --git a/lib/stdlib/test/binary_module_SUITE.erl b/lib/stdlib/test/binary_module_SUITE.erl
index c5cfea5e9e..e0811f19cf 100644
--- a/lib/stdlib/test/binary_module_SUITE.erl
+++ b/lib/stdlib/test/binary_module_SUITE.erl
@@ -22,7 +22,8 @@
-export([all/0, suite/0,
interesting/1,scope_return/1,random_ref_comp/1,random_ref_sr_comp/1,
random_ref_fla_comp/1,parts/1, bin_to_list/1, list_to_bin/1,
- copy/1, referenced/1,guard/1,encode_decode/1,badargs/1,longest_common_trap/1]).
+ copy/1, referenced/1,guard/1,encode_decode/1,badargs/1,longest_common_trap/1,
+ check_no_invalid_read_bug/1]).
-export([random_number/1, make_unaligned/1]).
@@ -36,7 +37,7 @@ all() ->
[scope_return,interesting, random_ref_fla_comp, random_ref_sr_comp,
random_ref_comp, parts, bin_to_list, list_to_bin, copy,
referenced, guard, encode_decode, badargs,
- longest_common_trap].
+ longest_common_trap, check_no_invalid_read_bug].
-define(MASK_ERROR(EXPR),mask_error((catch (EXPR)))).
@@ -1361,3 +1362,13 @@ make_unaligned2(Bin0) when is_binary(Bin0) ->
Bin.
id(I) -> I.
+
+check_no_invalid_read_bug(Config) when is_list(Config) ->
+ check_no_invalid_read_bug(24);
+check_no_invalid_read_bug(60) ->
+ ok;
+check_no_invalid_read_bug(I) ->
+ N = 1 bsl I,
+ binary:encode_unsigned(N+N),
+ binary:encode_unsigned(N+N, little),
+ check_no_invalid_read_bug(I+1).
diff --git a/lib/stdlib/test/erl_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl
index dda8d0a12e..f5d80e7e68 100644
--- a/lib/stdlib/test/erl_pp_SUITE.erl
+++ b/lib/stdlib/test/erl_pp_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -51,7 +51,7 @@
otp_6321/1, otp_6911/1, otp_6914/1, otp_8150/1, otp_8238/1,
otp_8473/1, otp_8522/1, otp_8567/1, otp_8664/1, otp_9147/1,
otp_10302/1, otp_10820/1, otp_11100/1, otp_11861/1, pr_1014/1,
- otp_13662/1, otp_14285/1]).
+ otp_13662/1, otp_14285/1, otp_15592/1]).
%% Internal export.
-export([ehook/6]).
@@ -81,7 +81,7 @@ groups() ->
[otp_6321, otp_6911, otp_6914, otp_8150, otp_8238,
otp_8473, otp_8522, otp_8567, otp_8664, otp_9147,
otp_10302, otp_10820, otp_11100, otp_11861, pr_1014, otp_13662,
- otp_14285]}].
+ otp_14285, otp_15592]}].
init_per_suite(Config) ->
Config.
@@ -1167,6 +1167,11 @@ otp_14285(_Config) ->
[{encoding,latin1}])),
ok.
+otp_15592(_Config) ->
+ ok = pp_expr(<<"long12345678901234567890123456789012345678901234"
+ "56789012345678901234:f(<<>>)">>),
+ ok.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
compile(Config, Tests) ->
diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk
index e0217418fe..d46173497b 100644
--- a/lib/stdlib/vsn.mk
+++ b/lib/stdlib/vsn.mk
@@ -1 +1 @@
-STDLIB_VSN = 3.7
+STDLIB_VSN = 3.7.1