Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file CCFun_vec.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380(* This file is free software, part of containers. See file "license" for more details. *)(*$inject
let _listuniq =
let g = Q.(small_list (pair small_int small_int)) in
Q.map_same_type
(fun l ->
CCList.sort_uniq ~cmp:(fun a b -> Stdlib.compare (fst a)(fst b)) l
) g
;;
*)(** {1 Hash Tries} *)type'asequence=('a->unit)->unittype'agen=unit->'aoptiontype'aprinter=Format.formatter->'a->unittype'aktree=unit->[`Nil|`Nodeof'a*'aktreelist](* TODO
(** {2 Transient IDs} *)
module Transient = struct
type state = { mutable frozen: bool }
type t = Nil | St of state
let empty = Nil
let equal a b = Stdlib.(==) a b
let create () = St {frozen=false}
let active = function Nil -> false | St st -> not st.frozen
let frozen = function Nil -> true | St st -> st.frozen
let freeze = function Nil -> () | St st -> st.frozen <- true
let with_ f =
let r = create() in
try
let x = f r in
freeze r;
x
with e ->
freeze r;
raise e
exception Frozen
end
*)(* function array *)moduleA=structtype'at='aarrayletlength_log=5letmax_length=32letmask=max_length-1let()=assert(max_length=1lsllength_log)letlength=Array.lengthletiteri=Array.iteriletiter=Array.iterletfold=Array.fold_leftletmap=Array.mapletiteri_revfa=fori=lengtha-1downto0dofia.(i)doneletcreate()=[||]letempty=[||]letis_emptya=lengtha=0letreturnx=[|x|]letgetai=ifi<0||i>=lengthatheninvalid_arg"A.get";Array.unsafe_getai(* push at the back *)letpushxa=letn=lengthainifn=max_lengththeninvalid_arg"A.push";letarr=Array.make(n+1)xinArray.blita0arr0n;arrletpopa=letn=lengthainifn=0theninvalid_arg"A.pop";Array.suba0(n-1)letappendab=letn_a=lengthainletn_b=lengthbinifn_a+n_b>max_lengththeninvalid_arg"A.append";ifn_a=0thenbelseifn_b=0thenaelse(letarr=Array.make(n_a+n_b)(a.(0))inArray.blita0arr0n_a;Array.blitb0arrn_an_b;arr)letset~mutaix=ifi<0||i>lengtha||i>=max_lengththeninvalid_arg"A.set";ifi=lengthathen((* insert in a longer copy *)letarr=Array.make(i+1)xinArray.blita0arr0i;arr)elseifmutthen((* replace element at [i] in place *)a.(i)<-x;a)else((* replace element at [i] in copy *)letarr=Array.copyainarr.(i)<-x;arr)end(** {2 Functors} *)type'at={size:int;leaves:'aA.t;subs:'atA.t;}(* invariant:
- [A.length leaves < A.max_length ==> A.is_empty subs]
- either:
* [exists n. forall i. subs[i].size = n] (all subtrees of same size)
* [exists n i.
(forall j<i. sub[j].size=32^{n+1}-1) &
(forall j>=i, sub[j].size<32^{n+1}-1)]
(prefix of subs has size of complete binary tree; suffix has
smaller size (actually decreasing))
*)letempty={size=0;leaves=A.empty;subs=A.empty}letis_empty{size;_}=size=0(*$T
is_empty empty
*)letlength{size;_}=size(*$T
not (is_empty (return 2))
length (return 2) = 1
*)letreturnx={leaves=A.returnx;subs=A.empty;size=1}typeidx_l=|I_oneofint|I_consofint*idx_l(* split an index into a low and high parts *)letlow_idx_i=ilandA.masklethigh_idx_i=ilsrA.length_logletcombine_idxij=(ilslA.length_log)lorj(* split an index into a high part, < 32, and a low part *)letsplit_idxi:idx_l=letrecauxhighlow=ifhigh=0thenlowelseifhigh<A.max_lengththenI_cons(high-1,low)elseaux(high_idx_high)(I_cons(low_idx_high,low))inaux(high_idx_i)(I_one(low_idx_i))letget_(i:int)(m:'at):'a=letrecauxlm=matchlwith|I_onex->assert(x<A.lengthm.leaves);A.getm.leavesx|I_cons(x,tl)->auxtl(A.getm.subsx)inaux(split_idxi)m(*$Q
_listuniq (fun l -> \
let m = of_list l in \
List.for_all (fun (i,y) -> get_exn i m = y) @@ List.mapi CCPair.make l)
*)letget_exniv=ifi>=0&&i<lengthvthenget_ivelseraiseNot_foundletgetiv=ifi>=0&&i<lengthvthenSome(get_iv)elseNoneletpush_(i:int)(x:'a)(m:'at):'at=letrecauxlm=matchlwith|I_onei->assert(i=A.lengthm.leaves);assert(A.lengthm.leaves<A.max_length);assert(A.is_emptym.subs);{mwithsize=m.size+1;leaves=A.pushxm.leaves}|I_cons(i,tl)->aux_replace_subtlmiandaux_replace_sublmx=assert(x<=A.lengthm.subs);(* insert in subtree, possibly a new one *)letsub_m=ifx<A.lengthm.substhenA.getm.subsxelseemptyinletsub_m=auxlsub_min{mwithsize=m.size+1;subs=A.set~mut:falsem.subsxsub_m}inaux(split_idxi)mletpushx(v:_t):_t=push_v.sizexvletpop_i(m:'at):'a*'at=letrecauxlm=matchlwith|I_onex->assert(x+1=A.lengthm.leaves);(* last one *)letx=A.getm.leavesxinx,{mwithsize=m.size-1;leaves=A.popm.leaves}|I_cons(x,tl)->aux_remove_subtlmxandaux_remove_sublmx=letsub=A.getm.subsxinlety,sub'=auxlsubinifis_emptysub'then(assert(i+1=A.lengthm.subs);(* last one *)y,{mwithsize=m.size-1;subs=A.popm.subs})else(y,{mwithsize=m.size-1;subs=A.set~mut:falsem.subsxsub})inaux(split_idxi)mletpop_exn(v:'at):'a*'at=ifv.size=0thenfailwith"Fun_vec.pop_exn";pop_(v.size-1)vletpop(v:'at):('a*'at)option=ifv.size=0thenNoneelseSome(pop_(v.size-1)v)letiteri~f(m:'at):unit=(* basically, a 32-way BFS traversal.
The queue contains subtrees to explore, along with their high_idx_ offsets *)letq:(int*'at)Queue.t=Queue.create()inQueue.push(0,m)q;whilenot(Queue.is_emptyq)dolethigh,m=Queue.popqinA.iteri(funix->f(combine_idxhighi)x)m.leaves;A.iteri(funisub->Queue.push(combine_idxihigh,sub)q)m.subs;doneletiteri_rev~f(m:'at):unit=(* like {!iteri} but last element comes first *)letrecauxhighm=A.iteri_rev(funisub->aux(combine_idxihigh)sub)m.subs;(* only now, explore current leaves *)A.iteri_rev(funix->f(combine_idxhighi)x)m.leaves;inaux0mletfoldi~f~xm=letacc=refxiniterim~f:(funix->acc:=f!accix);!accletfoldi_rev~f~xm=letacc=refxiniteri_revm~f:(funix->acc:=f!accix);!accletiter~fm=iteri~f:(fun_x->fx)mletfold~f~xm=foldi~f:(funacc_x->faccx)~xmletfold_rev~f~xm=foldi_rev~f:(funacc_x->faccx)~xmletrecmapfm:_t={subs=A.map(mapf)m.subs;leaves=A.mapfm.leaves;size=m.size;}(*$QR
Q.(pair (fun1 Observable.int bool)(small_list int)) (fun (f,l) ->
let f = Q.Fn.apply f in
(List.map f l) = (of_list l |> map f |> to_list)
)
*)letappendab=ifis_emptybthenaelsefold~f:(funvx->pushxv)~x:ab(*$QR
Q.(pair (small_list int)(small_list int)) (fun (l1,l2) ->
(l1 @ l2) = (append (of_list l1)(of_list l2) |> to_list)
)
*)letadd_listvl=List.fold_left(funvx->pushxv)vlletof_listl=add_listemptylletto_listm=fold_revm~f:(funaccx->x::acc)~x:[](*$QR
Q.(small_list int) (fun l ->
l = to_list (of_list l))
*)letadd_seqvseq=letv=refvinseq(funx->v:=pushx!v);!vletof_seqs=add_seqemptysletto_seqmyield=iteri~f:(fun_v->yieldv)m(*$Q
_listuniq (fun l -> \
(List.sort Stdlib.compare l) = \
(l |> Iter.of_list |> of_seq |> to_seq |> Iter.to_list \
|> List.sort Stdlib.compare) )
*)letrecadd_genmg=matchg()with|None->m|Somex->add_gen(pushxm)gletof_geng=add_genemptyg(* traverse the tree by increasing hash order, where the order compares
hashes lexicographically by A.length_log-wide chunks of bits,
least-significant chunks first *)letto_genm=letq_cur:'aQueue.t=Queue.create()inletq_sub:'atQueue.t=Queue.create()inQueue.pushmq_sub;letrecnext()=ifnot(Queue.is_emptyq_cur)then(Some(Queue.popq_cur))elseifnot(Queue.is_emptyq_sub)then(letm=Queue.popq_subinA.iter(funx->Queue.pushxq_cur)m.leaves;A.iter(funsub->Queue.pushsubq_sub)m.subs;next())elseNoneinnext(*$Q
_listuniq (fun l -> \
(List.sort Stdlib.compare l) = \
(l |> Gen.of_list |> of_gen |> to_gen |> Gen.to_list \
|> List.sort Stdlib.compare) )
*)letchoosem=to_genm()(*$T
choose empty = None
choose (of_list [1,1; 2,2]) <> None
*)letchoose_exnm=matchchoosemwith|None->raiseNot_found|Some(k,v)->k,vletppppvoutm=letfirst=reftrueiniterm~f:(funv->if!firstthenfirst:=falseelseFormat.fprintfout";@ ";ppvoutv)