%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Copyright (c) 2004 by Erik Stenman.  
%% -*- erlang-indent-level: 2 -*-
%% ====================================================================
%%  Filename : 	c.erl
%%  Module   :	c
%%  Purpose  :  
%%  Notes    : 
%%  History  :	* 2004-09-21 Erik Stenman (stenman@csd.uu.se): 
%%               Created.
%%  CVS      :
%%              $Author: $
%%              $Date: $
%%              $Revision: $
%% ====================================================================
%%  Exports  :
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

-module(tc).
-export([checksum_1/2,t/0,c/3,checksum_2/2,checksum_3/2]).
-compile(inline).

t() ->
    {ok,B} = file:read_file("tc.erl"),
    C = <<B/binary,B/binary,B/binary,B/binary,B/binary>>,
    D = <<C/binary,C/binary,C/binary,C/binary,C/binary>>,
    E = <<D/binary,D/binary,D/binary,D/binary,D/binary,
	 D/binary,D/binary,D/binary,D/binary,D/binary,
	 D/binary,D/binary,D/binary,D/binary,D/binary,
	 D/binary,D/binary,D/binary,D/binary,D/binary,
	 D/binary,D/binary,42:8/integer>>,
    F = <<E/binary,E/binary,E/binary,E/binary,E/binary>>,
    garbage_collect(),
    io:format("M1: ~w~n",[timer:tc(tc,checksum_1,[F,0])]),
    garbage_collect(),
    io:format("M2: ~w~n",[timer:tc(tc,checksum_2,[F,0])]),
    garbage_collect(),
    io:format("M3: ~w~n",[timer:tc(tc,checksum_3,[F,0])]),
    garbage_collect(),
    io:format("M4: ~w~n",[timer:tc(tc,c,[0,F,0])]).

 
checksum_1(<<Num:16/integer, Remainder/binary>>, Csum) ->
    checksum_1(Remainder, Csum + Num);
checksum_1(<<Num:8/integer>>,CSum) -> 
    checksum_1(<<>>,CSum+(Num bsl 8));
checksum_1(_, Csum) when Csum > 16#ffff ->
    checksum_1(<<>>,Csum band 16#ffff + (Csum bsr 16));
checksum_1(_,CSum) -> CSum.

checksum_2(Bin = <<N1:16/integer, N2:16/integer, N3:16/integer, 
	N4:16/integer, N5:16/integer, N6:16/integer, 
	N7:16/integer, N8:16/integer, Rem/binary>>, 
	Csum) when size(Bin)>=16 ->
    checksum_2(Rem, Csum+N1+N2+N3+N4+N5+N6+N7+N8);
checksum_2(Bin,Csum) ->
    checksum_1(Bin,Csum).

checksum_3(Bin = <<N1:16/integer, N2:16/integer, N3:16/integer, 
	N4:16/integer, N5:16/integer, N6:16/integer, 
	N7:16/integer, N8:16/integer, Rem/binary>>, 
	Csum) when size(Bin)>=16 ->
    checksum_3(Rem, '+'(Csum,'+'(N1,'+'(N2,'+'(N3,'+'(N4,'+'(N5,'+'(N6,'+'(N7,N8)))))))));
checksum_3(Bin,Csum) ->
    c(0,Bin,Csum).


c(N,Bin,Csum) ->
    case Bin of 
	<<_:N/binary, Num:16/integer,_/binary>> ->
	    c(N+2,Bin,'+'(Csum,Num));
        <<_:N/binary, Num:8/integer>> ->
	    '+'(Csum,Num bsl 8);
	_ -> Csum
    end.

'+'(A,B) ->
    S = A + B,
    S band 16#ffff + (S bsr 16).
