123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103(******************************************************************************)(* *)(* Fix *)(* *)(* François Pottier, Inria Paris *)(* *)(* Copyright Inria. All rights reserved. This file is distributed under the *)(* terms of the GNU Library General Public License version 2, with a *)(* special exception on linking, as described in the file LICENSE. *)(* *)(******************************************************************************)(* A queue [q] is represented as a circular array of elements, [q.buffer]. The
slots whose logical index lies between [q.first] (inclusive) and [q.first +
q.size] (exclusive) contain the elements of the queue. A logical index must
be normalized modulo [n], where [n] is the length of the array [buffer], to
obtain a physical index. *)(* We maintain the following invariants:
- [n] is zero or a power of two, so as to speed up the [modulo] operation.
- [0 <= q.size <= n] holds. *)type'at={(* The array that stores the elements (as well as empty slots). *)mutablebuffer:'aarray;(* The logical index of the first element. *)mutablefirst:int;(* The number of elements. *)mutablesize:int;}(* The following code iterates on all queued elements:
let n = Array.length q.buffer in
for i = 0 to q.size - 1 do
f q.buffer.((q.first + i) mod n)
done
Because [n] is a power of 2, this is equivalent to:
let n = Array.length q.buffer in
for i = 0 to q.size - 1 do
f q.buffer.((q.first + i) land (n - 1))
done
*)(* The buffer is initially an empty array. Another array is allocated when an
element is inserted. *)letcreate()={buffer=[||];first=0;size=0;}letis_emptyq=q.size=0letaddxq=letbuffer=q.bufferinletn=Array.lengthbufferinifq.size<nthenbegin(* The queue still has room left. *)buffer.((q.first+q.size)land(n-1))<-x;q.size<-q.size+1;endelseifn>0thenbegin(* The buffer is nonempty, and is full. *)(* Allocate a new buffer that is twice larger. *)letbuffer'=Array.make(n*2)xin(* Move all existing elements. *)letfirst=q.firstland(n-1)inArray.blitbufferfirstbuffer'0(n-first);Array.blitbuffer0buffer'(n-first)first;q.buffer<-buffer';q.first<-0;q.size<-n+1;endelsebegin(* The queue has a buffer of size 0. Allocate an array. *)q.buffer<-Array.make8x;q.size<-1;endexceptionEmptylettakeq=ifq.size=0thenraiseEmptyelsebeginq.size<-q.size-1;letn=Array.lengthq.bufferinletresult=q.buffer.(q.firstland(n-1))inq.first<-q.first+1;resultend