123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347(**************************************************************************)(* *)(* OCaml *)(* *)(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)(* Antal Spector-Zabusky, Jane Street, New York *)(* *)(* Copyright 1996 Institut National de Recherche en Informatique et *)(* en Automatique. *)(* Copyright 2023 Jane Street Group LLC *)(* *)(* All rights reserved. This file is distributed under the terms of *)(* the GNU Lesser General Public License version 2.1, with the *)(* special exception on linking described in the file LICENSE. *)(* *)(**************************************************************************)open!Stdlib(* NOTE: If you update this file, please also update iarrayLabels.ml; from the
declaration of [type +'a t = 'a iarray] on down, they're the same. This is a
temporary state of affairs, but for now, please copy things! *)(* In this file, we use four different implementation strategies:
1. Reusing [external]s for mutable arrays. (E.g., [get].)
2. Copying implementations from [array.ml], which in this new context read
from immutable arrays. (E.g., [iter].)
3. As (2), but they construct a mutable array, which we unsafely
reinterpret as an immutable array at the very end (E.g., [map].)
4. (Only for sorting.) Copying the immutable array and passing it to a
mutating function. (E.g., [sort].)
The first and third strategies are safe because mutable and immutable arrays
have the same runtime representation, and we only apply them to functions
that satisfy the following three properties:
A. They do not mutate their array inputs;
B. They do not hold on to their array inputs; and
C. They return a fresh array if they return an array.
We do not expose other primitives (e.g., [unsafe_set]) or functions (e.g.,
[fill]).
We choose between the four strategies as follows:
1. We use [external]s if there is a corresponding [external].
2. Functions that only read arrays can have their implementations safely
copied.
3. Functions that create an immutable array have to do so by creating a
mutable array and freezing it, since immutable arrays are, well,
immutable. For efficiency, we freeze them unsafely.
4. Sorting is implemented in-place and this allows to to reuse it.
*)[@@@ocaml.flambda_o3](* An alias for the type of immutable arrays. *)type(+'a:anymodseparable)t='aiarray(* Array operations *)externallength:('a:anymodseparable).local_'aiarray->int@@portable="%array_length"[@@layout_poly]externalget:('a:anymodseparable).('aiarray[@local_opt])->int->('a[@local_opt])@@portable="%array_safe_get"[@@layout_poly]externalunsafe_get:('a:anymodseparable).('aiarray[@local_opt])->int->('a[@local_opt])@@portable="%array_unsafe_get"[@@layout_poly]externalconcat:('a:anymodseparable).'aiarraylist->'aiarray@@portable="caml_array_concat"externalappend_prim:('a:anymodseparable).'aiarray->'aiarray->'aiarray@@portable="caml_array_append"externalunsafe_sub:('a:anymodseparable).'aiarray->int->int->'aiarray@@portable="caml_array_sub"externalunsafe_of_array:('a:anymodseparable).'aarray->'aiarray@@portable="%array_to_iarray"externalunsafe_to_array:('a:anymodseparable).'aiarray->'aarray@@portable="%array_of_iarray"(* Used only to reimplement [init] *)externalunsafe_set_mutable:('a:anymodseparable).'aarray->int->'a->unit@@portable="%array_unsafe_set"[@@layout_poly](* We can't use immutable array literals in this file, since we don't want to
require the stdlib to be compiled with extensions, so instead of [[::]] we
use [unsafe_of_(local_)array [||]] below. *)(* The implementation is copied from [Array] so that [f] can be [local_] *)letinitl(local_f)=ifl=0thenunsafe_of_array[||]elseifl<0theninvalid_arg"Iarray.init"(* See #6575. We could also check for maximum array size, but this depends
on whether we create a float array or a regular one... *)elseletres=Array.makel(f0)infori=1topredldounsafe_set_mutableresi(fi)done;unsafe_of_arrayresletappenda1a2=iflengtha1=0thena2(* Safe because they're immutable *)elseiflengtha2=0thena1elseappend_prima1a2letsuba~pos~len=ifpos<0||len<0||pos>lengtha-lentheninvalid_arg"Iarray.sub"elseunsafe_subaposlenletiterfa=fori=0tolengtha-1dof(unsafe_getai)doneletiter2fab=iflengtha<>lengthbtheninvalid_arg"Iarray.iter2: arrays must have the same length"elsefori=0tolengtha-1dof(unsafe_getai)(unsafe_getbi)doneletmapfa=letl=lengthainifl=0thenunsafe_of_array[||]elsebeginletr=Array.makel(f(unsafe_geta0))infori=1tol-1doArray.unsafe_setri(f(unsafe_getai))done;unsafe_of_arrayrendletmap2fab=letla=lengthainletlb=lengthbinifla<>lbtheninvalid_arg"Iarray.map2: arrays must have the same length"elsebeginifla=0thenunsafe_of_array[||]elsebeginletr=Array.makela(f(unsafe_geta0)(unsafe_getb0))infori=1tola-1doArray.unsafe_setri(f(unsafe_getai)(unsafe_getbi))done;unsafe_of_arrayrendendletiterifa=fori=0tolengtha-1dofi(unsafe_getai)doneletmapifa=letl=lengthainifl=0thenunsafe_of_array[||]elsebeginletr=Array.makel(f0(unsafe_geta0))infori=1tol-1doArray.unsafe_setri(fi(unsafe_getai))done;unsafe_of_arrayrendletto_lista=letrectolistires=ifi<0thenreselsetolist(i-1)(unsafe_getai::res)intolist(lengtha-1)[]letof_listl=unsafe_of_array(Array.of_listl)(* This shouldn't violate the forward-pointers restriction because the list
elements already exist *)letto_arrayia=Array.copy(unsafe_to_arrayia)letof_arrayma=unsafe_of_array(Array.copyma)letfold_leftfxa=letr=refxinfori=0tolengtha-1dor:=f!r(unsafe_getai)done;!rletfold_left_mapfaccinput_array=letlen=lengthinput_arrayiniflen=0then(acc,unsafe_of_array[||])elsebeginletacc,elt=facc(unsafe_getinput_array0)inletoutput_array=Array.makeleneltinletacc=refaccinfori=1tolen-1doletacc',elt=f!acc(unsafe_getinput_arrayi)inacc:=acc';Array.unsafe_setoutput_arrayielt;done;!acc,unsafe_of_arrayoutput_arrayendletfold_rightfax=letr=refxinfori=lengtha-1downto0dor:=f(unsafe_getai)!rdone;!r(* CR aspectorzabusky: Why do I need this? Shouldn't mode-crossing handle doing
this? *)let[@inlinealways]globalize_bool:local_bool->bool=funb->bletexistspa=letn=lengthainletrecloopi=exclave_ifi=nthenfalseelseifp(unsafe_getai)thentrueelseloop(succi)inglobalize_bool(loop0)letfor_allpa=letn=lengthainletrecloopi=exclave_ifi=nthentrueelseifp(unsafe_getai)thenloop(succi)elsefalseinglobalize_bool(loop0)letfor_all2pl1l2=letn1=lengthl1andn2=lengthl2inifn1<>n2theninvalid_arg"Iarray.for_all2"elseletrecloopi=exclave_ifi=n1thentrueelseifp(unsafe_getl1i)(unsafe_getl2i)thenloop(succi)elsefalseinglobalize_bool(loop0)letexists2pl1l2=letn1=lengthl1andn2=lengthl2inifn1<>n2theninvalid_arg"Iarray.exists2"elseletrecloopi=exclave_ifi=n1thenfalseelseifp(unsafe_getl1i)(unsafe_getl2i)thentrueelseloop(succi)inglobalize_bool(loop0)letmemxa=letn=lengthainletrecloopi=exclave_ifi=nthenfalseelseifcompare(unsafe_getai)x=0thentrueelseloop(succi)inglobalize_bool(loop0)letmemqxa=letn=lengthainletrecloopi=exclave_ifi=nthenfalseelseifx==(unsafe_getai)thentrueelseloop(succi)inglobalize_bool(loop0)letfind_optpa=letn=lengthainletrecloopi=ifi=nthenNoneelseletx=unsafe_getaiinifpxthenSomexelseloop(succi)inloop0[@nontail]letfind_mapfa=letn=lengthainletrecloopi=ifi=nthenNoneelsematchf(unsafe_getai)with|None->loop(succi)|Some_asr->rinloop0[@nontail]letsplitx=ifx=unsafe_of_array[||]thenunsafe_of_array[||],unsafe_of_array[||]elsebeginleta0,b0=unsafe_getx0inletn=lengthxinleta=Array.makena0inletb=Array.makenb0infori=1ton-1doletai,bi=unsafe_getxiinArray.unsafe_setaiai;Array.unsafe_setbibidone;unsafe_of_arraya,unsafe_of_arraybendletcombineab=letna=lengthainletnb=lengthbinifna<>nbtheninvalid_arg"Iarray.combine";letr=ifna=0then[||]elsebeginletx=Array.makena(unsafe_geta0,unsafe_getb0)infori=1tona-1doArray.unsafe_setxi(unsafe_getai,unsafe_getbi)done;xendinunsafe_of_arrayr(* Must be fully applied due to the value restriction *)letlift_sortsortercmpiarr=letarr=to_arrayiarrinsortercmparr;unsafe_of_arrayarrletsortcmpiarr=lift_sortArray.sortcmpiarrletstable_sortcmpiarr=lift_sortArray.stable_sortcmpiarrletfast_sortcmpiarr=lift_sortArray.fast_sortcmpiarrletto_seqa=letrecauxi()=ifi<lengthathenletx=unsafe_getaiinSeq.Cons(x,aux(i+1))elseSeq.Nilinaux0letto_seqia=letrecauxi()=ifi<lengthathenletx=unsafe_getaiinSeq.Cons((i,x),aux(i+1))elseSeq.Nilinaux0letof_seqi=unsafe_of_array(Array.of_seqi)