123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773(******************************************************************************)(* *)(* Sek *)(* *)(* Arthur Charguéraud, Émilie Guermeur and François Pottier *)(* *)(* Copyright Inria. All rights reserved. This file is distributed under the *)(* terms of the GNU Lesser General Public License as published by the Free *)(* Software Foundation, either version 3 of the License, or (at your *)(* option) any later version, as described in the file LICENSE. *)(* *)(******************************************************************************)openPrivateSignaturesincludePublicSignatureincludePublicSettings(* -------------------------------------------------------------------------- *)(* -------------------------------------------------------------------------- *)(* Default settings. *)moduleDefaultSettings=structlet[@inline]capacitydepth=ifdepth=0then128else16letoverwrite_empty_slots=trueletthreshold=64(* The space usage of a sequence of length [threshold+1] exceeds [2 *
capacity 0]. Thus, to maintain the space usage below [4 * n] in all
cases, it is important to pick [threshold <= (capacity 0) / 2]. *)letcheck_iterator_validity=trueend(* -------------------------------------------------------------------------- *)(* -------------------------------------------------------------------------- *)(* This functor puts everything together. In short, it applies the functors
[ShareableSequence.Make] and [EphemeralSequence.Make] to obtain shareable
sequences and ephemeral sequences, defines conversions between them, and
adds a number of convenience functions. *)(* We do not check that the [capacity] function provided by the user abides by
our requirements: that is, [capacity depth] should be at least 2, and
[capacity] must behave as a mathematical function. Checking these
properties at runtime might defeat compiler optimizations. *)module[@inline]Make(Settings:sigincludeCAPACITYincludeOVERWRITE_EMPTY_SLOTSincludeTHRESHOLDincludeCHECK_ITERATOR_VALIDITYend):SEK=struct(* -------------------------------------------------------------------------- *)(* -------------------------------------------------------------------------- *)(* Export the types [side] and [direction] and the exceptions [Empty]
and [End]. *)typenonrecside=sideletfront=frontletback=backletother=othertypenonrecdirection=directionletforward=forwardletbackward=backwardletsign=signletopposite=oppositeexceptionEmpty=EmptyexceptionEnd=End(* -------------------------------------------------------------------------- *)(* -------------------------------------------------------------------------- *)(* Instantiate the functors that define the data structures. *)(* This is ML-module-mania: a big puzzle game. *)(* -------------------------------------------------------------------------- *)(* Ephemeral chunks. *)moduleEChunk=EphemeralChunk.Make(Settings)(* -------------------------------------------------------------------------- *)(* Shareable chunks. *)moduleSChunk=ShareableChunk.Make(EChunk)(* -------------------------------------------------------------------------- *)(* Shareable sequences. *)moduleSSeq=ShareableSequence.Make(SChunk)(Settings)(* -------------------------------------------------------------------------- *)(* Extra functionality of shareable sequences, required in order to apply
the functor [Iterator.Make]. *)moduleSSeqHooks=structtype'at='aSSeq.tletweight=SSeq.weightletdummy=SSeq.dummyopenSSeq(* Accessors. *)(* These accessors assume that an iterator on an empty shareable sequence is
never created. This works because shareable sequences are used in two
ways: 1- as the middle sequence in an ephemeral sequence (and we never
create an iterator on an empty middle sequence); 2- as a persistent
sequence (and we use TrivialIterator to implement iterators on short
sequences). *)letfronts=matchswith|Level{front;_}->front|Zero_|One_|Short_->assertfalseletmiddles=matchswith|Level{middle;_}->middle|Zero_|One_|Short_->assertfalseletbacks=matchswith|Level{back;_}->back|Zero_|One_|Short_->assertfalselet[@inline]weight_fronts=SChunk.weight(fronts)(* A persistent sequence cannot be modified, therefore the hooks that
support the modification operations are nonfunctional. *)letschunk_uniquely_owned_s_p=falseletensure_schunk_uniquely_owned_s_i_p=assertfalse(* An iterator on a persistent sequence is always valid and does not
need a birth date. *)typebirth=unitlet[@inline]iterator_is_born_s=()let[@inline]is_valid_s_birth=trueletinvalidate_iterators_s=assertfalseletinvalidate_iterators_except_s=assertfalseend(* -------------------------------------------------------------------------- *)(* Iterators on shareable sequences. *)(* This construction requires applying [Iterator.Make] to its own result.
Therefore, a [module rec] construct is needed. *)modulerecSSeqIter0:WITERwithtype'ameasure='aSChunk.measureandtype'at='aSSeq.t=Iterator.Make(SChunk)(SSeq)(SSeqHooks)(SSeqIter0)(* Unrolling the self-application once allows inlining and specialisation at
the outermost level. This yields a 3x performance improvement in
[get_and_move]. *)(* In terms of functionality, the modules [SSeqIter0] and [SSeqIter] are
equivalent. *)moduleSSeqIter=Iterator.Make(SChunk)(SSeq)(SSeqHooks)(SSeqIter0)(* -------------------------------------------------------------------------- *)(* Ephemeral sequences. *)moduleESeq=EphemeralSequence.Make(SChunk)(Settings)(SSeq)(SSeqIter)(* -------------------------------------------------------------------------- *)(* Iterators on ephemeral sequences. *)moduleESeqIter=UnitWeightIterator.Make(SChunk)(Iterator.Make(SChunk)(SSeq)(ESeq.Hooks)(SSeqIter))(* -------------------------------------------------------------------------- *)(* Heavyweight persistent sequences, based directly on shareable sequences. *)moduleHeavyPSeq=PersistentSequence.Make(SSeq)(* Iterators on heavy persistent sequences. *)moduleHeavyPSeqIter=UnitWeightIterator.Make(SChunk)(SSeqIter)(* -------------------------------------------------------------------------- *)(* To reduce the cost of working with persistent sequences, we introduce a
lightweight representation of short persistent sequences, and switch to
heavyweight persistent sequences only above a certain threshold. *)modulePSeq=ShortPersistentSequence.Make(HeavyPSeq)(HeavyPSeqIter)(Settings)(* Iterators on short persistent sequences. *)moduleShortPSeqIter=TrivialIterator.Make(PSeq)(* -------------------------------------------------------------------------- *)(* Iterators on persistent sequences. *)modulePSeqIter=struct(* For sequences of length no greater than [threshold], we use a trivial
iterator implementation. For long sequences, we use the iterators
provided by the module [S]. Dispatching between the two implementations
is trivial. *)moduleT=ShortPSeqItermoduleI=HeavyPSeqItertype'aiter=|IZeroOneShortof'aT.iter|ILongof'aI.iteropenPSeqlet[@specialise]createpovs=matchswith|Zero_|One_|Short_->IZeroOneShort(T.createpovs)|Level_->ILong(I.createpovs)let[@specialise]resetpovit=matchitwith|IZeroOneShortit->T.resetpovit|ILongit->I.resetpovitletcopy=function|IZeroOneShortit->IZeroOneShort(T.copyit)|ILongit->ILong(I.copyit)letsequence=function|IZeroOneShortit->T.sequenceit|ILongit->I.sequenceitletlength=function|IZeroOneShortit->T.lengthit|ILongit->I.lengthitletindex=function|IZeroOneShortit->T.indexit|ILongit->I.indexitletfinished=function|IZeroOneShortit->T.finishedit|ILongit->I.finisheditletget=function|IZeroOneShortit->T.getit|ILongit->I.getitletmovepov=function|IZeroOneShortit->T.movepovit|ILongit->I.movepovitletjumppovitk=matchitwith|IZeroOneShortit->T.jumppovitk|ILongit->I.jumppovitkletget_segmentpov=function|IZeroOneShortit->T.get_segmentpovit|ILongit->I.get_segmentpovitletreachiti=matchitwith|IZeroOneShortit->T.reachiti|ILongit->I.reachitiletcheck=function|IZeroOneShortit->T.checkit|ILongit->I.checkitletprintelement=function|IZeroOneShortit->T.printelementit|ILongit->I.printelementitend(* Iter *)(* -------------------------------------------------------------------------- *)(* -------------------------------------------------------------------------- *)(* Conversions between ephemeral sequences and persistent sequences. *)letthreshold=Settings.thresholdlet[@inline]snapshot_shorts=assert(ESeq.lengths<=threshold);(* Because [s] is short, we can (and should) allocate a short array
directly. Thus, we do not allocate a heavy persistent sequence. *)PSeq.of_short_array_destructive(ESeq.defaults)(ESeq.to_arrays)letsnapshot_and_clear_longs=assert(threshold<ESeq.lengths);(* Because [s] is long, we must create a heavy persistent sequence. *)PSeq.wrap_long(ESeq.snapshot_and_clears)letsnapshot_and_clears=letn=ESeq.lengthsinifn<=thresholdthenbeginlets'=snapshot_shortsinESeq.clears;s'endelsesnapshot_and_clear_longsletsnapshots=letn=ESeq.lengthsinifn<=thresholdthensnapshot_shortselsesnapshot_and_clear_long(ESeq.shallow_copys)(* It makes sense for [snapshot] to perform a shallow copy.
When people want to take a snapshot of a data structure,
they usually want an efficient operation. If they were
willing to pay a heavy cost, then they would think of
taking a "copy", not a "snapshot". *)letedits=ESeq.edit(PSeq.unwraps)(* -------------------------------------------------------------------------- *)(* -------------------------------------------------------------------------- *)(* We are essentially done. *)(* There remains to wrap the core functions with defensive code (although
our specification does not say so, we raise [Invalid_argument _] when
the user provides an invalid argument or attempts to perform a forbidden
operation) and define a large number of convenience functions. *)(* -------------------------------------------------------------------------- *)(* Ephemeral sequences. *)moduleEphemeral=structincludeESeqletunchecked_init=initletmakednv=ifnot(0<=n)theninvalid_arg"make: invalid length"elsemakednvletinitdnf=ifnot(0<=n)theninvalid_arg"init: invalid length"elseinitdnflet[@specialise]pop_optpovs=trySome(poppovs)withEmpty->Nonelet[@specialise]peek_optpovs=trySome(peekpovs)withEmpty->Nonelet[@inline]getsi=ifnot(0<=i&&i<lengths)theninvalid_arg"get: invalid index"elsegetsilet[@inline]setsix=ifnot(0<=i&&i<lengths)theninvalid_arg"set: invalid index"elsesetsixletconcats1s2=ifs1==s2theninvalid_arg"concat: the arguments must be distinct"elseconcats1s2let[@specialise]appendpovs1s2=ifs1==s2theninvalid_arg"append: the arguments must be distinct"elseappendpovs1s2let[@specialise]carvepovsi=ifnot(0<=i&&i<=lengths)theninvalid_arg"carve: invalid index"elsecarvepovsilet[@specialise]unchecked_takepovsi=matchpovwith|Front->takesi|Back->dropsilet[@specialise]unchecked_droppovsi=matchpovwith|Front->dropsi|Back->takesilettakepovsi=ifnot(0<=i&&i<=lengths)theninvalid_arg"take: invalid index"elseunchecked_takepovsiletdroppovsi=ifnot(0<=i&&i<=lengths)theninvalid_arg"drop: invalid index"elseunchecked_droppovsiletsplitsi=ifnot(0<=i&&i<=lengths)theninvalid_arg"split: invalid index"elsesplitsiletof_array_segmentdefaultaheadsize=ifnot(0<=size)theninvalid_arg"of_array_segment: invalid size"elseifnot(0<=head)theninvalid_arg"of_array_segment: invalid head"elseifnot(head+size<=Array.lengtha)theninvalid_arg"of_array_segment: invalid head or size"elseof_array_segmentdefaultaheadsizelet[@inline]of_arraydefaulta=of_array_segmentdefaulta0(Array.lengtha)(* [of_seq] *)(* It seems important to guarantee that the input sequence is forced only
once. (If the user is willing to force it multiple times, then she can
first measure its length, then use [of_seq_segment].) This can be done
in several ways:
- First convert the sequence to a list, then use [of_list].
- Convert it directly to a sequence via iterated pushes.
We choose the second approach, which seems more economical in terms of
memory. Iterated pushes are supposed to be efficient anyway. *)letof_seqdxs=lets=createdinSeq.iter(funx->pushbacksx)xs;slet[@specialise]iterpovfs=ArrayExtra.iteriter_segmentspovfsletiter_leftfs=iterFrontfsletiter_rightfs=iterBackfsletiteri_leftfs=Adapters.iteri_leftiter_leftfsletiteri_rightfs=Adapters.iteri_rightlengthiter_rightfslet[@specialise]iteripovfs=matchpovwith|Front->iteri_leftfs|Back->iteri_rightfsletfold_leftgseeds=Adapters.fold_leftiter_leftgseedsletfold_rightgsseed=Adapters.fold_rightiter_rightgsseedincludeGeneric.Iter(structtypenonrec'at='atletiter=iterend)includeGeneric.IterCreatePush(structtypenonrec'at='atletdefault=defaultletlength=lengthletiter=itertype'au='atletcreate_nd=createdletpush=pushlet[@inline]finalizes=send)letflattenss=letd=default(defaultss)inlets=creatediniterforward(appendbacks)ss;(* At this point [ss] is a sequence of empty sequences.
That seems pretty useless, so we prefer to clear it. *)clearss;sletstable_sortcmps=leta=to_arraysinArray.stable_sortcmpa;assigns(of_array(defaults)a)letsort=stable_sortletuniqcmps=Generic.uniqis_emptycreatedefaultpeekfilter(funpovsx->pushpovsx;s)cmps(* -------------------------------------------------------------------------- *)(* Iterators on ephemeral sequences (unchecked operations). *)moduleUncheckedIter=structincludeESeqIter(* Derived read operations. *)let[@inline]get_optit=trySome(getit)withEnd->Nonelet[@inline]get_segment_optpovit=trySome(get_segmentpovit)withEnd->None(* Derived read-and-move operations. *)let[@inline]get_and_movepovit=letx=getitin(* can raise [End] *)movepovit;xlet[@inline]get_and_move_optpovit=trySome(get_and_movepovit)withEnd->Nonelet[@inline]get_segment_and_jumppovit=let(_,_,k)asseg=get_segmentpovitin(* can raise [End] *)jumppovitk;seglet[@inline]get_segment_and_jump_optpovit=trySome(get_segment_and_jumppovit)withEnd->None(* Derived write-and-move operations. *)let[@inline]set_and_movepovitx=setitx;movepovitlet[@inline]get_writable_segment_optpovit=trySome(get_writable_segmentpovit)withEnd->Nonelet[@inline]get_writable_segment_and_jumppovit=let(_,_,k)asseg=get_writable_segmentpovitinjumppovitk;seglet[@inline]get_writable_segment_and_jump_optpovit=trySome(get_writable_segment_and_jumppovit)withEnd->None(* Miscellaneous. *)letformatelementchannelit=PPrint.ToFormatter.pretty0.876channel(printelementit)letformatchannel(it:intiter)=formatPPrint.OCaml.intchannelitend(* UncheckedIter *)(* -------------------------------------------------------------------------- *)(* Iterators on ephemeral sequences. *)moduleIter=struct(* A few functions do not need dynamic checks. We prefer to list them
one by one, instead of using [include UncheckedIter]. *)type'aiter='aUncheckedIter.iterletcreate=UncheckedIter.createletreset=UncheckedIter.resetletsequence=UncheckedIter.sequenceletis_valid=UncheckedIter.is_validletformat=UncheckedIter.formatletcheck=UncheckedIter.check(* Validation machinery. *)openSettings(* [check_iterator_validity] *)let[@inline]validatecallerit=ifcheck_iterator_validity&¬(is_validit)theninvalid_arg(caller^": invalid iterator")(* Creation operations. *)letcopyit=validate"copy"it;UncheckedIter.copyit(* Accessors. *)letlengthit=validate"length"it;UncheckedIter.lengthitletindexit=validate"index"it;UncheckedIter.indexitletfinishedit=validate"finished"it;UncheckedIter.finishedit(* Read operations. *)letgetit=validate"get"it;UncheckedIter.getitletget_optit=validate"get_opt"it;UncheckedIter.get_optitlet[@specialise]get_segmentpovit=validate"get_segment"it;UncheckedIter.get_segmentpovitlet[@specialise]get_segment_optpovit=validate"get_segment_opt"it;UncheckedIter.get_segment_optpovit(* Move operations. *)let[@specialise]movepovit=validate"move"it;(* For efficiency reasons, the check against attempting to move beyond the
sentinel is performed inside [move], instead of up front. *)UncheckedIter.movepovitlet[@specialise]jumppovitk=validate"jump"it;lettarget=indexit+signpov*kinif-1<=target&&target<=UncheckedIter.lengthitthenUncheckedIter.jumppovitkelseinvalid_arg"jump: target index is out of bounds"letreachiti=validate"reach"it;ifnot(-1<=i&&i<=UncheckedIter.lengthit)theninvalid_arg"reach: invalid index"elseUncheckedIter.reachiti(* Read-and-move operations. *)let[@specialise]get_and_movepovit=validate"get_and_move"it;UncheckedIter.get_and_movepovitlet[@specialise]get_and_move_optpovit=validate"get_and_move_opt"it;UncheckedIter.get_and_move_optpovitlet[@specialise]get_segment_and_jumppovit=validate"get_segment_and_jump"it;UncheckedIter.get_segment_and_jumppovitlet[@specialise]get_segment_and_jump_optpovit=validate"get_segment_and_jump_opt"it;UncheckedIter.get_segment_and_jump_optpovit(* Write operations. *)letsetitx=validate"set"it;UncheckedIter.setitxlet[@specialise]get_writable_segmentpovit=validate"get_writable_segment"it;UncheckedIter.get_writable_segmentpovitlet[@specialise]get_writable_segment_optpovit=validate"get_writable_segment_opt"it;UncheckedIter.get_writable_segment_optpovit(* Write-and-move operations. *)let[@specialise]set_and_movepovitx=validate"set_and_move"it;UncheckedIter.set_and_movepovitxlet[@specialise]get_writable_segment_and_jumppovit=validate"get_writable_segment_and_jump"it;UncheckedIter.get_writable_segment_and_jumppovitlet[@specialise]get_writable_segment_and_jump_optpovit=validate"get_writable_segment_and_jump_opt"it;UncheckedIter.get_writable_segment_and_jump_optpovitend(* Iter *)(* -------------------------------------------------------------------------- *)(* More operations on ephemeral sequences. *)(* The operations whose definition requires iterators are here. *)includeGeneric.IteratorsInit(structtypenonrec'at='atletdefault=defaultletlength=lengthletunchecked_init=unchecked_initmoduleIter=UncheckedIterend)(* [restrict s head size] is an in-place variant of [sub]: the sequence is
truncated in place to the segment defined by [head] and [size]. *)let[@inline]restrictsheadsize=unchecked_dropfrontshead;unchecked_takefrontssize(* [_unchecked_sharing_sub] is a (currently unused) implementation of [sub]
with sharing semantics: that is, the sequence that is returned shares
some of its chunks with the sequence [s]. *)let_unchecked_sharing_subsheadsize=lets=shallow_copysinrestrictsheadsize;slet[@inline]unchecked_copying_subsheadsize=letit=Iter.createforwardsinIter.reachithead;unchecked_init(defaults)size(fun_i->Iter.get_and_moveforwardit)(* TODO speed up using [get_segment_and_jump] and [push_segment] *)letsubsheadsize=ifnot(0<=size)theninvalid_arg"sub: invalid size"elseifnot(0<=head)theninvalid_arg"sub: invalid head"elseifnot(head+size<=lengths)theninvalid_arg"sub: invalid head or size"elseunchecked_copying_subsheadsizeletrecunchecked_iter_fillitsizex=ifsize>0thenbeginassert(not(Iter.finishedit));leta,i,k=Iter.get_writable_segment_and_jumpforwarditinifsize<=kthenArray.fillaisizexelsebeginArray.fillaikx;letsize=size-kinunchecked_iter_fillitsizexendendlet[@inline]unchecked_fillsheadsizex=(* We must explicitly invalidate all iterators, because the loop
below won't do it in case [size] is zero. *)ESeq.Hooks.invalidate_iteratorss;letit=Iter.createforwardsinIter.reachithead;unchecked_iter_fillitsizexletfillsheadsizex=ifnot(0<=size)theninvalid_arg"fill: invalid size"elseifnot(0<=head)theninvalid_arg"fill: invalid head"elseifnot(head+size<=lengths)theninvalid_arg"fill: invalid head or size"elseunchecked_fillsheadsizexletunchecked_blitpovs1start1s2start2size=letit1=Iter.create(* irrelevant: *)povs1andit2=Iter.create(* irrelevant: *)povs2inIter.reachit1start1;Iter.reachit2start2;letblit_segment(a1,i1,k1)(a2,i2,k2)=assert(k1=k2);Array.blita1i1a2i2k1inbounded_iter2_segmentspov(s1==s2)truesizeit1it2blit_segmentlet[@inline]unchecked_blits1head1s2head2size=(* We must explicitly invalidate all iterators, because the code
below doesn't do it in all cases. *)ESeq.Hooks.invalidate_iteratorss2;ifs1!=s2then(* Both directions work. *)unchecked_blitforwards1head1s2head2sizeelseifhead1=head2then(* There is nothing to do in this case. *)()elseifhead1<head2then(* Blit backward to avoid any problem in case of overlap. *)unchecked_blitbackwards1(head1+size-1)s2(head2+size-1)sizeelse(* Blit forward to avoid any problem in case of overlap. *)unchecked_blitforwards1head1s2head2sizeletblits1head1s2head2size=ifnot(0<=size)theninvalid_arg"blit: invalid size"elseifnot(0<=head1)theninvalid_arg"blit: invalid source head"elseifnot(head1+size<=lengths1)theninvalid_arg"blit: invalid source head or size"elseifnot(0<=head2)theninvalid_arg"blit: invalid destination head"elseifnot(head2+size<=lengths2)theninvalid_arg"blit: invalid destination head or size"elseunchecked_blits1head1s2head2size(* Define [copy] with a [mode] argument as a single entry point
for [deep_copy] and [shallow_copy]. *)letcopy?mode:(mode=`Copy)s=matchmodewith|`Copy->deep_copys|`Share->shallow_copysend(* Ephemeral *)moduleE=Ephemeral(* -------------------------------------------------------------------------- *)(* Persistent sequences. *)modulePersistent=structincludePSeqletunchecked_init=initletmakednv=ifnot(0<=n)theninvalid_arg"make: invalid length"elsemakednvletinitdnf=ifnot(0<=n)theninvalid_arg"init: invalid length"elseinitdnflet[@inline]getsi=ifnot(0<=i&&i<lengths)theninvalid_arg"get: invalid index"elsegetsilet[@inline]setsix=ifnot(0<=i&&i<lengths)theninvalid_arg"set: invalid index"elsesetsixletsplitsi=ifnot(0<=i&&i<=lengths)theninvalid_arg"split: invalid index"elsesplitsilet[@specialised]unchecked_takepovsi=(* Internally, the functions are named [take] and [drop], and
do not take a [pov] parameter. Externally, these functions
take a [side] parameter: [take front] and [drop back] are
two names for the same function, as are [take back] and
[drop front]. *)matchpovwith|Front->takesi|Back->dropsilet[@specialised]takepovsi=ifnot(0<=i&&i<=lengths)theninvalid_arg"take: invalid index"elseunchecked_takepovsilet[@specialised]droppovsi=ifnot(0<=i&&i<=lengths)theninvalid_arg"drop: invalid index"elseunchecked_take(dualpov)siletsubsheadsize=ifnot(0<=size)theninvalid_arg"sub: invalid size"elseifnot(0<=head)theninvalid_arg"sub: invalid head"elseifnot(head+size<=lengths)theninvalid_arg"sub: invalid head or size"elsesubsheadsizeletof_array_segmentdefaultaheadsize=ifnot(0<=size)theninvalid_arg"of_array_segment: invalid size"elseifnot(0<=head)theninvalid_arg"of_array_segment: invalid head"elseifnot(head+size<=Array.lengtha)theninvalid_arg"of_array_segment: invalid head or size"elseof_array_segmentdefaultaheadsizelet[@inline]of_seqdxs=snapshot_and_clear(E.of_seqdxs)let[@specialise]pop_optpovs=tryletx,s=poppovsinSomex,swithEmpty->None,slet[@specialise]peek_optpovs=trySome(peekpovs)withEmpty->Nonelet[@specialise]iterpovfs=ArrayExtra.iteriter_segmentspovfsletiter_leftfs=iterFrontfsletiter_rightfs=iterBackfsletiteri_leftfs=Adapters.iteri_leftiter_leftfsletiteri_rightfs=Adapters.iteri_rightlengthiter_rightfslet[@specialise]iteripovfs=matchpovwith|Front->iteri_leftfs|Back->iteri_rightfsletfold_leftgseeds=Adapters.fold_leftiter_leftgseedsletfold_rightgsseed=Adapters.fold_rightiter_rightgsseedletto_lists=Adapters.to_listiter_rightsletformatelementchannels=PPrint.ToFormatter.pretty0.876channel(printelements)letformatchannel(s:intt)=formatPPrint.OCaml.intchannelsletflattenss=letd=default(defaultss)infold_rightconcatss(created)includeGeneric.Iter(structtypenonrec'at='atletiter=iterend)(* The functor [IterCreatePush] defines several functions that use repeated
pushing into an ephemeral data structure, then convert this data structure
into a persistent sequence. *)(* When dealing with a long persistent sequence, then the ephemeral data
structure can be an ephemeral sequence. When dealing with a short sequence,
however, we do not want to pay the price of allocating a heavy ephemeral
sequence; we prefer to work with a home-made stack, stored in an array. *)(* Therefore, we apply the functor [IterCreatePush] twice, and for each
function, we write a small wrapper, which selects at runtime between the
two implementations. *)moduleIterCreatePushLightweight=Generic.IterCreatePush(structtypenonrec'at='atletdefault=defaultletlength=lengthletiter=iter(* An array, used a stack, growing towards the top. We choose this
representation because it allows us to use [of_array_segment]. *)type'au={data:'aarray;mutablelimit:int;default:'a}let[@inline]creatend={data=Array.makend;limit=0;default=d}let[@inline]pushdirectionsx=assert(direction=back);letlimit=s.limitinassert(limit<Array.lengths.data);s.data.(limit)<-x;s.limit<-limit+1letfinalize{data;limit;default}=of_array_segmentdefaultdata0limitend)moduleIterCreatePushHeavyweight=Generic.IterCreatePush(structtypenonrec'at='atletdefault=defaultletlength=lengthletiter=itertype'au='aE.tletcreate_nd=E.createdletpush=E.pushletfinalize=snapshot_and_clearend)letfilterps=iflengths<=thresholdthenIterCreatePushLightweight.filterpselseIterCreatePushHeavyweight.filterpsletfilter_mapdfs=iflengths<=thresholdthenIterCreatePushLightweight.filter_mapdfselseIterCreatePushHeavyweight.filter_mapdfsletflatten_map=(* No choice here. Because we cannot predict the length of the result,
we choose the heavyweight road. *)(* An alternative approach would be to use an ephemeral data structure
that begins its life as a bounded stack (stored in an array) and
switches to an ephemeral sequence when [threshold] is exceeded. LATER *)IterCreatePushHeavyweight.flatten_mapletpartitionps=iflengths<=thresholdthenIterCreatePushLightweight.partitionpselseIterCreatePushHeavyweight.partitionpsletstable_sortcmps=(* Convert [s] to an array; sort; convert back. *)(* Considering that [s] is a persistent sequence, therefore cannot
be sorted in place, I can't think of a better way. *)leta=to_arraysinArray.stable_sortcmpa;of_array(defaults)aletsort=stable_sortletuniqcmps=Generic.uniqis_emptycreatedefaultpeekfilterpushcmps(* -------------------------------------------------------------------------- *)(* Iterators on persistent sequences (unchecked operations). *)moduleUncheckedIter=structincludePSeqIter(* Read operations. *)letget_optit=trySome(getit)withEnd->Nonelet[@specialise]get_segment_optpovit=trySome(get_segmentpovit)withEnd->None(* Read-and-move operations. *)let[@inline]get_and_movepovit=letx=getitin(* can raise [End] *)movepovit;xlet[@specialise]get_and_move_optpovit=trySome(get_and_movepovit)withEnd->Nonelet[@inline]get_segment_and_jumppovit=let(_,_,k)asseg=get_segmentpovitin(* can raise [End] *)jumppovitk;seglet[@specialise]get_segment_and_jump_optpovit=trySome(get_segment_and_jumppovit)withEnd->None(* This phony write operation is required by [Generic.Iter]. *)letget_writable_segment_and_jump_pov_it=assertfalse(* never called *)(* Miscellaneous. *)letformatelementchannelit=PPrint.ToFormatter.pretty0.876channel(printelementit)letformatchannel(it:intiter)=formatPPrint.OCaml.intchannelitend(* UncheckedIter *)(* -------------------------------------------------------------------------- *)(* Iterators on persistent sequences (checked operations). *)moduleIter=structincludeUncheckedIterlet[@specialise]jumppovitk=lettarget=indexit+signpov*kinif-1<=target&&target<=lengthitthenjumppovitkelseinvalid_arg"jump: target index is out of bounds"letreachiti=ifnot(-1<=i&&i<=lengthit)theninvalid_arg"reach: invalid index"elsereachitiend(* Iter *)(* -------------------------------------------------------------------------- *)(* More operations on persistent sequences. *)(* The operations whose definition requires iterators are here. *)includeGeneric.IteratorsInit(structtypenonrec'at='atletdefault=defaultletlength=lengthletunchecked_init=unchecked_initmoduleIter=UncheckedIterend)end(* Persistent *)moduleP=Persistent(* -------------------------------------------------------------------------- *)(* Imposing a length equality check on top of a binary function. *)let[@inline]strictifylength1length2namefs1s2=letn1,n2=length1s1,length2s2inifn1<>n2theninvalid_arg(Printf.sprintf"%s: the sequences have distinct lengths (%d <> %d)"namen1n2)elsefs1s2(* -------------------------------------------------------------------------- *)(* -------------------------------------------------------------------------- *)(* Emulation wrappers for some of OCaml's standard library modules. *)moduleEmulated=struct(* -------------------------------------------------------------------------- *)(* An [Array] wrapper. *)moduleArray=structtype'at='aE.ttype'aarray='atletlength=E.lengthletget=E.getletset=E.setletmake=E.makeletcreate_floatn=make0.0n0.0letinit=E.initletmake_matrixdmnx=init(maked0x)m(fun_i->makednx)(* [_sharing_append] is an implementation of [Array.append] with internal
sharing. It requires logarithmic time, but causes the sequences to lose
the unique ownership of their chunks. *)(* [_sharing_concat] is an implementation of [Array.concat] with internal
sharing. *)letappend_shallow_copys1s2=E.appendbacks1(E.shallow_copys2)let_sharing_appends1s2=lets1=E.shallow_copys1inappend_shallow_copys1s2;s1let_sharing_concat(typea)(d:a)(ss:aarraylist):aarray=lets=E.createdinList.iter(append_shallow_copys)ss;s(* These implementations of [Array.append] and [Array.concat] use copying
and preserve unique ownership. *)(* A possibly more efficient implementation would use [iter_segments] on
each source sequence in turn and [push_segment] into the destination
sequence. TODO *)(* Because the length of the result can be easily computed in advance,
one might imagine implementing [Array.concat] using [init]. However,
that would require reading elements one by one instead of segment by
segment, so it would be slower. *)letappend_deep_copys1s2=E.appendbacks1(E.deep_copys2)letconcat(typea)(d:a)(ss:aarraylist):aarray=lets=E.createdinList.iter(append_deep_copys)ss;sletappends1s2=concat(E.defaults1)[s1;s2]letsub=E.subletcopy=E.deep_copyletfill=E.fillletblit=E.blitletto_list=E.to_listletof_list=E.of_listlet[@inline]iterfs=E.iterforwardfslet[@inline]iterifs=E.iteriforwardfsletmap=E.mapletmapi=E.mapiletfold_left=E.fold_leftletfold_right=E.fold_rightlet[@inline]strictifynamefs1s2=strictifylengthlengthnamefs1s2letiter2fs1s2=strictify"iter2"(E.iter2forwardf)s1s2letmap2dfs1s2=strictify"map2"(E.map2df)s1s2letfor_all=E.for_allletexists=E.existsletfor_all2=E.for_all2letexists2=E.exists2letmem=E.memletmemq=E.memqletsort=E.sortletstable_sort=E.stable_sortletfast_sort=stable_sortlet[@inline]to_seqs=E.to_seqforwardslet[@inline]to_seqis=E.to_seqiforwardsletof_seq=E.of_seqend(* Array *)(* -------------------------------------------------------------------------- *)(* A [Queue] wrapper. *)moduleQueue=structtype'at='aE.texceptionEmpty=Emptylet[@inline]created=E.createdlet[@inline]addxq=E.pushbackqxletpush=addlet[@inline]takeq=E.popfrontqlet[@inline]take_optq=E.pop_optfrontqletpop=takelet[@inline]peekq=E.peekfrontqlet[@inline]peek_optq=E.peek_optfrontqlettop=peekletclear=E.clearletcopy=E.deep_copyletis_empty=E.is_emptyletlength=E.lengthlet[@inline]iterfs=E.iterfrontfslet[@inline]foldfseeds=E.fold_leftfseedslet[@inline]transferq1q2=(* Add all of [q1]'s elements at the end of [q2], then clear [q1]. *)E.appendbackq2q1let[@inline]to_seqs=E.to_seqforwardslet[@inline]add_seqqxs=Seq.iter(funx->pushxq)xsletof_seqdxs=letq=createdinadd_seqqxs;qend(* Queue *)(* -------------------------------------------------------------------------- *)(* A [Stack] wrapper. *)moduleStack=structtype'at='aE.texceptionEmpty=Emptylet[@inline]created=E.createdlet[@inline]pushxs=E.pushfrontsxlet[@inline]pops=E.popfrontslet[@inline]pop_opts=E.pop_optfrontslet[@inline]tops=E.peekfrontslet[@inline]top_opts=E.peek_optfrontsletclear=E.clearletcopy=E.deep_copyletis_empty=E.is_emptyletlength=E.lengthlet[@inline]iterfs=E.iterfrontfslet[@inline]foldfseeds=E.fold_leftfseedslet[@inline]to_seqs=E.to_seqforwardslet[@inline]add_seqsxs=Seq.iter(funx->pushxs)xsletof_seqdxs=lets=createdinadd_seqsxs;send(* Stack *)(* -------------------------------------------------------------------------- *)(* A [List] wrapper. *)moduleList=structtype'at='aP.ttype'alist='atletlength=P.lengthletcompare_lengthss1s2=compare(lengths1)(lengths2)letcompare_length_withs1n2=compare(lengths1)n2letconsxs=P.pushfrontsxlethds=tryletx,_=P.popfrontsinxwithEmpty->failwith"hd"lettls=trylet_,s=P.popfrontsinswithEmpty->failwith"tl"letnth si=ifi<0theninvalid_arg "List.nth"elseifi<lengthsthenP.getsielsefailwith"nth"letnth_optsi=ifi<0theninvalid_arg"List.nth"elseifi<length sthenSome(P.getsi)elseNoneletrev=P.revletinit=P.initletappend=P.concatlet(@)=appendletrev_appends1s2=append(P.revs1)s2letflatten=P.flattenletconcat=flattenlet[@inline]iterfs=P.iterforwardfslet[@inline]iterifs=P.iteriforwardfsletmap=P.mapletmapi=P.mapi(* Not worthy of being defined in the module [Persistent]: *)letrev_mapdfs=letit=P.Iter.createbackwardsininitd(lengths)(fun_i->letx=P.Iter.get_and_movebackwarditinfx)letfilter_map=P.filter_mapletconcat_map=P.flatten_map(* [fold_left_map] appears in OCaml 4.11.0. *)letfold_left_mapdfaccus=letstate=refaccuinlets=mapd(funx->letaccu=!stateinletaccu,y=faccuxinstate:=accu;y)sin!state,sletfold_left=P.fold_leftletfold_right=P.fold_rightlet[@inline]strictifynamefs1s2=strictifylengthlengthnamefs1s2letiter2fs1s2=strictify"iter2"(P.iter2forwardf)s1s2letmap2dfs1s2=strictify"map2"(P.map2df)s1s2(* Not worthy of being defined in the module [Persistent]: *)letrev_map2dfs1s2=letit1=P.Iter.createbackwards1andit2=P.Iter.createbackwards2ininitd(min(lengths1)(lengths2))(fun_i->letx1=P.Iter.get_and_movebackwardit1andx2=P.Iter.get_and_movebackwardit2infx1x2)letrev_map2dfs1s2=strictify"rev_map2"(rev_map2df)s1s2letfold_left2fseeds1s2=strictify"fold_left2"(P.fold_left2fseed)s1s2letfold_right2fs1s2seed=strictify"fold_right2"(funs1s2->P.fold_right2fs1s2seed)s1s2letfor_all=P.for_allletexists=P.existsletexists2ps1s2=strictify"exists2"(P.exists2p)s1s2letfor_all2ps1s2=strictify"for_all2"(P.for_all2p)s1s2letmem=P.memletmemq=P.memqletfindps=P.findforwardpsletfind_optps=P.find_optforwardpsletfind_mapps=P.find_mapforwardpsletfilter=P.filterletfind_all=filterlet[@inline]postincrementindex=leti=!indexinindex:=i+1;iletfilterips=leti=ref0infilter(funx->p(postincrementi)x)sletpartition=P.partition(* Not worthy of being defined in the module [Persistent]: *)letassockkvs=let_,v=find(fun(k',_)->k=k')kvsinvletassoc_optkkvs=trySome(assockkvs)withNot_found->Noneletassqkkvs=let_,v=find(fun(k',_)->k==k')kvsinvletassq_optkkvs=trySome(assqkkvs)withNot_found->Noneletmem_assockkvs=assoc_optkkvs<>Noneletmem_assqkkvs=assq_optkkvs<>None(* TODO [remove_assoc] and [remove_assq] cannot yet be implemented;
we need [delete] on sequences (or on iterators). *)letsplit=P.unzipletcombines1s2=strictify"combine"P.zips1s2letsort=P.sortletstable_sort=P.stable_sortletfast_sort=stable_sortletuniq=P.uniqletsort_uniqcmps=s|>sortcmp|>uniqcmpletmerge=P.mergeletto_seqs=P.to_seqforwardsletof_seq=P.of_seqend(* List *)end(* Emulated *)(* -------------------------------------------------------------------------- *)(* -------------------------------------------------------------------------- *)(* This little function is used to check that we have not mistakenly
enabled assertions in a release build; that would be costly. *)letreleased()=assert(1=2)(* Expose the module [Segment]. *)moduleSegment=Segmentend(* -------------------------------------------------------------------------- *)(* Instantiate [Make] with default parameters. *)includeMake(DefaultSettings)(* -------------------------------------------------------------------------- *)(* Include this functor, which is defined in a separate file, because it is
essentially impossible to write down its signature in a compact way. *)includeSupplyDefault