1: %%
    2: %% %CopyrightBegin%
    3: %%
    4: %% Copyright Ericsson AB 2000-2011. All Rights Reserved.
    5: %%
    6: %% The contents of this file are subject to the Erlang Public License,
    7: %% Version 1.1, (the "License"); you may not use this file except in
    8: %% compliance with the License. You should have received a copy of the
    9: %% Erlang Public License along with this software. If not, it can be
   10: %% retrieved online at http://www.erlang.org/.
   11: %%
   12: %% Software distributed under the License is distributed on an "AS IS"
   13: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
   14: %% the License for the specific language governing rights and limitations
   15: %% under the License.
   16: %%
   17: %% %CopyrightEnd%
   18: %%
   19: 
   20: -module(bs_match_int_SUITE).
   21: 
   22: -export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2,
   23: 	 init_per_testcase/2,end_per_testcase/2,
   24: 	 init_per_suite/1,end_per_suite/1,
   25: 	 integer/1,signed_integer/1,dynamic/1,more_dynamic/1,mml/1,
   26: 	 match_huge_int/1,bignum/1,unaligned_32_bit/1]).
   27: 
   28: -include_lib("test_server/include/test_server.hrl").
   29: 
   30: -import(lists, [seq/2]).
   31: 
   32: suite() -> [{ct_hooks,[ts_install_cth]}].
   33: 
   34: all() -> 
   35:     [integer, signed_integer, dynamic, more_dynamic, mml,
   36:      match_huge_int, bignum, unaligned_32_bit].
   37: 
   38: groups() -> 
   39:     [].
   40: 
   41: init_per_group(_GroupName, Config) ->
   42:     Config.
   43: 
   44: end_per_group(_GroupName, Config) ->
   45:     Config.
   46: 
   47: init_per_testcase(_Case, Config) ->
   48:     test_lib:interpret(?MODULE),
   49:     Dog = test_server:timetrap(?t:minutes(4)),
   50:     [{watchdog,Dog}|Config].
   51: 
   52: end_per_testcase(_Case, Config) ->
   53:     Dog = ?config(watchdog, Config),
   54:     ?t:timetrap_cancel(Dog),
   55:     ok.
   56: 
   57: init_per_suite(Config) when is_list(Config) ->
   58:     ?line test_lib:interpret(?MODULE),
   59:     ?line true = lists:member(?MODULE, int:interpreted()),
   60:     Config.
   61: 
   62: end_per_suite(Config) when is_list(Config) ->
   63:     ok.
   64: 
   65: integer(Config) when is_list(Config) ->
   66:     ?line 0 = get_int(mkbin([])),
   67:     ?line 0 = get_int(mkbin([0])),
   68:     ?line 42 = get_int(mkbin([42])),
   69:     ?line 255 = get_int(mkbin([255])),
   70:     ?line 256 = get_int(mkbin([1,0])),
   71:     ?line 257 = get_int(mkbin([1,1])),
   72:     ?line 258 = get_int(mkbin([1,2])),
   73:     ?line 258 = get_int(mkbin([1,2])),
   74:     ?line 65534 = get_int(mkbin([255,254])),
   75:     ?line 16776455 = get_int(mkbin([255,253,7])),
   76:     ?line 4245492555 = get_int(mkbin([253,13,19,75])),
   77:     ?line 4294967294 = get_int(mkbin([255,255,255,254])),
   78:     ?line 4294967295 = get_int(mkbin([255,255,255,255])),
   79:     ?line Eight = [200,1,19,128,222,42,97,111],
   80:     ?line cmp128(Eight, uint(Eight)),
   81:     ?line fun_clause(catch get_int(mkbin(seq(1,5)))),
   82:     ok.
   83: 
   84: get_int(Bin) ->
   85:     I = get_int1(Bin),
   86:     get_int(Bin, I).
   87: 
   88: get_int(Bin0, I) when size(Bin0) < 4 ->
   89:     Bin = <<0,Bin0/binary>>,
   90:     I = get_int1(Bin),
   91:     get_int(Bin, I);
   92: get_int(_, I) -> I.
   93: 
   94: get_int1(<<I:0>>) -> I;
   95: get_int1(<<I:8>>) -> I;
   96: get_int1(<<I:16>>) -> I;
   97: get_int1(<<I:24>>) -> I;
   98: get_int1(<<I:32>>) -> I.
   99: 
  100: cmp128(<<I:128>>, I) -> equal;
  101: cmp128(_, _) -> not_equal.
  102: 
  103: signed_integer(Config) when is_list(Config) ->
  104:     ?line {no_match,_} = sint(mkbin([])),
  105:     ?line {no_match,_} = sint(mkbin([1,2,3])),
  106:     ?line 127 = sint(mkbin([127])),
  107:     ?line -1 = sint(mkbin([255])),
  108:     ?line -128 = sint(mkbin([128])),
  109:     ?line 42 = sint(mkbin([42,255])),
  110:     ?line 127 = sint(mkbin([127,255])).
  111: 
  112: sint(Bin) ->
  113:     case Bin of
  114: 	<<I:8/signed>> -> I;
  115: 	<<I:8/signed,_:3,_:5>> -> I;
  116: 	Other -> {no_match,Other}
  117:     end.
  118: 
  119: uint(L) -> uint(L, 0).
  120: uint([H|T], Acc) -> uint(T, Acc bsl 8 bor H);
  121: uint([], Acc) -> Acc.
  122: 
  123: dynamic(Config) when is_list(Config) ->
  124:     dynamic(mkbin([255]), 8),
  125:     dynamic(mkbin([255,255]), 16),
  126:     dynamic(mkbin([255,255,255]), 24),
  127:     dynamic(mkbin([255,255,255,255]), 32),
  128:     ok.
  129: 
  130: dynamic(Bin, S1) when S1 >= 0 ->
  131:     S2 = size(Bin) * 8 - S1,
  132:     dynamic(Bin, S1, S2, (1 bsl S1) - 1, (1 bsl S2) - 1),
  133:     dynamic(Bin, S1-1);
  134: dynamic(_, _) -> ok.
  135: 
  136: dynamic(Bin, S1, S2, A, B) ->
  137: %    io:format("~p ~p ~p ~p\n", [S1,S2,A,B]),
  138:     case Bin of
  139: 	<<A:S1,B:S2>> ->
  140: 	    io:format("~p ~p ~p ~p\n", [S1,S2,A,B]),
  141: 	    ok;
  142: 	_Other -> erlang:error(badmatch, [Bin,S1,S2,A,B])
  143:     end.
  144: 
  145: more_dynamic(doc) -> "Extract integers at different alignments and of different sizes.";
  146: more_dynamic(Config) when is_list(Config) ->
  147: 
  148:     % Unsigned big-endian numbers.
  149:     Unsigned  = fun(Bin, List, SkipBef, N) ->
  150: 			SkipAft = 8*size(Bin) - N - SkipBef,
  151: 			<<_:SkipBef,Int:N,_:SkipAft>> = Bin,
  152: 			Int = make_int(List, N, 0)
  153: 		end,
  154:     ?line more_dynamic1(Unsigned, funny_binary(42)),
  155: 
  156:     %% Signed big-endian numbers.
  157:     Signed  = fun(Bin, List, SkipBef, N) ->
  158: 		      SkipAft = 8*size(Bin) - N - SkipBef,
  159: 		      <<_:SkipBef,Int:N/signed,_:SkipAft>> = Bin,
  160: 		      case make_signed_int(List, N) of
  161: 			  Int -> ok;
  162: 			  Other ->
  163: 			      io:format("Bin = ~p,", [Bin]),
  164: 			      io:format("SkipBef = ~p, N = ~p", [SkipBef,N]),
  165: 			      io:format("Expected ~p, got ~p", [Int,Other]),
  166: 			      ?t:fail()
  167: 		      end
  168: 	      end,
  169:     ?line more_dynamic1(Signed, funny_binary(43)),
  170: 
  171:     %% Unsigned little-endian numbers.
  172:     UnsLittle  = fun(Bin, List, SkipBef, N) ->
  173: 			 SkipAft = 8*size(Bin) - N - SkipBef,
  174: 			 <<_:SkipBef,Int:N/little,_:SkipAft>> = Bin,
  175: 			 Int = make_int(big_to_little(List, N), N, 0)
  176: 		 end,
  177:     ?line more_dynamic1(UnsLittle, funny_binary(44)),
  178: 
  179:     %% Signed little-endian numbers.
  180:     SignLittle  = fun(Bin, List, SkipBef, N) ->
  181: 			  SkipAft = 8*size(Bin) - N - SkipBef,
  182: 			  <<_:SkipBef,Int:N/signed-little,_:SkipAft>> = Bin,
  183: 			  Little = big_to_little(List, N),
  184: 			  Int = make_signed_int(Little, N)
  185: 		  end,
  186:     ?line more_dynamic1(SignLittle, funny_binary(45)),
  187: 
  188:     ok.
  189: 
  190: more_dynamic1(Action, Bin) ->
  191:     BitList = bits_to_list(binary_to_list(Bin), 16#80),
  192:     more_dynamic2(Action, Bin, BitList, 0).
  193: 
  194: more_dynamic2(Action, Bin, [_|T]=List, Bef) ->
  195:     more_dynamic3(Action, Bin, List, Bef, size(Bin)*8),
  196:     more_dynamic2(Action, Bin, T, Bef+1);
  197: more_dynamic2(_, _, [], _) -> ok.
  198: 
  199: more_dynamic3(Action, Bin, List, Bef, Aft) when Bef =< Aft ->
  200: %%    io:format("~p, ~p", [Bef,Aft-Bef]),
  201:     Action(Bin, List, Bef, Aft-Bef),
  202:     more_dynamic3(Action, Bin, List, Bef, Aft-1);
  203: more_dynamic3(_, _, _, _, _) -> ok.
  204: 
  205: big_to_little(List, N) -> big_to_little(List, N, []).
  206: 
  207: big_to_little([B0,B1,B2,B3,B4,B5,B6,B7|T], N, Acc) when N >= 8 ->
  208:     big_to_little(T, N-8, [B0,B1,B2,B3,B4,B5,B6,B7|Acc]);
  209: big_to_little(List, N, Acc) -> lists:sublist(List, 1, N) ++ Acc.
  210: 
  211: make_signed_int(_List, 0) -> 0;
  212: make_signed_int([0|_]=List, N) -> make_int(List, N, 0);
  213: make_signed_int([1|_]=List0, N) ->
  214:     List1 = reversed_sublist(List0, N, []),
  215:     List2 = two_complement_and_reverse(List1, 1, []),
  216:     -make_int(List2, length(List2), 0).
  217: 
  218: reversed_sublist(_List, 0, Acc) -> Acc;
  219: reversed_sublist([H|T], N, Acc) -> reversed_sublist(T, N-1, [H|Acc]).
  220: 
  221: two_complement_and_reverse([H|T], Carry, Acc) ->
  222:     Sum = 1-H+Carry,
  223:     two_complement_and_reverse(T, Sum div 2, [Sum rem 2|Acc]);
  224: two_complement_and_reverse([], Carry, Acc) -> [Carry|Acc].
  225: 
  226: make_int(_List, 0, Acc) -> Acc;
  227: make_int([H|T], N, Acc) -> make_int(T, N-1, Acc bsl 1 bor H).
  228: 
  229: bits_to_list([_|T], 0) -> bits_to_list(T, 16#80);
  230: bits_to_list([H|_]=List, Mask) ->
  231:     [case H band Mask of
  232: 	 0 -> 0;
  233: 	 _ -> 1
  234:      end|bits_to_list(List, Mask bsr 1)];
  235: bits_to_list([], _) -> [].
  236: 
  237: fun_clause({'EXIT',{function_clause,_}}) -> ok.
  238: mkbin(L) when is_list(L) -> list_to_binary(L).
  239: 
  240: funny_binary(N) ->
  241:     B0 = erlang:md5([N]),
  242:     {B1,_B2} = split_binary(B0, byte_size(B0) div 3),
  243:     B1.
  244: 
  245: mml(Config) when is_list(Config) ->
  246:     ?line single_byte_binary = mml_choose(<<42>>),
  247:     ?line multi_byte_binary = mml_choose(<<42,43>>).
  248: 
  249: mml_choose(<<_A:8>>) -> single_byte_binary;
  250: mml_choose(<<_A:8,_T/binary>>) -> multi_byte_binary.
  251: 
  252: match_huge_int(Config) when is_list(Config) ->
  253:     Sz = 1 bsl 27,
  254:     ?line Bin = <<0:Sz,13:8>>,
  255:     ?line skip_huge_int_1(Sz, Bin),
  256:     ?line 0 = match_huge_int_1(Sz, Bin),
  257: 
  258:     %% Test overflowing the size of an integer field.
  259:     ?line nomatch = overflow_huge_int_skip_32(Bin),
  260:     case erlang:system_info(wordsize) of
  261: 	4 ->
  262: 	    ?line nomatch = overflow_huge_int_32(Bin);
  263: 	8 ->
  264: 	    %% An attempt will be made to allocate heap space for
  265: 	    %% the bignum (which will probably fail); only if the
  266: 	    %% allocation succeds will the matching fail because
  267: 	    %% the binary is too small.
  268: 	    ok
  269:     end,
  270:     ?line nomatch = overflow_huge_int_skip_64(Bin),
  271:     ?line nomatch = overflow_huge_int_64(Bin),
  272: 
  273:     %% Test overflowing the size of an integer field using variables as sizes.
  274:     ?line Sizes = case erlang:system_info(wordsize) of
  275: 		      4 -> lists:seq(25, 32);
  276: 		      8 -> []
  277: 		  end ++ lists:seq(50, 64),
  278:     ?line ok = overflow_huge_int_unit128(Bin, Sizes),
  279: 
  280:     ok.
  281: 
  282: overflow_huge_int_unit128(Bin, [Sz0|Sizes]) ->
  283:     Sz = id(1 bsl Sz0),
  284:     case Bin of
  285: 	<<_:Sz/unit:128,0,_/binary>> ->
  286: 	    {error,Sz};
  287: 	_ ->
  288: 	    case Bin of
  289: 		<<Var:Sz/unit:128,0,_/binary>> ->
  290: 		    {error,Sz,Var};
  291: 		_ ->
  292: 		    overflow_huge_int_unit128(Bin, Sizes)
  293: 	    end
  294:     end;
  295: overflow_huge_int_unit128(_, []) -> ok.
  296: 
  297: match_huge_int_1(I, Bin) ->
  298:     <<Int:I,13>> = Bin,
  299:     Int.
  300: 
  301: skip_huge_int_1(I, Bin) ->
  302:     <<_:I,13>> = Bin.
  303: 
  304: overflow_huge_int_skip_32(<<_:4294967296,0,_/binary>>) -> 1; % 1 bsl 32
  305: overflow_huge_int_skip_32(<<_:33554432/unit:128,0,_/binary>>) -> 2; % 1 bsl 25
  306: overflow_huge_int_skip_32(<<_:67108864/unit:64,0,_/binary>>) -> 3; % 1 bsl 26
  307: overflow_huge_int_skip_32(<<_:134217728/unit:32,0,_/binary>>) -> 4; % 1 bsl 27
  308: overflow_huge_int_skip_32(<<_:268435456/unit:16,0,_/binary>>) -> 5; % 1 bsl 28
  309: overflow_huge_int_skip_32(<<_:536870912/unit:8,0,_/binary>>) -> 6; % 1 bsl 29
  310: overflow_huge_int_skip_32(<<_:1073741824/unit:8,0,_/binary>>) -> 7; % 1 bsl 30
  311: overflow_huge_int_skip_32(<<_:2147483648/unit:8,0,_/binary>>) -> 8; % 1 bsl 31
  312: overflow_huge_int_skip_32(_) -> nomatch.
  313: 
  314: overflow_huge_int_32(<<Int:4294967296,_/binary>>) -> {1,Int}; % 1 bsl 32
  315: overflow_huge_int_32(<<Int:33554432/unit:128,0,_/binary>>) -> {2,Int}; % 1 bsl 25
  316: overflow_huge_int_32(<<Int:67108864/unit:128,0,_/binary>>) -> {3,Int}; % 1 bsl 26
  317: overflow_huge_int_32(<<Int:134217728/unit:128,0,_/binary>>) -> {4,Int}; % 1 bsl 27
  318: overflow_huge_int_32(<<Int:268435456/unit:128,0,_/binary>>) -> {5,Int}; % 1 bsl 28
  319: overflow_huge_int_32(<<Int:536870912/unit:128,0,_/binary>>) -> {6,Int}; % 1 bsl 29
  320: overflow_huge_int_32(<<Int:1073741824/unit:128,0,_/binary>>) -> {7,Int}; % 1 bsl 30
  321: overflow_huge_int_32(<<Int:2147483648/unit:128,0,_/binary>>) -> {8,Int}; % 1 bsl 31
  322: overflow_huge_int_32(_) -> nomatch.
  323: 
  324: overflow_huge_int_skip_64(<<_:18446744073709551616,_/binary>>) -> 1; % 1 bsl 64
  325: overflow_huge_int_skip_64(<<_:144115188075855872/unit:128,0,_/binary>>) -> 2; % 1 bsl 57
  326: overflow_huge_int_skip_64(<<_:288230376151711744/unit:64,0,_/binary>>) -> 3; % 1 bsl 58
  327: overflow_huge_int_skip_64(<<_:576460752303423488/unit:32,0,_/binary>>) -> 4; % 1 bsl 59
  328: overflow_huge_int_skip_64(<<_:1152921504606846976/unit:16,0,_/binary>>) -> 5; % 1 bsl 60
  329: overflow_huge_int_skip_64(<<_:2305843009213693952/unit:8,0,_/binary>>) -> 6; % 1 bsl 61
  330: overflow_huge_int_skip_64(<<_:4611686018427387904/unit:8,0,_/binary>>) -> 7; % 1 bsl 62
  331: overflow_huge_int_skip_64(<<_:9223372036854775808/unit:8,0,_/binary>>) -> 8; % 1 bsl 63
  332: overflow_huge_int_skip_64(_) -> nomatch.
  333: 
  334: overflow_huge_int_64(<<Int:18446744073709551616,_/binary>>) -> {1,Int}; % 1 bsl 64
  335: overflow_huge_int_64(<<Int:144115188075855872/unit:128,0,_/binary>>) -> {2,Int}; % 1 bsl 57
  336: overflow_huge_int_64(<<Int:288230376151711744/unit:128,0,_/binary>>) -> {3,Int}; % 1 bsl 58
  337: overflow_huge_int_64(<<Int:576460752303423488/unit:128,0,_/binary>>) -> {4,Int}; % 1 bsl 59
  338: overflow_huge_int_64(<<Int:1152921504606846976/unit:128,0,_/binary>>) -> {5,Int}; % 1 bsl 60
  339: overflow_huge_int_64(<<Int:2305843009213693952/unit:128,0,_/binary>>) -> {6,Int}; % 1 bsl 61
  340: overflow_huge_int_64(<<Int:4611686018427387904/unit:128,0,_/binary>>) -> {7,Int}; % 1 bsl 62
  341: overflow_huge_int_64(<<Int:9223372036854775808/unit:128,0,_/binary>>) -> {8,Int}; % 1 bsl 63
  342: overflow_huge_int_64(_) -> nomatch.
  343: 
  344: bignum(Config) when is_list(Config) ->
  345:     ?line Bin = id(<<42,0:1024/unit:8,43>>),
  346:     ?line <<42:1025/little-integer-unit:8,_:8>> = Bin,
  347:     ?line <<_:8,43:1025/integer-unit:8>> = Bin,
  348: 
  349:     ?line BignumBin = id(<<0:512/unit:8,258254417031933722623:9/unit:8>>),
  350:     ?line <<258254417031933722623:(512+9)/unit:8>> = BignumBin,
  351:     erlang:garbage_collect(),			%Search for holes in debug-build.
  352:     ok.
  353: 
  354: unaligned_32_bit(Config) when is_list(Config) ->
  355:     %% There used to be a risk for heap overflow (fixed in R11B-5).
  356:     ?line L = unaligned_32_bit_1(<<-1:(64*1024)>>),
  357:     ?line unaligned_32_bit_verify(L, 1638).
  358: 
  359: unaligned_32_bit_1(<<1:1,U:32,_:7,T/binary>>) ->
  360:     [U|unaligned_32_bit_1(T)];
  361: unaligned_32_bit_1(_) ->
  362:     [].
  363: 
  364: unaligned_32_bit_verify([], 0) -> ok;
  365: unaligned_32_bit_verify([4294967295|T], N) when N > 0 ->
  366:     unaligned_32_bit_verify(T, N-1).
  367: 
  368: id(I) -> I.