1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2006-2018. 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%% Originally based on Per Gustafsson's test suite.
21%%
22
23-module(bs_bincomp_SUITE).
24
25-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
26	 init_per_group/2,end_per_group/2,
27	 byte_aligned/1,bit_aligned/1,extended_byte_aligned/1,
28	 extended_bit_aligned/1,mixed/1,filters/1,trim_coverage/1,
29	 nomatch/1,sizes/1,general_expressions/1,matched_out_size/1,
30         no_generator/1]).
31
32-include_lib("common_test/include/ct.hrl").
33
34suite() -> [{ct_hooks,[ts_install_cth]}].
35
36all() ->
37    [byte_aligned, bit_aligned, extended_byte_aligned,
38     extended_bit_aligned, mixed, filters, trim_coverage,
39     nomatch, sizes, general_expressions, matched_out_size,
40     no_generator].
41
42groups() ->
43    [].
44
45init_per_suite(Config) ->
46    test_lib:recompile(?MODULE),
47    Config.
48
49end_per_suite(_Config) ->
50    ok.
51
52init_per_group(_GroupName, Config) ->
53	Config.
54
55end_per_group(_GroupName, Config) ->
56	Config.
57
58byte_aligned(Config) when is_list(Config) ->
59    cs_init(),
60    <<"abcdefg">> = cs(<< <<(X+32)>> || <<X>> <= <<"ABCDEFG">> >>),
61    <<"AxyzBxyzCxyz">> = cs(<< <<X, "xyz">> || <<X>> <= <<"ABC">> >>),
62    <<1:32/little,2:32/little,3:32/little,4:32/little>> =
63	cs(<< <<X:32/little>> || <<X:32>> <= <<1:32,2:32,3:32,4:32>> >>),
64    cs(<<1:32/little,2:32/little,3:32/little,4:32/little>> =
65	   << <<X:32/little>> || <<X:16>> <= <<1:16,2:16,3:16,4:16>> >>),
66    cs_end().
67
68bit_aligned(Config) when is_list(Config) ->
69    cs_init(),
70    <<$a:7,$b:7,$c:7,$d:7,$e:7,$f:7,$g:7>> =
71	cs(<< <<(X+32):7>> || <<X>> <= <<"ABCDEFG">> >>),
72    <<"ABCDEFG">> =
73	cs(<< <<(X-32)>> || <<X:7>> <= <<$a:7,$b:7,$c:7,$d:7,$e:7,$f:7,$g:7>> >>),
74    <<1:31/little,2:31/little,3:31/little,4:31/little>> =
75	cs(<< <<X:31/little>> || <<X:31>> <= <<1:31,2:31,3:31,4:31>> >>),
76    <<1:31/little,2:31/little,3:31/little,4:31/little>> =
77	cs(<< <<X:31/little>> || <<X:15>> <= <<1:15,2:15,3:15,4:15>> >>),
78    cs_end().
79
80extended_byte_aligned(Config) when is_list(Config) ->
81    cs_init(),
82    <<"abcdefg">> = cs(<< <<(X+32)>> || X <- "ABCDEFG" >>),
83    "abcdefg" = [(X+32) || <<X>> <= <<"ABCDEFG">>],
84    <<1:32/little,2:32/little,3:32/little,4:32/little>> =
85	cs(<< <<X:32/little>> || X <- [1,2,3,4] >>),
86    [256,512,768,1024] =
87	[X || <<X:16/little>> <= <<1:16,2:16,3:16,4:16>>],
88    cs_end().
89
90extended_bit_aligned(Config) when is_list(Config) ->
91    cs_init(),
92    <<$a:7,$b:7,$c:7,$d:7,$e:7,$f:7,$g:7>> =
93	cs(<< <<(X+32):7>> || X <- "ABCDEFG" >>),
94    "ABCDEFG" = [(X-32) || <<X:7>> <= <<$a:7,$b:7,$c:7,$d:7,$e:7,$f:7,$g:7>>],
95    <<1:31/little,2:31/little,3:31/little,4:31/little>> =
96	cs(<< <<X:31/little>> || X <- [1,2,3,4] >>),
97    [256,512,768,1024] =
98	[X || <<X:15/little>> <= <<1:15,2:15,3:15,4:15>>],
99    cs_end().
100
101mixed(Config) when is_list(Config) ->
102    cs_init(),
103    <<2,3,3,4,4,5,5,6>> =
104	cs_default(<< <<(X+Y)>> || <<X>> <= <<1,2,3,4>>, <<Y>> <= <<1,2>> >>),
105    <<2,3,3,4,4,5,5,6>> =
106	cs_default(<< <<(X+Y)>> || <<X>> <= <<1,2,3,4>>, Y <- [1,2] >>),
107    <<2,3,3,4,4,5,5,6>> =
108	cs_default(<< <<(X+Y)>> || X <- [1,2,3,4], Y <- [1,2] >>),
109    One = id([1,2,3,4]),
110    Two = id([1,2]),
111    <<2,3,3,4,4,5,5,6>> =
112	cs_default(<< <<(X+Y)>> || X <- One, Y <- Two >>),
113    [2,3,3,4,4,5,5,6] =
114	[(X+Y) || <<X>> <= <<1,2,3,4>>, <<Y>> <= <<1,2>>],
115    [2,3,3,4,4,5,5,6] =
116	[(X+Y) || <<X>> <= <<1,2,3,4>>, Y <- [1,2]],
117    <<2:3,3:3,3:3,4:3,4:3,5:3,5:3,6:3>> =
118	cs_default(<< <<(X+Y):3>> || <<X:3>> <= <<1:3,2:3,3:3,4:3>>,
119                                     <<Y:3>> <= <<1:3,2:3>> >>),
120    <<2:3,3:3,3:3,4:3,4:3,5:3,5:3,6:3>> =
121	cs_default(<< <<(X+Y):3>> || <<X:3>> <= <<1:3,2:3,3:3,4:3>>, Y <- [1,2] >>),
122    <<2:3,3:3,3:3,4:3,4:3,5:3,5:3,6:3>> =
123	cs_default(<< <<(X+Y):3>> || X <- [1,2,3,4], Y <- [1,2] >>),
124    <<2:3,3:3,3:3,4:3,4:3,5:3,5:3,6:3>> =
125	cs_default(<< <<(X+Y):3>> || {X,Y} <- [{1,1},{1,2},{2,1},{2,2},
126					       {3,1},{3,2},{4,1},{4,2}] >>),
127    [2,3,3,4,4,5,5,6] =
128	[(X+Y) || <<X:3>> <= <<1:3,2:3,3:3,4:3>>, <<Y:3>> <= <<1:3,2:3>>],
129    [2,3,3,4,4,5,5,6] =
130	[(X+Y) || <<X:3>> <= <<1:3,2:3,3:3,4:3>>, {_,Y} <- [{a,1},{b,2}]],
131
132    %% OTP-16899: Nested binary comprehensions would fail to load.
133    <<0,1,0,2,0,3,99>> = mixed_nested([1,2,3]),
134
135    <<1>> = cs_default(<< <<X>> || L <- [[1]], X <- L >>),
136
137    cs_end().
138
139mixed_nested(L) ->
140    << << << << E:16 >> || E <- L >> || true >>/binary, 99:(id(8))>>.
141
142filters(Config) when is_list(Config) ->
143    cs_init(),
144    <<"BDF">> =
145	cs_default(<< <<(X-32)>> ||
146		       <<X:7>> <= <<$a:7,$b:7,$c:7,$d:7,$e:7,$f:7,$g:7>>,
147		       X rem 2 == 0>>),
148    <<"abc">> = cs_default(<< <<(X+32)>> ||
149			       X <- "ABCDEFG",
150			       is_less_than(X, $D)>>),
151    <<"efg">> = cs_default(<< <<(X+32)>> ||
152			       X <- "ABCDEFG",
153			       not is_less_than(X, $E)>>),
154    <<"b">> = cs_default(<< <<(X+32)>> ||
155			     X <- "ABCDEFG",
156			     is_less_than(X, $D),
157			     X rem 2 == 0>>),
158    <<"eg">> = cs_default(<< <<(X+32)>> ||
159			      X <- "ABCDEFG",
160			      not is_less_than(X, $E),
161			      X rem 2 == 1>>),
162
163    %% Filtering by a non-matching pattern.
164    <<"abd">> = cs_default(<< <<X:8>> ||
165			       <<0:1,X:7>> <= <<$a:8,$b:8,1:1,$c:7,$d:8,
166						1:1,$e:7,0:4>> >>),
167
168    <<42,42>> = cs_default(<< <<42:8>> || 42 <- [1,2,3,42,43,42] >>),
169    cs_end().
170
171is_less_than(X, C) when X < C -> true;
172is_less_than(_, _) -> false.
173
174trim_coverage(Config) when is_list(Config) ->
175    <<0,0,0,2,0,0,5,48,0,11,219,174,0,0,0,0>> = coverage_materialiv(a, b, {1328,777134}),
176    <<67,40,0,0,66,152,0,0,69,66,64,0>> = coverage_trimmer([42,19,777]),
177    <<0,0,2,43,0,0,3,9,0,0,0,3,64,8,0,0,0,0,0,0,
178	   64,68,0,0,0,0,0,0,192,171,198,0,0,0,0,0>> =
179	coverage_lightfv(555, 777, {3.0,40.0,-3555.0}),
180    ok.
181
182coverage_materialiv(A, B, Params) ->
183    A = id(A),
184    B = id(B),
185    <<(tuple_size(Params)):32,
186     (<< <<C:32>> || C <- tuple_to_list(Params)>>)/binary,
187     0:(((1+tuple_size(Params)) rem 2)*32)>>.
188
189coverage_lightfv(Light, Pname, Params) ->
190    id(<<Light:32,Pname:32,(size(Params)):32,
191	(<< <<C:64/float>> || C <- tuple_to_list(Params)>>)/binary,
192	0:(((1+size(Params)) rem 2)*32)>>).
193
194coverage_trimmer(Params) ->
195    X = id(0),
196    Y = id(1),
197    id({X,Y}),
198    << <<(begin {A,B,D} = id({C,C,C}), id(0),
199		coverage_summer(A, B, C, D) end):32/float>> ||
200	C <- Params >>.
201
202coverage_summer(A, B, C, D) -> A+B+C+D.
203
204nomatch(Config) when is_list(Config) ->
205    Bin = id(<<1,2,3,4,5>>),
206    <<>> = << <<X:8>> || X = {_,_} = [_|_] <- [1,2,3] >>,
207    [] = [X || <<X:all/binary>> <= Bin],
208    [] = [X || <<X:bad/binary>> <= Bin],
209    <<>> = << <<X:32>> || <<X:all/binary>> <= Bin >>,
210    <<>> = << <<X:32>> || <<X:bad/binary>> <= Bin >>,
211
212    <<>> = << <<"a">> || <<_:1/float>> <= Bin>>,
213
214    NaN = <<(-1):32>>,
215    <<>> = << <<"a">> || <<_:32/float>> <= NaN >>,
216
217    ok.
218
219sizes(Config) when is_list(Config) ->
220    cs_init(),
221    Fun0 = fun(List) ->
222		   cs(<< <<E:8>> || E <- List >>)
223	   end,
224    <<>> = Fun0([]),
225    <<1>> = Fun0([1]),
226    <<1,2>> = Fun0([1,2]),
227    <<1,2,3>> = Fun0([1,2,3]),
228
229    Fun1 = fun(List) ->
230		   cs(<< <<E:16>> || E <- List >>)
231	   end,
232    <<>> = Fun1([]),
233    <<1:16>> = Fun1([1]),
234    <<1:16,2:16>> = Fun1([1,2]),
235    <<1:16,2:16,3:16>> = Fun1([1,2,3]),
236
237    Fun2 = fun(List) ->
238		   cs(<< <<E:4>> || E <- List >>)
239	   end,
240    <<>> = Fun2([]),
241    <<1:4>> = Fun2([1]),
242    <<1:4,13:4>> = Fun2([1,13]),
243    <<1:4,13:4,7:4>> = Fun2([1,13,7]),
244    <<0:1000/unit:8>> = Fun2(lists:duplicate(2000, 0)),
245
246    Fun3 = fun(List) ->
247		   cs(<< <<E:3>> || E <- List >>)
248	   end,
249    <<>> = Fun3([]),
250    <<40,177,29:5>> = Fun3([1,2,1,3,0,7,5]),
251    <<0:512/unit:3>> = Fun3(lists:duplicate(512, 0)),
252
253    Fun4 = fun(List, Size) ->
254		   cs(<< <<E:Size>> || E <- List >>)
255	   end,
256    <<>> = Fun4([], 8),
257    <<42:6>> = Fun4([42], 6),
258    <<42:16>> = Fun4([42], 16),
259
260    Fun5 = fun(List, Sz1, Sz2, Sz3) ->
261		   cs(<< <<E:Sz1,(E+1):Sz2/unit:8,(E+2):Sz3/unit:8>> || E <- List >>)
262	   end,
263    <<>> = Fun5([], 1, 1, 1),
264    <<7:3,8:40,9:56>> = Fun5([7], 3, 5, 7),
265
266    Fun6 = fun(List, Size) ->
267		   cs(<< <<E:8,(E+1):Size>> || E <- List >>)
268	   end,
269    <<>> = Fun6([], 42),
270    <<42,43:20>> = Fun6([42], 20),
271
272    %% Binary generators.
273
274    Fun10 = fun(Bin) ->
275		    cs(<< <<E:16>> || <<E:8>> <= Bin >>)
276            end,
277    <<>> = Fun10(<<>>),
278    <<1:16>> = Fun10(<<1>>),
279    <<1:16,2:16>> = Fun10(<<1,2>>),
280
281    Fun11 = fun(Bin) ->
282		    cs(<< <<E:8>> || <<E:16>> <= Bin >>)
283            end,
284    <<>> = Fun11(<<>>),
285    <<1>> = Fun11(<<1:16>>),
286    <<1,2>> = Fun11(<<1:16,2:16>>),
287    <<1,2>> = Fun11(<<1:16,2:16,0:1>>),
288    <<1,2>> = Fun11(<<1:16,2:16,0:7>>),
289    <<1,2>> = Fun11(<<1:16,2:16,42:8>>),
290    <<1,2>> = Fun11(<<1:16,2:16,42:9>>),
291    <<1,2>> = Fun11(<<1:16,2:16,255:15>>),
292
293    Fun12 = fun(Bin, Sz1, Sz2) ->
294		    cs(<< <<E:Sz1>> || <<E:Sz2>> <= Bin >>)
295	    end,
296    <<>> = Fun12(<<>>, 1, 1),
297    Binary = list_to_binary(lists:seq(0, 255)),
298    Binary = Fun12(Binary, 1, 1),
299    Binary = Fun12(Binary, 4, 4),
300    Binary = Fun12(Binary, 8, 8),
301    <<17:9,19:9>> = Fun12(<<17:6,19:6>>, 9, 6),
302
303    Fun13 = fun(Sz) ->
304		    cs_default(<< <<C:8>> || <<C:4>> <= <<1:4,2:4,3:4,0:Sz>> >>)
305   	    end,
306    <<1,2,3>> = Fun13(0),
307    <<1,2,3,0>> = Fun13(4),
308    <<1,2,3,0>> = Fun13(5),
309    <<1,2,3,0>> = Fun13(6),
310    <<1,2,3,0>> = Fun13(7),
311    <<1,2,3,0,0>> = Fun13(8),
312
313    <<0:3>> = cs_default(<< <<0:S>> || S <- [0,1,2] >>),
314    <<0:3>> = cs_default(<< <<0:S>> || <<S>> <= <<0,1,2>> >>),
315
316    {'EXIT',_} = (catch << <<C:4>> || <<C:8>> <= {1,2,3} >>),
317
318    cs_end(),
319    ok.
320
321-define(BAD(E),   {'EXIT',{badarg,_}} = (catch << (E) || _ <- [1,2,3] >>)).
322-define(BAD_V(E), {'EXIT',{badarg,_}} = (catch << (E) || I <- [1,2,3] >>)).
323
324general_expressions(_) ->
325    <<1,2,3>> = << begin <<1,2,3>> end || _ <- [1] >>,
326    <<"abc">> = << begin <<"abc">> end || _ <- [1] >>,
327    <<1,2,3>> = << begin
328		       I = <<(I0+1)>>,
329		       id(I)
330		   end || <<I0>> <= <<0,1,2>> >>,
331    <<1,2,3>> = << I || I <- [<<1,2>>,<<3>>] >>,
332    <<1,2,3>> = << (id(<<I>>)) || I <- [1,2,3] >>,
333    <<2,4>> = << case I rem 2 of
334		     0 -> <<I>>;
335		     1 -> <<>>
336		 end || I <- [1,2,3,4,5] >>,
337    <<2,3,4,5,6,7>> = << << (id(<<J>>)) || J <- [2*I,2*I+1] >> ||
338			  I <- [1,2,3] >>,
339    <<1,2,2,3,4,4>> = << if
340			     I rem 2 =:= 0 -> <<I,I>>;
341			     true -> <<I>>
342			 end || I <- [1,2,3,4] >>,
343    self() ! <<42>>,
344    <<42>> = << receive B -> B end || _ <- [1] >>,
345    <<10,5,3>> = << try
346			<<(10 div I)>>
347		    catch _:_ ->
348			    <<>>
349		    end || I <- [0,1,2,3] >>,
350
351    %% Failing expressions.
352    ?BAD(bad_atom),
353    ?BAD(42),
354    ?BAD(42.0),
355    ?BAD_V({ok,I}),
356    ?BAD_V([I]),
357    ?BAD_V(fun() -> I end),
358
359    ok.
360
361-undef(BAD).
362
363matched_out_size(Config) when is_list(Config) ->
364    <<1, 2>> = matched_out_size_1(<<4, 1:4, 4, 2:4>>),
365    ok.
366
367matched_out_size_1(Binary) ->
368    << <<X>> || <<S, X:S>> <= Binary>>.
369
370no_generator(Config) ->
371    [<<"abc">>] = [<<(id(<<"abc">>)) || true >>],
372    {<<>>} = {<<(id(<<"abc">>)) || false >>},
373
374    %% Would crash the compiler when compiled with +no_type_opt.
375    {'EXIT',{badarg,_}} = (catch << (catch "\001") || true >>),
376
377    ok.
378
379cs_init() ->
380    erts_debug:set_internal_state(available_internal_state, true),
381    ok.
382
383cs_end() ->
384    erts_debug:set_internal_state(available_internal_state, false),
385    ok.
386
387%% Verify that the allocated size is exact (rounded up to the nearest byte).
388cs(Bin) ->
389    ByteSize = byte_size(Bin),
390    {refc_binary,ByteSize,{binary,ByteSize},_} =
391	erts_debug:get_internal_state({binary_info,Bin}),
392    Bin.
393
394%% Verify that the allocated size of the binary is the default size.
395cs_default(Bin) ->
396    ByteSize = byte_size(Bin),
397    {refc_binary,ByteSize,{binary,256},_} =
398	erts_debug:get_internal_state({binary_info,Bin}),
399    Bin.
400
401id(I) -> I.
402