Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file CCRingBuffer.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449(* This file is free software, part of containers. See file "license" for more details. *)(* Copyright (C) 2015 Simon Cruanes, Carmelo Piccione *)(** Generic Circular Buffer for IO, with bulk operations.
The bulk operations (e.g. based on {!Array.blit} or {!Bytes.blit})
are more efficient than item-by-item copy.
See https://en.wikipedia.org/wiki/Circular_buffer for an overview. *)moduleArray=struct(** The abstract type for arrays *)moduletypeS=sigtypeelt(** The element type *)typet(** The type of an array instance *)valdummy:elt(** A dummy element used for empty slots in the array
@since 2.4 *)valcreate:int->t(** Make an array of the given size, filled with dummy elements *)vallength:t->int(** [length t] gets the total number of elements currently in [t] *)valget:t->int->elt(** [get t i] gets the element at position [i] *)valset:t->int->elt->unit(** [set t i e] sets the element at position [i] to [e] *)valsub:t->int->int->t(** [sub t i len] gets the subarray of [t] from
position [i] to [i + len] *)valcopy:t->t(** [copy t] makes a fresh copy of the array [t] *)valblit:t->int->t->int->int->unit(** [blit t s arr i len] copies [len] elements from [arr] starting at [i]
to position [s] from [t] *)valiter:(elt->unit)->t->unit(** [iter f t] iterates over the array [t] invoking [f] with
the current element, in array order *)endmoduleByte:Swithtypeelt=charandtypet=Bytes.t=structtypeelt=charletdummy='\x00'includeBytesendmoduleMake(Elt:sigtypetvaldummy:tend):Swithtypeelt=Elt.tandtypet=Elt.tarray=structtypeelt=Elt.ttypet=Elt.tarrayletdummy=Elt.dummyletcreatesize=Array.makesizeElt.dummyletlength=Array.lengthletget=Array.getletset=Array.setletcopy=Array.copyletblit=Array.blitletiter=Array.iterletsub=Array.subendendmoduletypeS=sigmoduleArray:Array.S(** The module type of Array for this ring buffer *)typet(** Defines the bounded ring buffer type *)exceptionEmpty(** Raised in querying functions when the buffer is empty *)valcreate:int->t(** [create size] creates a new bounded buffer with given size.
The underlying array is allocated immediately and no further (large)
allocation will happen from now on.
@raise Invalid_argument if the arguments is [< 1] *)valcopy:t->t(** Make a fresh copy of the buffer. *)valcapacity:t->int(** Length of the inner buffer. *)vallength:t->int(** Number of elements currently stored in the buffer. *)valis_full:t->bool(** true if pushing an element would erase another element.
@since 1.3 *)valblit_from:t->Array.t->int->int->unit(** [blit_from buf from_buf o len] copies the slice [o, ... o + len - 1] from
a input buffer [from_buf] to the end of the buffer.
If the slice is too large for the buffer, only the last part of the array
will be copied.
@raise Invalid_argument if [o,len] is not a valid slice of [s] *)valblit_into:t->Array.t->int->int->int(** [blit_into buf to_buf o len] copies at most [len] elements from [buf]
into [to_buf] starting at offset [o] in [s].
@return the number of elements actually copied ([min len (length buf)]).
@raise Invalid_argument if [o,len] is not a valid slice of [s]. *)valappend:t->into:t->unit(** [append b ~into] copies all data from [b] and adds it at the
end of [into]. Erases data of [into] if there is not enough room. *)valto_list:t->Array.eltlist(** Extract the current content into a list *)valclear:t->unit(** Clear the content of the buffer. Doesn't actually destroy the content. *)valis_empty:t->bool(** Is the buffer empty (i.e. contains no elements)? *)valjunk_front:t->unit(** Drop the front element from [t].
@raise Empty if the buffer is already empty. *)valjunk_back:t->unit(** Drop the back element from [t].
@raise Empty if the buffer is already empty. *)valskip:t->int->unit(** [skip b len] removes [len] elements from the front of [b].
@raise Invalid_argument if [len > length b]. *)valiter:t->f:(Array.elt->unit)->unit(** [iter b ~f] calls [f i t] for each element [t] in [buf] *)valiteri:t->f:(int->Array.elt->unit)->unit(** [iteri b ~f] calls [f i t] for each element [t] in [buf], with [i]
being its relative index within [buf]. *)valget_front:t->int->Array.elt(** [get_front buf i] returns the [i]-th element of [buf] from the front, ie
the one returned by [take_front buf] after [i-1] calls to [junk_front buf].
@raise Invalid_argument if the index is invalid (> [length buf]) *)valget_back:t->int->Array.elt(** [get_back buf i] returns the [i]-th element of [buf] from the back, ie
the one returned by [take_back buf] after [i-1] calls to [junk_back buf].
@raise Invalid_argument if the index is invalid (> [length buf]) *)valpush_back:t->Array.elt->unit(** Push value at the back of [t].
If [t.bounded=false], the buffer will grow as needed,
otherwise the oldest elements are replaced first. *)valpeek_front:t->Array.eltoption(** First value from front of [t], without modification. *)valpeek_front_exn:t->Array.elt(** First value from front of [t], without modification.
@raise Empty if buffer is empty.
@since 1.3 *)valpeek_back:t->Array.eltoption(** Get the last value from back of [t], without modification. *)valpeek_back_exn:t->Array.elt(** Get the last value from back of [t], without modification.
@raise Empty if buffer is empty.
@since 1.3 *)valtake_back:t->Array.eltoption(** Take and remove the last value from back of [t], if any *)valtake_back_exn:t->Array.elt(** Take and remove the last value from back of [t].
@raise Empty if buffer is already empty. *)valtake_front:t->Array.eltoption(** Take and remove the first value from front of [t], if any *)valtake_front_exn:t->Array.elt(** Take and remove the first value from front of [t].
@raise Empty if buffer is already empty. *)valof_array:Array.t->t(** Create a buffer from an initial array, but doesn't take ownership
of it (stills allocates a new internal array)
@since 0.11 *)valto_array:t->Array.t(** Create an array from the elements, in order.
@since 0.11 *)endmoduleMakeFromArray(A:Array.S):SwithmoduleArray=A=structmoduleArray=Atypet={mutablestart:int;mutablestop:int;(* excluded *)buf:Array.t;}exceptionEmptyletcreatesize=ifsize<1theninvalid_arg"CCRingBuffer.create";{start=0;stop=0;buf=A.create(size+1)(* keep room for extra slot *);}letcopyb={bwithbuf=A.copyb.buf}letcapacityb=letlen=A.lengthb.bufinmatchlenwith|0->0|l->l-1letlengthb=ifb.stop>=b.startthenb.stop-b.startelseA.lengthb.buf-b.start+b.stopletis_fullb=lengthb+1=Array.lengthb.bufletnext_bi=letj=i+1inifj=A.lengthb.bufthen0elsejletincr_start_b=b.start<-next_bb.startletincr_stop_b=b.stop<-next_bb.stopletpush_backbe=A.setb.bufb.stope;incr_stop_b;ifb.start=b.stopthenincr_start_b;(* overwritten one element *)()letblit_frombfrom_bufolen=iflen=0then()elseifo+len>A.lengthfrom_buftheninvalid_arg"CCRingBuffer.blit_from"elsefori=otoo+len-1dopush_backb(A.getfrom_bufi)doneletblit_intobto_bufolen=ifo+len>A.lengthto_buftheninvalid_arg"CCRingBuffer.blit_into";ifb.stop>=b.startthen(letn=min(b.stop-b.start)leninA.blitb.bufb.startto_bufon;n)else(letlen_end=A.lengthb.buf-b.startinA.blitb.bufb.startto_bufo(minlen_endlen);iflen_end>=lenthenlen(* done *)else(letn=minb.stop(len-len_end)inA.blitb.buf0to_buf(o+len_end)n;n+len_end))letis_emptyb=b.start=b.stoplettake_front_exnb=ifb.start=b.stopthenraiseEmpty;letc=A.getb.bufb.startinA.setb.bufb.startA.dummy;b.start<-next_bb.start;clettake_frontb=trySome(take_front_exnb)withEmpty->Nonelettake_back_exnb=ifb.start=b.stopthenraiseEmpty;ifb.stop=0thenb.stop<-A.lengthb.buf-1elseb.stop<-b.stop-1;letc=A.getb.bufb.stopinA.setb.bufb.stopA.dummy;clettake_backb=trySome(take_back_exnb)withEmpty->Noneletjunk_frontb=ifb.start=b.stopthenraiseEmpty;A.setb.bufb.startA.dummy;ifb.start+1=A.lengthb.bufthenb.start<-0elseb.start<-b.start+1letjunk_backb=ifb.start=b.stopthenraiseEmpty;ifb.stop=0thenb.stop<-A.lengthb.buf-1elseb.stop<-b.stop-1;A.setb.bufb.stopA.dummyletskipblen=iflen>lengthbtheninvalid_arg"CCRingBuffer.skip";for_=1tolendojunk_frontbdoneletclearb=skipb(lengthb)letiterb~f=ifb.stop>=b.startthenfori=b.starttob.stop-1dof(A.getb.bufi)doneelse(fori=b.starttoA.lengthb.buf-1dof(A.getb.bufi)done;fori=0tob.stop-1dof(A.getb.bufi)done)letiterib~f=ifb.stop>=b.startthenfori=b.starttob.stop-1dofi(A.getb.bufi)doneelse(fori=b.starttoA.lengthb.buf-1dofi(A.getb.bufi)done;fori=0tob.stop-1dofi(A.getb.bufi)done)letgetbi=ifb.stop>=b.startthenifi>=b.stop-b.starttheninvalid_arg"CCRingBuffer.get"elseA.getb.buf(b.start+i)else(letlen_end=A.lengthb.buf-b.startinifi<len_endthenA.getb.buf(b.start+i)elseifi-len_end>b.stoptheninvalid_arg"CCRingBuffer.get"elseA.getb.buf(i-len_end))letget_frontbi=ifis_emptybtheninvalid_arg"CCRingBuffer.get_front"elsegetbiletget_backbi=letoffset=lengthb-i-1inifoffset<0theninvalid_arg"CCRingBuffer.get_back"elsegetboffsetletto_listb=letlen=lengthbinletrecbuildli=ifi<0thenlelsebuild(get_frontbi::l)(i-1)inbuild[](len-1)(* TODO: more efficient version, with one or two blit *)letappendb~into=iterb~f:(push_backinto)letpeek_front_exnb=ifis_emptybthenraiseEmptyelseA.getb.bufb.startletpeek_frontb=trySome(peek_front_exnb)withEmpty->Noneletpeek_back_exnb=ifis_emptybthenraiseEmptyelse(leti=ifb.stop=0thenA.lengthb.buf-1elseb.stop-1inA.getb.bufi)letpeek_backb=trySome(peek_back_exnb)withEmpty->Noneletof_arraya=letb=create(max(A.lengtha)16)inblit_fromba0(A.lengtha);bletto_arrayb=leta=A.create(lengthb)inletn=blit_intoba0(lengthb)inassert(n=lengthb);aendmoduleByte=MakeFromArray(Array.Byte)moduleMake(Elt:sigtypetvaldummy:tend)=MakeFromArray(Array.Make(Elt))