12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091(******************************************************************************)(* *)(* Baby *)(* *)(* François Pottier, Inria Paris *)(* *)(* Copyright 2024--2024 Inria. All rights reserved. This file is *)(* distributed under the terms of the GNU Library General Public *)(* License, with an exception, as described in the file LICENSE. *)(* *)(******************************************************************************)openArrayletcompressequala=letn=lengthainifn<=1then(* If the length of the array is 0 or 1, there is nothing to do. *)nelse(* Now, prepare to copy the elements of the array downwards, in place,
so as to eliminate duplicate elements. [last] is the last element
that was read and kept. [!dst] is the number of elements that have
been kept so far, so it is also the index of the slot that will be
written next. *)letlast=refa.(0)inletdst=ref1in(* Let [src] scan the array. *)forsrc=1ton-1doassert(1<=!dst&&!dst<=src&&src<n);assert(equal!lasta.(src-1));letcurrent=a.(src)inifcurrent=!lastthen(* Skip this element. *)()elsebegin(* Keep this element, copying it down to index [!dst]. *)if!dst<srcthena.(!dst)<-current;last:=current;incrdstend;assert(equal!lastcurrent);assert(equal!lasta.(src));done;!dsttyperun=int*intletrecforeach_increasing_run_in_slicecompareyieldaccuain=assert(0<=i&&i<=n&&n<=lengtha);ifi=nthen(* There are no more runs. *)accuelse(* A new run begins at index [i]. *)letlast=a.(i)andj=i+1inscancompareyieldaccuailastjnandscancompareyieldaccuailastjn=assert(0<=i&&i<=j&&j<=n&&n<=lengtha);ifj=nthen(* The run [i, j] ends here,
and the loop ends as well. *)yieldaccuijelseletcurrent=a.(j)inifcomparelastcurrent<0then(* The current run continues. *)letlast=currentandj=j+1inscancompareyieldaccuailastjnelse(* The run [i, j] ends here,
and the loop continues. *)letaccu=yieldaccuijinletlast=currentandi=jandj=j+1inscancompareyieldaccuailastjnletforeach_increasing_runcompareyieldaccua=leti=0andn=lengthainforeach_increasing_run_in_slicecompareyieldaccuainletincreasing_runscomparea=letyieldrunsij=((i,j)::runs)inforeach_increasing_runcompareyield[]a|>List.rev