123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388(*
* Bitset - Efficient bit sets
* Copyright (C) 2003 Nicolas Cannasse
* Copyright (C) 2009 David Teller, LIFO, Universite d'Orleans
* Copyright (C) 2012 Sylvain Le Gall
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version,
* with the special exception on linking described in file LICENSE.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*)typet=Bytes.trefletprint_array=letbuf=Buffer.create 8inletprint_bcharc=letrc=refcinBuffer.clearbuf;for_i=1to8doBuffer.add_charbuf(if!rcland 1==1then'1'else '0');rc:=!rclsr1done;Buffer.contentsbufinArray.init256print_bcharletprintoutt=let buf=!tinfori=0to(Bytes.lengthbuf)-1doBatInnerIO.nwriteout(Array.unsafe_get print_array(Char.code(Bytes.unsafe_getbufi)))doneletcapacity t=(Bytes.length!t)*8letempty()=ref(Bytes.create0)letcreate_sfuncn=(* n is in bits *)ifn<0theninvalid_arg("BitSet."^sfun^": negative size");letsize=n/8+(ifnmod8=0then0else1)inref(Bytes.makesizec)letcreate=create_ "create"'\000'letcopyt=ref(Bytes.copy!t)letextendtn=(*len in bits *)ifn>capacitytthenlett'=createninBytes.blit!t0!t'0(Bytes.length!t);t:=!t'typebit_op=|Set|Unset|Toggleletrecapply_bit_op sfunoptx=letpos=x/8inifpos<0theninvalid_arg("BitSet."^sfun^": negative index")elseifpos<Bytes.length!tthenletdelta=xmod8inletc=Char.code(Bytes.unsafe_get!tpos)inletmask=1lsl deltainlet v=(clandmask)<>0inletbsetc=Bytes.unsafe_set!tpos(Char.unsafe_chrc)inmatchopwith|Set->ifnotvthenbset(clormask)|Unset->ifvthenbset(clxormask)(* TODO: shrink *)|Toggle->bset(clxormask);elsematchopwith|Set|Toggle->extendt(x+1);apply_bit_opsfunoptx|Unset->()letsettx=apply_bit_op"set"Settxletunsettx=apply_bit_op"unset"Unsettxlettoggletx=apply_bit_op"toggle"Toggletxletmemtx=letpos=x/8inifpos<0theninvalid_arg"BitSet.mem: negative index"elseifpos<Bytes.length!tthenletdelta=xmod8inletc=Char.code(Bytes.unsafe_get!tpos)in(cland(1lsldelta))<>0elsefalseletaddxt=letdup=copytinsetdupx;dupletremovext=letdup=copytinunsetdupx;dup(*$T
let b =empty() in ignore(add 1 b); count b = 0
let b = empty() in count(add 1 b) = 1
let b = create_full 5 in ignore(remove 1 b); count b = 5
let b = create_full 5 in count(remove 1 b) = 4
*)letputt=function|true->sett|false->unsettletcreate_fulln=lett=create_"create_full"'\255'nin(* Fix the tail *)fori=nto(capacityt)-1dounsettidone;t(*$Q
Q.small_int (fun n -> count (create_full n) = n)
*)letcomparet1t2=letlen1=Bytes.length !t1inletlen2=Bytes.length!t2iniflen1=len2thenBytes.compare!t1!t2elseletdiff=ref0inletidx=ref0inletclen=min len1len2inwhile!diff=0&&!idx<clendodiff :=Char.compare(Bytes.unsafe_get !t1!idx)(Bytes.unsafe_get!t2!idx);incridxdone;iflen1 <len2thenwhile!diff=0&&!idx<len2dodiff:=Char.compare'\000'(Bytes.unsafe_get !t2!idx);incridxdoneelsewhile!diff=0&&!idx<len1dodiff:=Char.compare(Bytes.unsafe_get!t1!idx)'\000';incridxdone;!diff(*$T
compare (of_list [1;2]) (of_list [1]) > 0
*)letequalt1t2=comparet1t2=0letord=BatOrd.ordcompare(*$Q
(Q.pair (Q.list Q.small_int) (Q.list Q.small_int)) (fun (l1,l2) -> \
let of_list' l = of_list (List.map abs l) in \
let b1 = of_list' l1 and b2 = of_list' l2 in \
ord b1 b2 = BatOrd.rev_ord0 (ord b2 b1))
*)(* Array that return the count of bits for a char *)letcount_array=letreccount_bitsi=ifi=0then0else(count_bits(i/2))+(imod2)inArray.init256count_bitsletcountt=letc=ref0infori=0to(Bytes.length!t)-1doc:=!c+Array.unsafe_getcount_array(Char.code(Bytes.unsafe_get!ti))done;!c(*Array of array that given a char and a delta return the delta of the next
* set bit.
*)letnext_set_bit_array=leteighth_bit=1lsl7inletmkc=letarr=Array.make8~-1inletrecmk' last_set_bitiv=ifi>=0thenletlast_set_bit=ifvlandeighth_bit<>0thenielselast_set_bitinarr.(i)<-last_set_bit;mk'last_set_bit(i-1)(vlsl1)inmk'~-17c;arrinArray.init256mk(* DEBUG bit arrays.
let () =
Array.iteri
(fun idx arr ->
let buf = Buffer.create 8 in
for i = 0 to 7 do
let c =
if (idx land (1 lsl (7 - i))) = 0 then
'0'
else
'1'
in
Buffer.add_char buf c
done;
Buffer.add_string buf ": ";
for i = 0 to 7 do
Buffer.add_string buf
(Printf.sprintf "%d -> %d; "
i arr.(i))
done;
Buffer.add_char buf '\n';
Buffer.output_buffer stderr buf)
next_set_bit_array;
flush stderr
*)(* Find the first set bit in the bit array *)letrecnext_set_bittx=ifx<0theninvalid_arg"BitSet.next_set_bit"elseletpos=x/8inifpos<Bytes.length!tthenbeginletdelta=xmod8inlet c=Char.code(Bytes.unsafe_get!tpos)inletdelta_next=Array.unsafe_get(Array.unsafe_get next_set_bit_arrayc)deltainifdelta_next<0thennext_set_bit t((pos+1)*8)elseSome(pos*8+delta_next)endelsebeginNoneendletenumt=letrecmakencnt=letcur=refninletcnt=refcntinletnext()=matchnext_set_bitt!curwithSomeelem->decrcnt;cur:=(elem+1);elem|None->raiseBatEnum.No_more_elementsinBatEnum.make~next~count:(fun()-> !cnt)~clone:(fun()->make!cur!cnt)inmake0(count t)(*$T
BitSet.of_list [5;3;2;1] |> BitSet.enum |> Enum.skip 1 |> Enum.count = 3
let e = BitSet.of_list [5;3;2;1] |> enum in \
Enum.junk e; Enum.iter (fun _ -> ()) (Enum.clone e); (Enum.count e = 3)
*)(*$Q
(Q.list Q.small_int) (fun l -> \
let b = BitSet.of_list (List.map abs l) in \
b |> BitSet.enum |> BitSet.of_enum |> equal b)
*)letof_enum?(cap=128)e=letbs=createcapinBatEnum.iter(setbs)e;bsletof_list ?(cap=128)lst=letbs =create capinList.iter (setbs)lst;bstypeset_op=|Inter|Diff|Unite|DiffSymletapply_set_opopt1 t2=letidx=ref 0inletlen1=Bytes.length!t1inletlen2=Bytes.length!t2inletclen=minlen1len2inlet apply_op=match opwith|Inter->(func1c2->c1landc2)|Diff ->(func1c2->c1land(lnotc2))|Unite->(func1c2->c1lorc2)|DiffSym->(func1c2->c1lxorc2)in(* this operates on the common substring only *)while!idx<clendoletc1=Char.code(Bytes.unsafe_get!t1!idx)inletc2=Char.code(Bytes.unsafe_get!t2!idx)inletcr=apply_opc1c2inBytes.unsafe_set!t1!idx(Char.unsafe_chrcr);incridxdone;(* handles the non-shared suffixes as well *)beginmatchopwith|Inter->(* clear the non-shared suffix of t1 *)iflen1>len2thenbeginBytes.fill!t1len2(len1-len2)(Char.chr0)end|Diff ->(* keep the non-shared suffix of t1, that is, do nothing *)()|Unite->(* copy the non-shared suffix of t2 *)iflen1<len2thenbeginextend t1(len2*8);Bytes.blit!t2len1!t1len1(len2-len1)end|DiffSym->(* copy the non-shared suffix of t2 *)iflen1<len2thenbeginlettmp=Bytes.copy!t2inBytes.blit !t10tmp0len1;t1:=tmpendendlet intersect t1t2=apply_set_opIntert1 t2letdifferentiatet1t2=apply_set_opDifft1t2letunitet1t2=apply_set_opUnitet1 t2letdifferentiate_symt1t2=apply_set_opDiffSymt1t2letbiop_with_copyfab=leta'=copyainfa'b;a'letinterab=biop_with_copyintersectabletunionab=biop_with_copyuniteabletdiffab=biop_with_copydifferentiateabletsym_diffab=biop_with_copydifferentiate_symab