1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2000-2020. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20-module(bs_match_misc_SUITE).
21
22-export([all/0, suite/0,
23	 bound_var/1,bound_tail/1,t_float/1,little_float/1,sean/1,
24	 kenneth/1,encode_binary/1,native/1,happi/1,
25	 size_var/1,wiger/1,x0_context/1,huge_float_field/1,
26	 writable_binary_matched/1,otp_7198/1,unordered_bindings/1,
27	 float_middle_endian/1,unsafe_get_binary_reuse/1, fp16/1]).
28
29-include_lib("common_test/include/ct.hrl").
30
31suite() ->
32    [{ct_hooks,[ts_install_cth]},
33     {timetrap, {seconds, 10}}].
34
35all() ->
36    [bound_var, bound_tail, t_float, little_float, sean,
37     kenneth, encode_binary, native, happi, size_var, wiger,
38     x0_context, huge_float_field, writable_binary_matched,
39     otp_7198, unordered_bindings, float_middle_endian,
40     unsafe_get_binary_reuse, fp16].
41
42
43%% Test matching of bound variables.
44bound_var(Config) when is_list(Config) ->
45    ok = bound_var(42, 13, <<42,13>>),
46    nope = bound_var(42, 13, <<42,255>>),
47    nope = bound_var(42, 13, <<154,255>>),
48    ok.
49
50bound_var(A, B, <<A:8,B:8>>) -> ok;
51bound_var(_, _, _) -> nope.
52
53%% Test matching of a bound tail.
54bound_tail(Config) when is_list(Config) ->
55    ok = bound_tail(<<>>, <<13,14>>),
56    ok = bound_tail(<<2,3>>, <<1,1,2,3>>),
57    nope = bound_tail(<<2,3>>, <<1,1,2,7>>),
58    nope = bound_tail(<<2,3>>, <<1,1,2,3,4>>),
59    nope = bound_tail(<<2,3>>, <<>>),
60    ok.
61
62bound_tail(T, <<_:16,T/binary>>) -> ok;
63bound_tail(_, _) -> nope.
64
65t_float(Config) when is_list(Config) ->
66    F = f1(),
67    G = f_one(),
68
69    G = match_float(<<63,128,0,0>>, 32, 0),
70    G = match_float(<<63,240,0,0,0,0,0,0>>, 64, 0),
71
72    fcmp(F, match_float(<<F:32/float>>, 32, 0)),
73    fcmp(F, match_float(<<F:64/float>>, 64, 0)),
74    fcmp(F, match_float(<<1:1,F:32/float,127:7>>, 32, 1)),
75    fcmp(F, match_float(<<1:1,F:64/float,127:7>>, 64, 1)),
76    fcmp(F, match_float(<<1:13,F:32/float,127:3>>, 32, 13)),
77    fcmp(F, match_float(<<1:13,F:64/float,127:3>>, 64, 13)),
78
79    {'EXIT',{{badmatch,_},_}} = (catch match_float(<<0,0>>, 8, 0)),
80    {'EXIT',{{badmatch,_},_}} = (catch match_float(<<0,0>>, 16#7fffffff, 0)),
81
82    ok.
83
84float_middle_endian(Config) when is_list(Config) ->
85    F = 9007199254740990.0, % turns to -NaN when word-swapped
86    fcmp(F, match_float(<<F:64/float>>, 64, 0)),
87    fcmp(F, match_float(<<1:1,F:64/float,127:7>>, 64, 1)),
88    fcmp(F, match_float(<<1:13,F:64/float,127:3>>, 64, 13)),
89    ok.
90
91
92fcmp(0.0, 0.0) -> ok;
93fcmp(F1, F2) when (F1 - F2) / F2 < 0.0000001 -> ok.
94
95match_float(Bin0, Fsz, I) ->
96    Bin = make_sub_bin(Bin0),
97    Bsz = size(Bin) * 8,
98    Tsz = Bsz - Fsz - I,
99    <<_:I,F:Fsz/float,_:Tsz>> = Bin,
100    F.
101
102little_float(Config) when is_list(Config) ->
103    F = f2(),
104    G = f_one(),
105
106    G = match_float_little(<<0,0,0,0,0,0,240,63>>, 64, 0),
107    G = match_float_little(<<0,0,128,63>>, 32, 0),
108
109    fcmp(F, match_float_little(<<F:32/float-little>>, 32, 0)),
110    fcmp(F, match_float_little(<<F:64/float-little>>, 64, 0)),
111    fcmp(F, match_float_little(<<1:1,F:32/float-little,127:7>>, 32, 1)),
112    fcmp(F, match_float_little(<<1:1,F:64/float-little,127:7>>, 64, 1)),
113    fcmp(F, match_float_little(<<1:13,F:32/float-little,127:3>>, 32, 13)),
114    fcmp(F, match_float_little(<<1:13,F:64/float-little,127:3>>, 64, 13)),
115
116    ok.
117
118match_float_little(Bin0, Fsz, I) ->
119    Bin = make_sub_bin(Bin0),
120    Bsz = size(Bin) * 8,
121    Tsz = Bsz - Fsz - I,
122    <<_:I,F:Fsz/float-little,_:Tsz>> = Bin,
123    F.
124
125
126make_sub_bin(Bin0) ->
127    Sz = size(Bin0),
128    Bin1 = <<37,Bin0/binary,38,39>>,
129    <<_:8,Bin:Sz/binary,_:8,_:8>> = Bin1,
130    Bin.
131
132f1() ->
133    3.1415.
134
135f2() ->
136    2.7133.
137
138f_one() ->
139    1.0.
140
141sean(Config) when is_list(Config) ->
142    small = sean1(<<>>),
143    small = sean1(<<1>>),
144    small = sean1(<<1,2>>),
145    small = sean1(<<1,2,3>>),
146    large = sean1(<<1,2,3,4>>),
147
148    small = sean1(<<4>>),
149    small = sean1(<<4,5>>),
150    small = sean1(<<4,5,6>>),
151    {'EXIT',{function_clause,_}} = (catch sean1(<<4,5,6,7>>)),
152    ok.
153
154sean1(<<B/binary>>) when byte_size(B) < 4 -> small;
155sean1(<<1, _B/binary>>) -> large.
156
157kenneth(Config) when is_list(Config) ->
158    {ok,[145,148,113,129,0,0,0,0]} =
159	msisdn_internal_storage(<<145,148,113,129,0,0,0,0>>, []).
160
161msisdn_internal_storage(<<>>,MSISDN) ->
162    {ok,lists:reverse(MSISDN)};
163msisdn_internal_storage(<<2#11111111:8,_Rest/binary>>,MSISDN) ->
164    {ok,lists:reverse(MSISDN)};
165msisdn_internal_storage(<<2#1111:4,DigitN:4,_Rest/binary>>,MSISDN) when
166    DigitN < 10 ->
167    {ok,lists:reverse([(DigitN bor 2#11110000)|MSISDN])};
168msisdn_internal_storage(<<DigitNplus1:4,DigitN:4,Rest/binary>>,MSISDN) when
169    DigitNplus1 < 10,
170    DigitN < 10 ->
171    NewMSISDN=[((DigitNplus1 bsl 4) bor DigitN)|MSISDN],
172    msisdn_internal_storage(Rest,NewMSISDN);
173msisdn_internal_storage(_Rest,_MSISDN) ->
174    {fault}. %% Mandatory IE incorrect
175
176encode_binary(Config) when is_list(Config) ->
177    "C2J2QiSc" = encodeBinary(<<11,98,118,66,36,156>>, []),
178    ok.
179
180encodeBinary(<<>>, Output) ->
181    lists:reverse(Output);
182encodeBinary(<<Data:1/binary>>, Output) ->
183    <<DChar1:6, DChar2:2>> = Data,
184    Char1 = getBase64Char(DChar1),
185    Char2 = getBase64Char(DChar2),
186    Char3 = "=",
187    Char4 = "=",
188    NewOutput = Char4 ++ Char3 ++ Char2 ++ Char1 ++ Output,
189    encodeBinary(<<>>, NewOutput);
190encodeBinary(<<Data:2/binary>>, Output) ->
191    <<DChar1:6, DChar2:6, DChar3:4>> = Data,
192    Char1 = getBase64Char(DChar1),
193    Char2 = getBase64Char(DChar2),
194    Char3 = getBase64Char(DChar3),
195    Char4 = "=",
196    NewOutput = Char4 ++ Char3 ++ Char2 ++ Char1 ++ Output,
197    encodeBinary(<<>>, NewOutput);
198encodeBinary(<<Data:3/binary, Rest/binary>>, Output) ->
199    <<DChar1:6, DChar2:6, DChar3:6, DChar4:6>> = Data,
200    Char1 = getBase64Char(DChar1),
201    Char2 = getBase64Char(DChar2),
202    Char3 = getBase64Char(DChar3),
203    Char4 = getBase64Char(DChar4),
204    NewOutput = Char4 ++ Char3 ++ Char2 ++ Char1 ++ Output,
205    encodeBinary(Rest, NewOutput);
206encodeBinary(_Data, _) ->
207    error.
208
209getBase64Char(0)  -> "A";
210getBase64Char(1)  -> "B";
211getBase64Char(2)  -> "C";
212getBase64Char(3)  -> "D";
213getBase64Char(4)  -> "E";
214getBase64Char(5)  -> "F";
215getBase64Char(6)  -> "G";
216getBase64Char(7)  -> "H";
217getBase64Char(8)  -> "I";
218getBase64Char(9)  -> "J";
219getBase64Char(10) -> "K";
220getBase64Char(11) -> "L";
221getBase64Char(12) -> "M";
222getBase64Char(13) -> "N";
223getBase64Char(14) -> "O";
224getBase64Char(15) -> "P";
225getBase64Char(16) -> "Q";
226getBase64Char(17) -> "R";
227getBase64Char(18) -> "S";
228getBase64Char(19) -> "T";
229getBase64Char(20) -> "U";
230getBase64Char(21) -> "V";
231getBase64Char(22) -> "W";
232getBase64Char(23) -> "X";
233getBase64Char(24) -> "Y";
234getBase64Char(25) -> "Z";
235getBase64Char(26) -> "a";
236getBase64Char(27) -> "b";
237getBase64Char(28) -> "c";
238getBase64Char(29) -> "d";
239getBase64Char(30) -> "e";
240getBase64Char(31) -> "f";
241getBase64Char(32) -> "g";
242getBase64Char(33) -> "h";
243getBase64Char(34) -> "i";
244getBase64Char(35) -> "j";
245getBase64Char(36) -> "k";
246getBase64Char(37) -> "l";
247getBase64Char(38) -> "m";
248getBase64Char(39) -> "n";
249getBase64Char(40) -> "o";
250getBase64Char(41) -> "p";
251getBase64Char(42) -> "q";
252getBase64Char(43) -> "r";
253getBase64Char(44) -> "s";
254getBase64Char(45) -> "t";
255getBase64Char(46) -> "u";
256getBase64Char(47) -> "v";
257getBase64Char(48) -> "w";
258getBase64Char(49) -> "x";
259getBase64Char(50) -> "y";
260getBase64Char(51) -> "z";
261getBase64Char(52) -> "0";
262getBase64Char(53) -> "1";
263getBase64Char(54) -> "2";
264getBase64Char(55) -> "3";
265getBase64Char(56) -> "4";
266getBase64Char(57) -> "5";
267getBase64Char(58) -> "6";
268getBase64Char(59) -> "7";
269getBase64Char(60) -> "8";
270getBase64Char(61) -> "9";
271getBase64Char(62) -> "+";
272getBase64Char(63) -> "/";
273getBase64Char(_Else) ->
274    %% This is an illegal input.
275%    cgLogEM:log(error, ?MODULE, getBase64Char, [Else],
276%		"illegal input",
277%		?LINE, version()),
278    "**".
279
280-define(M(F), <<F>> = <<F>>).
281
282native(Config) when is_list(Config) ->
283    ?M(3.14:64/native-float),
284    ?M(333:16/native),
285    ?M(38658345:32/native),
286    case <<1:16/native>> of
287	<<0,1>> -> native_big();
288	<<1,0>> -> native_little()
289    end.
290
291native_big() ->
292    <<37.33:64/native-float>> = <<37.33:64/big-float>>,
293    <<3974:16/native-integer>> = <<3974:16/big-integer>>,
294    {comment,"Big endian"}.
295
296native_little() ->
297    <<37869.32343:64/native-float>> = <<37869.32343:64/little-float>>,
298    <<7974:16/native-integer>> = <<7974:16/little-integer>>,
299    {comment,"Little endian"}.
300
301happi(Config) when is_list(Config) ->
302    Bin = <<".123">>,
303    <<"123">> = lex_digits1(Bin, 1, []),
304    <<"123">> = lex_digits2(Bin, 1, []),
305    ok.
306
307lex_digits1(<<$., Rest/binary>>,_Val,_Acc) ->
308    Rest;
309lex_digits1(<<N, Rest/binary>>,Val, Acc) when N >= $0 , N =< $9 ->
310    lex_digits1(Rest,Val*10+dec(N),Acc);
311lex_digits1(_Other,_Val,_Acc) ->
312    not_ok.
313
314lex_digits2(<<N, Rest/binary>>,Val, Acc) when N >= $0 , N =< $9 ->
315    lex_digits2(Rest,Val*10+dec(N),Acc);
316lex_digits2(<<$., Rest/binary>>,_Val,_Acc) ->
317    Rest;
318lex_digits2(_Other,_Val,_Acc) ->
319    not_ok.
320
321dec(A) ->
322    A-$0.
323
324size_var(Config) when is_list(Config) ->
325    {<<45>>,<<>>} = split(<<1:16,45>>),
326    {<<45>>,<<46,47>>} = split(<<1:16,45,46,47>>),
327    {<<45,46>>,<<47>>} = split(<<2:16,45,46,47>>),
328
329    {<<45,46,47>>,<<48>>} = split_2(<<16:8,3:16,45,46,47,48>>),
330
331    {<<45,46>>,<<47>>} = split(2, <<2:16,45,46,47>>),
332    {'EXIT',{function_clause,_}} = (catch split(42, <<2:16,45,46,47>>)),
333
334    <<"cdef">> = skip(<<2:8,"abcdef">>),
335
336    ok.
337
338split(<<N:16,B:N/binary,T/binary>>) ->
339    {B,T}.
340
341split(N, <<N:16,B:N/binary,T/binary>>) ->
342    {B,T}.
343
344split_2(<<N0:8,N:N0,B:N/binary,T/binary>>) ->
345    {B,T}.
346
347skip(<<N:8,_:N/binary,T/binary>>) -> T.
348
349wiger(Config) when is_list(Config) ->
350    ok1 = wcheck(<<3>>),
351    ok2 = wcheck(<<1,2,3>>),
352    ok3 = wcheck(<<4>>),
353    {error,<<1,2,3,4>>} = wcheck(<<1,2,3,4>>),
354    {error,<<>>} = wcheck(<<>>),
355    ok.
356
357wcheck(<<A>>) when A==3->
358    ok1;
359wcheck(<<_,_:2/binary>>) ->
360    ok2;
361wcheck(<<_>>) ->
362    ok3;
363wcheck(Other) ->
364    {error,Other}.
365
366%% Test that having the match context in x(0) works.
367
368x0_context(Config) when is_list(Config) ->
369    x0_0([], <<3.0:64/float,42:16,123456:32>>).
370
371x0_0(_, Bin) ->
372    <<3.0:64/float,42:16,_/binary>> = Bin,
373    x0_1([], Bin, 64, 16, 2).
374
375x0_1(_, Bin, FloatSz, IntSz, BinSz) ->
376    <<_:FloatSz/float,42:IntSz,B:BinSz/binary,C:1/binary,D/binary>> = Bin,
377    id({B,C,D}),
378    <<_:FloatSz/float,42:IntSz,B:BinSz/binary,_/binary>> = Bin,
379    x0_2([], Bin).
380
381x0_2(_, Bin) ->
382    <<_:64,0:7,42:9,_/binary>> = Bin,
383    x0_3([], Bin).
384
385x0_3(_, Bin) ->
386    case Bin of
387        <<_:72,7:8,_/binary>> ->
388            ct:fail(bs_matched_1);
389        <<_:64,0:16,_/binary>> ->
390            ct:fail(bs_matched_2);
391        <<_:64,42:16,123456:32,_/binary>> ->
392            ok
393    end.
394
395
396huge_float_field(Config) when is_list(Config) ->
397    Sz = 1 bsl 27,
398    Bin = <<0:Sz>>,
399
400    nomatch = overflow_huge_float_skip_32(Bin),
401    nomatch = overflow_huge_float_32(Bin),
402
403    ok = overflow_huge_float(Bin, lists:seq(25, 32)++lists:seq(50, 64)),
404    ok = overflow_huge_float_unit128(Bin, lists:seq(25, 32)++lists:seq(50, 64)),
405    ok.
406
407overflow_huge_float_skip_32(<<_:4294967296/float,0,_/binary>>) -> 1; % 1 bsl 32
408overflow_huge_float_skip_32(<<_:33554432/float-unit:128,0,_/binary>>) -> 2; % 1 bsl 25
409overflow_huge_float_skip_32(<<_:67108864/float-unit:64,0,_/binary>>) -> 3; % 1 bsl 26
410overflow_huge_float_skip_32(<<_:134217728/float-unit:32,0,_/binary>>) -> 4; % 1 bsl 27
411overflow_huge_float_skip_32(<<_:268435456/float-unit:16,0,_/binary>>) -> 5; % 1 bsl 28
412overflow_huge_float_skip_32(<<_:536870912/float-unit:8,0,_/binary>>) -> 6; % 1 bsl 29
413overflow_huge_float_skip_32(<<_:1073741824/float-unit:8,0,_/binary>>) -> 7; % 1 bsl 30
414overflow_huge_float_skip_32(<<_:2147483648/float-unit:8,0,_/binary>>) -> 8; % 1 bsl 31
415overflow_huge_float_skip_32(_) -> nomatch.
416
417overflow_huge_float_32(<<F:4294967296/float,_/binary>>) -> {1,F}; % 1 bsl 32
418overflow_huge_float_32(<<F:33554432/float-unit:128,0,_/binary>>) -> {2,F}; % 1 bsl 25
419overflow_huge_float_32(<<F:67108864/float-unit:128,0,_/binary>>) -> {3,F}; % 1 bsl 26
420overflow_huge_float_32(<<F:134217728/float-unit:128,0,_/binary>>) -> {4,F}; % 1 bsl 27
421overflow_huge_float_32(<<F:268435456/float-unit:128,0,_/binary>>) -> {5,F}; % 1 bsl 28
422overflow_huge_float_32(<<F:536870912/float-unit:128,0,_/binary>>) -> {6,F}; % 1 bsl 29
423overflow_huge_float_32(<<F:1073741824/float-unit:128,0,_/binary>>) -> {7,F}; % 1 bsl 30
424overflow_huge_float_32(<<F:2147483648/float-unit:128,0,_/binary>>) -> {8,F}; % 1 bsl 31
425overflow_huge_float_32(_) -> nomatch.
426
427
428overflow_huge_float(Bin, [Sz0|Sizes]) ->
429    Sz = id(1 bsl Sz0),
430    case Bin of
431	<<_:Sz/float-unit:8,0,_/binary>> ->
432	    {error,Sz};
433	_ ->
434	    case Bin of
435		<<Var:Sz/float-unit:8,0,_/binary>> ->
436		    {error,Sz,Var};
437		_ ->
438		    overflow_huge_float(Bin, Sizes)
439	    end
440    end;
441overflow_huge_float(_, []) -> ok.
442
443overflow_huge_float_unit128(Bin, [Sz0|Sizes]) ->
444    Sz = id(1 bsl Sz0),
445    case Bin of
446        <<_:Sz/float-unit:128,0,_/binary>> ->
447            {error,Sz};
448        _ ->
449            case Bin of
450                <<Var:Sz/float-unit:128,0,_/binary>> ->
451                    {error,Sz,Var};
452                _ ->
453                    overflow_huge_float_unit128(Bin, Sizes)
454            end
455    end;
456overflow_huge_float_unit128(_, []) -> ok.
457
458
459%%
460%% Test that a writable binary can be safely matched.
461%%
462
463writable_binary_matched(Config) when is_list(Config) ->
464    WritableBin = create_writeable_binary(),
465    writable_binary_matched(WritableBin, WritableBin, 500).
466
467writable_binary_matched(<<0>>, _, N) ->
468    if N =:= 0 -> ok;
469       true ->
470           put(grow_heap, [N|get(grow_heap)]),
471           WritableBin = create_writeable_binary(),
472           writable_binary_matched(WritableBin, WritableBin, N-1)
473    end;
474writable_binary_matched(<<B:8,T/binary>>, WritableBin0, N) ->
475    WritableBin = writable_binary(WritableBin0, B),
476    writable_binary_matched(T, WritableBin, N).
477
478writable_binary(WritableBin0, B) when is_binary(WritableBin0) ->
479    %% Heavy append to force the binary to move.
480    WritableBin = <<WritableBin0/binary,0:(size(WritableBin0))/unit:8,B>>,
481    id(<<(id(0)):128/unit:8>>),
482    WritableBin.
483
484create_writeable_binary() ->
485  <<(id(<<>>))/binary,1,2,3,4,5,6,0>>.
486
487otp_7198(Config) when is_list(Config) ->
488    %% When a match context was reused, and grown at the same time to
489    %% increase the number of saved positions, the thing word was not updated
490    %% to account for the new size. Therefore, if there was a garbage collection,
491    %% the new slots would be included in the garbage collection.
492    [do_otp_7198(FillerSize) || FillerSize <- lists:seq(0, 256)],
493    ok.
494
495do_otp_7198(FillerSize) ->
496    Filler = erlang:make_tuple(FillerSize, 42),
497    {Pid,Ref} = spawn_monitor(fun() -> do_otp_7198_test(Filler) end),
498    receive
499	{'DOWN',Ref,process,Pid,normal} ->
500	    ok;
501	{'DOWN',Ref,process,Pid,Reason} ->
502	    ct:fail("unexpected: ~p", [Reason])
503    end.
504
505do_otp_7198_test(_) ->
506    [{'KEYWORD',114},
507     {'KEYWORD',101},
508     {'KEYWORD',103},
509     {'KEYWORD',105},
510     {'KEYWORD',111},
511     {'FIELD',110},
512     {'KEYWORD',119},
513     {'KEYWORD',104},
514     {'KEYWORD',97},
515     {'KEYWORD',116},
516     {'KEYWORD',101},
517     {'KEYWORD',118},
518     {'KEYWORD',101},
519     {'KEYWORD',114},
520     '$thats_all_folks$'] = otp_7198_scan(<<"region:whatever">>, []).
521
522
523otp_7198_scan(<<>>, TokAcc) ->
524        lists:reverse(['$thats_all_folks$' | TokAcc]);
525
526otp_7198_scan(<<D, Z, Rest/binary>>, TokAcc) when
527                        (D =:= $D orelse D =:= $d) and
528                        ((Z =:= $\s) or (Z =:= $() or (Z =:= $))) ->
529    otp_7198_scan(<<Z, Rest/binary>>, ['AND' | TokAcc]);
530
531otp_7198_scan(<<D>>, TokAcc) when
532                        (D =:= $D) or (D =:= $d) ->
533    otp_7198_scan(<<>>, ['AND' | TokAcc]);
534
535otp_7198_scan(<<N, Z, Rest/binary>>, TokAcc) when
536                        (N =:= $N orelse N =:= $n) and
537                        ((Z =:= $\s) or (Z =:= $() or (Z =:= $))) ->
538    otp_7198_scan(<<Z, Rest/binary>>, ['NOT' | TokAcc]);
539
540otp_7198_scan(<<C, Rest/binary>>, TokAcc) when
541                                (C >= $A) and (C =< $Z);
542                                (C >= $a) and (C =< $z);
543                                (C >= $0) and (C =< $9) ->
544    case Rest of
545        <<$:, R/binary>> ->
546            otp_7198_scan(R, [{'FIELD', C} | TokAcc]);
547        _ ->
548            otp_7198_scan(Rest, [{'KEYWORD', C} | TokAcc])
549    end.
550
551unordered_bindings(Config) when is_list(Config) ->
552    {<<1,2,3,4>>,<<42,42>>,<<3,3,3>>} =
553	unordered_bindings(4, 2, 3, <<1,2,3,4, 42,42, 3,3,3, 3>>),
554    ok.
555
556unordered_bindings(CompressedLength, HashSize, PadLength, T) ->
557    <<Content:CompressedLength/binary,Mac:HashSize/binary,
558     Padding:PadLength/binary,PadLength>> = T,
559    {Content,Mac,Padding}.
560
561%% ERL-901: A load-time optimization assumed that match contexts had no further
562%% uses when a bs_get_binary2 overwrote the match context's register, and
563%% figured it would be safe to reuse the match context's memory for the
564%% resulting binary.
565%%
566%% This is no longer safe as of OTP 22, as a match context may be reused after
567%% being passed to another function.
568unsafe_get_binary_reuse(Config) when is_list(Config) ->
569    <<_First, Rest/binary>> = <<"hello">>,
570    ubgr_1(Rest),
571    <<Second,_/bits>> = Rest,
572    $e = Second,
573    ok.
574
575ubgr_1(<<_CP/utf8, Rest/binary>>) -> id(Rest);
576ubgr_1(_) -> false.
577
578id(I) -> I.
579
580-define(FP16(EncodedInt, Float),
581        (fun(NlInt, NlFloat) ->
582                  <<F1:16/float>> = <<NlInt:16>>,
583                  fcmp(F1, NlFloat),
584                  <<F2:16/float>> = <<(NlInt+16#8000):16>>,
585                  fcmp(F2, NlFloat),
586                  <<F3:16/float-little>> = <<NlInt:16/little>>,
587                  fcmp(F3, NlFloat),
588                  <<F4:16/float-little>> = <<(NlInt+16#8000):16/little>>,
589                  fcmp(F4, NlFloat),
590                  <<F5:16/float-native>> = <<NlInt:16/native>>,
591                  fcmp(F5, NlFloat),
592                  <<F6:16/float-native>> = <<(NlInt+16#8000):16/native>>,
593                  fcmp(F6, NlFloat)
594         end)(nonliteral(EncodedInt), nonliteral(Float)),
595        (fun() ->
596                  <<F1:16/float>> = <<EncodedInt:16>>,
597                  fcmp(F1, Float),
598                  <<F2:16/float>> = <<(EncodedInt+16#8000):16>>,
599                  fcmp(F2, Float),
600                  <<F3:16/float-little>> = <<EncodedInt:16/little>>,
601                  fcmp(F3, Float),
602                  <<F4:16/float-little>> = <<(EncodedInt+16#8000):16/little>>,
603                  fcmp(F4, Float),
604                  <<F3:16/float-native>> = <<EncodedInt:16/native>>,
605                  fcmp(F3, Float),
606                  <<F4:16/float-native>> = <<(EncodedInt+16#8000):16/native>>,
607                  fcmp(F4, Float)
608         end)()).
609
610nonliteral(X) -> X.
611
612fp16(_Config) ->
613    %% smallest positive subnormal number
614    ?FP16(16#0001, 0.000000059604645),
615    %% largest positive subnormal number
616    ?FP16(16#03ff, 0.000060975552),
617    %% smallest positive normal number
618    ?FP16(16#0400, 0.00006103515625),
619    %% largest normal number
620    ?FP16(16#7bff, 65504),
621    ?FP16(16#7bff, 65504.0),
622    %% largest number less than one
623    ?FP16(16#3bff, 0.99951172),
624    %% zero
625    ?FP16(16#0000, 0.0),
626    %% one
627    ?FP16(16#3c00, 1),
628    ?FP16(16#3c00, 1.0),
629    %% smallest number larger than one
630    ?FP16(16#3c01, 1.00097656),
631    %% rounding of 1/3 to nearest
632    ?FP16(16#3555, 0.33325195),
633    %% others
634    ?FP16(16#4000, 2),
635    ?FP16(16#4000, 2.0),
636    ok.
637