123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116(* Fastbuf — the production buffer behind the fast catenable deque.
This module is the OCaml side of the extraction seam declared in
rocq/KTDeque/Extract/ExtractionFast.v: each function implements the
list semantics of the corresponding BufPrims.v primitive, with
- all four end operations worst-case O(1): the storage is the
CHECK-ERASED, size-fused verified §4 deque
(rocq/KTDeque/DequePtr/ErasedOps.v, extracted at
kTErasedChain.ml): the size rides in the top constructor
(no wrapper record, [size] is a field read), push/inject return
the chain bare, and the element trees carry NO runtime level
discipline — leaves are unboxed (eraw.ml), pairing is one
unchecked block, unpairing is blind field access. Each erased
op carries a success-conditional naturality lemma down to the
keystone-proven kt4 op, so the deque keystone describes this
storage on every input reachable from regular chains;
- append O(min |a| |b|): the smaller side is folded into the
larger — every §6 call site has a constant-bounded side under
the regularity invariant J (the accounting audited in
Catenable/Cost.v), so each reachable call is O(1).
Elements are stored as level-0 element trees; [base]/[unbase] are
the wrap/unwrap. The fail arms of the sized ops return their input
(a sentinel the §6 keystone proves unreachable on regular inputs). *)openKTErasedChaintype'at='aEraw.tgSChainletempty:'at=egs_emptyletsize(b:'at):int=matchbwith|GSEnding(n,_)->n|GSCons(n,_,_,_)->nletis_empty(b:'at):bool=sizeb=0(* check-erased elements (eraw.ml): a level-0 element IS the value —
zero allocation, zero runtime level checks *)letbase(x:'a):'aEraw.t=Eraw.leafxletunbase(t:'aEraw.t):'a=Eraw.unleaftletpush(x:'a)(b:'at):'at=epush_s(basex)bletinject(b:'at)(x:'a):'at=einject_sb(basex)letpop(b:'at):('a*'at)option=matchepop_sbwith|GPopOk(x,b')->Some(unbasex,b')|GPopFail->Noneleteject(b:'at):('at*'a)option=matcheeject_sbwith|GPopOk(x,b')->Some(b',unbasex)|GPopFail->Noneletb1(x:'a):'at=pushxemptyletb2(x:'a)(y:'a):'at=pushx(pushyempty)letb3(x:'a)(y:'a)(z:'a):'at=pushx(pushy(pushzempty))(* front-to-back element list by pop-drain (each pop verified); O(n),
used only by the bounded helpers and append's smaller side *)letto_list(b:'at):'alist=letrecgoaccb=matchepop_sbwith|GPopOk(x,b')->go(unbasex::acc)b'|GPopFail->List.revaccingo[]bletappend(a:'at)(b:'at):'at=ifsizea=0thenbelseifsizeb=0thenaelseifsizea<=sizebthen(* fold a's elements, back to front, onto b's front *)List.fold_right(funxacc->pushxacc)(to_lista)belse(* fold b's elements, front to back, onto a's back *)List.fold_left(funaccx->injectaccx)a(to_listb)letpop2(b:'at):(('a*'a)*'at)option=matchpopbwith|Some(x,b1)->(matchpopb1with|Some(y,b2)->Some((x,y),b2)|None->None)|None->Noneleteject2(b:'at):(('at*'a)*'a)option=matchejectbwith|Some(b1,z)->(matchejectb1with|Some(b2,y)->Some((b2,y),z)|None->None)|None->Noneleteject3(b:'at):((('at*'a)*'a)*'a)option=matchejectbwith|Some(b1,c)->(matchejectb1with|Some(b2,bb)->(matchejectb2with|Some(b3,a)->Some(((b3,a),bb),c)|None->None)|None->None)|None->None(* Coq argument order: bfold_right f z b / bfold_left f b z. *)letfold_right(f:'x->'z->'z)(z:'z)(b:'xt):'z=List.fold_rightf(to_listb)zletfold_left(f:'z->'x->'z)(b:'xt)(z:'z):'z=List.fold_leftfz(to_listb)