123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143(******************************************************************************)(* *)(* 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. *)(* *)(******************************************************************************)openPublicTypeAbbreviationsletis_valid_segmentaik=0<=k&&0<=i&&i+k<=Array.lengthaletfill_circularlyaikx=(* The destination array must be large enough. *)letn=Array.lengthainassert(k<=n);(* The destination index must be well-formed. *)assert(0<=i&&i<n);(* We need either one or two fills. *)ifi+k<=nthenArray.fillaikxelsebeginletk1=n-iinassert(0<k1&&k1<k);Array.fillaik1x;Array.filla0(k-k1)xend(** [blit_circularly_dst a1 i1 a2 i2 k] copies [k] elements from the array
[a1], starting at index [i1], to the array [a2], starting at index [i2].
The destination array is regarded as circular, so it is permitted for the
destination range to wrap around. *)letblit_circularly_dsta1i1a2i2k=(* The source range must be well-formed. *)assert(is_valid_segmenta1i1k);(* The destination array must be large enough to hold the data. *)letn2=Array.lengtha2inassert(k<=n2);(* The destination index must be well-formed. *)assert(0<=i2&&i2<n2);(* We need either one or two blits. *)ifi2+k<=n2thenArray.blita1i1a2i2kelsebeginletk1=n2-i2inassert(0<k1&&k1<k);Array.blita1i1a2i2k1;Array.blita1(i1+k1)a20(k-k1)endletblit_circularlya1i1a2i2k=letn1=Array.lengtha1in(* The source range must be well-formed. *)assert(0<=i1&&i1<n1);assert(0<=k);(* The destination array must be large enough to hold the data. *)letn2=Array.lengtha2inassert(k<=n2);(* The destination index must be well-formed. *)assert(0<=i2&&i2<n2);(* We need either one or two calls to [blit_circularly_dst]. *)ifi1+k<=n1thenblit_circularly_dsta1i1a2i2kelsebeginletk1=n1-i1inassert(0<k1&&k1<k);blit_circularly_dsta1i1a2i2k1;leti2=i2+k1inleti2=ifi2<n2theni2elsei2-n2in(* LATER: i2 can be computed using a modulo *)blit_circularly_dsta10a2i2(k-k1)endletcut_exactlynheadsizeyield=(* [head] and [size] must represent a valid range. *)assert(0<=size);assert(0<=head);(* The desired chunk capacity [n] must be positive. *)assert(0<n);(* [size] must be a multiple of [n]. *)assert(sizemodn=0);(* Compute the number of segments. *)letsegments=size/nin(* Iterate on these segments. *)fori=0tosegments-1doyield(head+i*n)ndoneletcutn0nsize=(* [size] must represent a valid length. *)assert(0<=size);(* The front chunk is allowed to be empty. *)assert(0<=n0);(* The desired chunk capacity [n] must be positive. *)assert(0<n);(* Compute the front segment, adjusting [head] and [size]. *)letfront,head,size=letsize_front=minsizen0in(0,size_front),size_front,size-size_frontin(* Compute the back segment, adjusting [size]. *)letback,size=letremainder=sizemodninletsize_back=ifsize>0&&remainder=0thennelseremainderinletsize=size-size_backin(head+size,size_back),sizein(* Return a triple of the front segment, an iterator on the
segments in the middle area (whose size is a multiple of [n]),
and the back segment. *)front,cut_exactlynheadsize,backtype'asegments=('aarray->index->length->unit)->unit(* The OCaml runtime system offers the C function [caml_array_gather], which
copies a series of array segments. We might wish to use it (thereby saving
the cost of initializing the array with [default] values) but that would
require materializing the list of segments in memory and writing some more
glue code in C. *)letconcat_segmentsdefaultnforeach_segment=assert(0<=n);letb=Array.makendefaultinletj=ref0inforeach_segment(funaik->assert(is_valid_segmentaik);assert(!j+k<=n);Array.blitaib!jk;j:=!j+k);b