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