From 472aaa83a21dd58966d7c3c3009391a4f61b074a Mon Sep 17 00:00:00 2001 From: carm Date: Tue, 10 Feb 2015 23:00:09 -0500 Subject: [PATCH 01/32] first cut of a polymorphic buffer --- src/data/CCBufferIO.ml | 108 ++++++++++++++++++---------------------- src/data/CCBufferIO.mli | 77 ++++++++++++++-------------- 2 files changed, 85 insertions(+), 100 deletions(-) diff --git a/src/data/CCBufferIO.ml b/src/data/CCBufferIO.ml index 58264d4f..c71c84a8 100644 --- a/src/data/CCBufferIO.ml +++ b/src/data/CCBufferIO.ml @@ -20,10 +20,11 @@ (** Circular Byte Buffer for IO *) -type t = { +type 'a t = { mutable start : int; mutable stop : int; (* excluded *) - mutable buf : string; + mutable buf : 'a array; + size: int } exception Empty @@ -31,39 +32,35 @@ exception Empty let create size = { start=0; stop=0; - buf =String.make size ' '; + size; + buf = Array.of_list []; } let copy b = - { b with buf=String.copy b.buf; } + { b with buf=Array.copy b.buf; } -let of_string s = - { start=0; - stop=String.length s; - buf=String.copy s; - } -let capacity b = String.length b.buf +let capacity b = b.size let length b = if b.stop >= b.start then b.stop - b.start - else (String.length b.buf - b.start) + b.stop + else (Array.length b.buf - b.start) + b.stop (* resize [b] so that inner capacity is [cap] *) -let resize b cap = - assert (cap >= String.length b.buf); - let buf' = String.make cap ' ' in +let resize b cap elem = + assert (cap >= Array.length b.buf); + let buf' = Array.make cap elem in (* copy into buf' *) let len = if b.stop >= b.start then begin - String.blit b.buf b.start buf' 0 (b.stop - b.start); + Array.blit b.buf b.start buf' 0 (b.stop - b.start); b.stop - b.start end else begin - let len_end = String.length b.buf - b.start in - String.blit b.buf b.start buf' 0 len_end; - String.blit b.buf 0 buf' len_end b.stop; + let len_end = Array.length b.buf - b.start in + Array.blit b.buf b.start buf' 0 len_end; + Array.blit b.buf 0 buf' len_end b.stop; len_end + b.stop end in @@ -72,66 +69,56 @@ let resize b cap = b.stop <- len; () -let blit_from b s o len = +let blit_from b from_buf o len = let cap = capacity b - length b in (* resize if needed, with a constant to amortize *) - if cap < len then resize b (String.length b.buf + len + 24); + if (Array.length from_buf) = 0 then () else + if cap < len then + resize b (Array.length b.buf + len + 24) from_buf.(0); assert (capacity b - length b >= len); if b.stop >= b.start then (* [_______ start xxxxxxxxx stop ______] *) - let len_end = String.length b.buf - b.stop in + let len_end = Array.length b.buf - b.stop in if len_end >= len - then (String.blit s o b.buf b.stop len; + then (Array.blit from_buf o b.buf b.stop len; b.stop <- b.stop + len) - else (String.blit s o b.buf b.stop len_end; - String.blit s (o+len_end) b.buf 0 (len-len_end); + else (Array.blit from_buf o b.buf b.stop len_end; + Array.blit from_buf (o+len_end) b.buf 0 (len-len_end); b.stop <- len-len_end) else begin (* [xxxxx stop ____________ start xxxxxx] *) let len_middle = b.start - b.stop in assert (len_middle >= len); - String.blit s o b.buf b.stop len; + Array.blit from_buf 0 b.buf b.stop len; b.stop <- b.stop + len end; () -let blit_into b s o len = - if o+len > String.length s +let blit_into b to_buf o len = + if o+len > Array.length to_buf then raise (Invalid_argument "BufferIO.blit_into"); if b.stop >= b.start then let n = min (b.stop - b.start) len in - let _ = String.blit b.buf b.start s o n in + let _ = Array.blit b.buf b.start to_buf o n in n else begin - let len_end = String.length b.buf - b.start in - String.blit b.buf b.start s o (min len_end len); + let len_end = Array.length b.buf - b.start in + Array.blit b.buf b.start to_buf o (min len_end len); if len_end >= len then len (* done *) else begin let n = min b.stop (len - len_end) in - String.blit b.buf 0 s (o+len_end) n; + Array.blit b.buf 0 to_buf (o+len_end) n; n + len_end end end -let add_string b s = blit_from b s 0 (String.length s) +let add b s = blit_from b s 0 (Array.length s) (*$Q (Q.pair Q.printable_string Q.printable_string) (fun (s,s') -> \ - let b = create 24 in add_string b s; add_string b s'; \ - String.length s + String.length s' = length b) -*) - -let to_string b = - let s = String.make (length b) ' ' in - let n = blit_into b s 0 (String.length s) in - assert (n = String.length s); - s - -(*$Q - (Q.pair Q.printable_string Q.printable_string) (fun (s,s') -> \ - let b = create 24 in add_string b s; add_string b s'; \ - to_string b = s ^ s') + let b = create 24 in add b s; add_string b s'; \ + Array.length s + String.length s' = length b) *) let clear b = @@ -142,26 +129,26 @@ let clear b = let reset b = clear b; if capacity b > 64 - then b.buf <- String.make 64 ' '; (* reset *) + then b.buf <- Array.sub b.buf 0 64; () let is_empty b = b.start = b.stop let next b = if b.start = b.stop then raise Empty; - b.buf.[b.start] + b.buf.(b.start) let pop b = if b.start = b.stop then raise Empty; - let c = b.buf.[b.start] in - if b.start + 1 = String.length b.buf + let c = b.buf.(b.start) in + if b.start + 1 = Array.length b.buf then b.start <- 0 else b.start <- b.start + 1; c let junk b = if b.start = b.stop then raise Empty; - if b.start + 1 = String.length b.buf + if b.start + 1 = Array.length b.buf then b.start <- 0 else b.start <- b.start + 1 @@ -170,7 +157,7 @@ let skip b len = if b.stop >= b.start then b.start <- b.start + len else - let len_end = String.length b.buf - b.start in + let len_end = Array.length b.buf - b.start in if len > len_end then b.start <- len-len_end (* wrap to the beginning *) else b.start <- b.start + len @@ -185,10 +172,10 @@ let skip b len = let iteri b f = if b.stop >= b.start - then for i = b.start to b.stop - 1 do f i b.buf.[i] done + then for i = b.start to b.stop - 1 do f i b.buf.(i) done else ( - for i = b.start to String.length b.buf -1 do f i b.buf.[i] done; - for i = 0 to b.stop - 1 do f i b.buf.[i] done; + for i = b.start to Array.length b.buf -1 do f i b.buf.(i) done; + for i = 0 to b.stop - 1 do f i b.buf.(i) done; ) (*$T @@ -202,13 +189,14 @@ let get b i = then if i >= b.stop - b.start then raise (Invalid_argument "BufferIO.get") - else b.buf.[b.start + i] + else b.buf.(b.start + i) else - let len_end = String.length b.buf - b.start in + let len_end = Array.length b.buf - b.start in if i < len_end - then b.buf.[b.start + i] + then b.buf.(b.start + i) else if i - len_end > b.stop then raise (Invalid_argument "BufferIO.get") - else b.buf.[i - len_end] - + else b.buf.(i - len_end) +let to_list b = + Array.to_list (Array.sub b.buf b.start b.stop) diff --git a/src/data/CCBufferIO.mli b/src/data/CCBufferIO.mli index c3c12fd4..3c6c4784 100644 --- a/src/data/CCBufferIO.mli +++ b/src/data/CCBufferIO.mli @@ -1,5 +1,5 @@ -(* - * BatBufferIO - Circular byte buffer +(** + * CCBufferIO - Polymorphic Circular Buffer * Copyright (C) 2014 Simon Cruanes * * This library is free software; you can redistribute it and/or @@ -18,79 +18,76 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *) -(** Circular Byte Buffer for IO *) +(** Circular Polymorphic Buffer for IO *) -type t = private { +type 'a t = private { mutable start : int; mutable stop : int; (* excluded *) - mutable buf : string; + mutable buf : 'a array; + size : int } exception Empty -val create : int -> t +val create : int -> 'a t (** [create size] creates a new buffer with given size *) -val copy : t -> t +val copy : 'a t ->'a t (** fresh copy of the buffer *) -val of_string : string -> t -(** build a buffer from an initial string. The string is copied. - Use {!String.blit_from} if you want more control. *) +val capacity : 'a t -> int +(** length of the inner buffer *) -val capacity : t -> int -(** length of the inner string buffer *) +val length : 'a t -> int +(** number of elements currently stored in the buffer *) -val length : t -> int -(** number of bytes currently stored in the buffer *) - -val blit_from : t -> string -> int -> int -> unit -(** [blit_from buf s o len] copies the slice [o, ... o + len - 1] from - the string [s] to the end of the buffer. +val blit_from : 'a t -> 'a array -> 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. @raise Invalid_argument if [o,len] is not a valid slice of [s] *) -val blit_into : t -> string -> int -> int -> int -(** [blit_into buf s o len] copies at most [len] bytes from [buf] - into [s], starting at offset [o] in [s]. - @return the number of bytes actually copied ([min len (length buf)]). +val blit_into : 'a t -> 'a array -> 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] *) -val add_string : t -> string -> unit -(** [add_string buf s] adds [s] at the end of [buf]. *) +val add : 'a t -> 'a array -> unit +(** [add buf t] adds elements [t] at the end of [buf]. *) -val to_string : t -> string -(** extract the current content into a string *) +val to_list : 'a t -> 'a list +(** extract the current content into a list *) -val clear : t -> unit +val clear : 'a t -> unit (** clear the content of the buffer. Doesn't actually destroy the content. *) -val reset : t -> unit +val reset : 'a t -> unit (** clear the content of the buffer, and also resize it to a default size *) -val is_empty : t -> bool -(** is the buffer empty (i.e. contains no byte)? *) +val is_empty :'a t -> bool +(** is the buffer empty (i.e. contains no elements)? *) -val next : t -> char -(** obtain next char (the first one of the buffer) +val next : 'a t -> 'a +(** obtain next element (the first one of the buffer) @raise Empty if the buffer is empty *) -val pop : t -> char -(** obtain and remove next char (the first one) +val pop : 'a t -> 'a +(** obtain and remove next element (the first one) @raise Empty if the buffer is empty *) -val junk : t -> unit +val junk : 'a t -> unit (** Drop next element. @raise Empty if the buffer is already empty *) -val skip : t -> int -> unit +val skip : 'a t -> int -> unit (** [skip b len] removes [len] elements from [b]. @raise Invalid_argument if [len > length b]. *) -val iteri : t -> (int -> char -> unit) -> unit -(** [iteri b f] calls [f i c] for each char [c] in [buf], with [i] +val iteri : 'a t -> (int -> 'a -> unit) -> unit +(** [iteri b f] calls [f i t] for each element [t] in [buf], with [i] being its relative index within [buf]. *) -val get : t -> int -> char -(** [get buf i] returns the [i]-th character of [buf], ie the one that +val get : 'a t -> int -> 'a +(** [get buf i] returns the [i]-th element of [buf], ie the one that is returned by [next buf] after [i-1] calls to [junk buf]. @raise Invalid_argument if the index is invalid (> [length buf]) *) From ae7244f2e3de1e405b7fdb0aa7ee736dc429a8ae Mon Sep 17 00:00:00 2001 From: Carmelo Piccione Date: Tue, 10 Feb 2015 23:01:59 -0500 Subject: [PATCH 02/32] Update ocamldoc --- src/data/CCBufferIO.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data/CCBufferIO.ml b/src/data/CCBufferIO.ml index c71c84a8..170c8934 100644 --- a/src/data/CCBufferIO.ml +++ b/src/data/CCBufferIO.ml @@ -1,5 +1,5 @@ (* - * BatBufferIO - Circular byte buffer + * CCBufferIO - Polymorphic circular buffer * Copyright (C) 2014 Simon Cruanes * * This library is free software; you can redistribute it and/or @@ -18,7 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *) -(** Circular Byte Buffer for IO *) +(** Polymorphic Circular Buffer for IO *) type 'a t = { mutable start : int; From 8fec7b005e4b62ee11b6a850c204da4e5d271e67 Mon Sep 17 00:00:00 2001 From: carm Date: Wed, 11 Feb 2015 11:09:19 -0500 Subject: [PATCH 03/32] wip fixes --- src/data/CCBufferIO.ml | 46 +++++++++++++++++------------------------- 1 file changed, 18 insertions(+), 28 deletions(-) diff --git a/src/data/CCBufferIO.ml b/src/data/CCBufferIO.ml index c71c84a8..abb96ff0 100644 --- a/src/data/CCBufferIO.ml +++ b/src/data/CCBufferIO.ml @@ -40,7 +40,7 @@ let copy b = { b with buf=Array.copy b.buf; } -let capacity b = b.size +let capacity b = Array.length b.buf let length b = if b.stop >= b.start @@ -65,34 +65,20 @@ let resize b cap elem = end in b.buf <- buf'; - b.start <- 0; - b.stop <- len; () let blit_from b from_buf o len = + if (Array.length from_buf) = 0 then () else let cap = capacity b - length b in (* resize if needed, with a constant to amortize *) - if (Array.length from_buf) = 0 then () else - if cap < len then - resize b (Array.length b.buf + len + 24) from_buf.(0); - assert (capacity b - length b >= len); - if b.stop >= b.start - then (* [_______ start xxxxxxxxx stop ______] *) - let len_end = Array.length b.buf - b.stop in - if len_end >= len - then (Array.blit from_buf o b.buf b.stop len; - b.stop <- b.stop + len) - else (Array.blit from_buf o b.buf b.stop len_end; - Array.blit from_buf (o+len_end) b.buf 0 (len-len_end); - b.stop <- len-len_end) - else begin (* [xxxxx stop ____________ start xxxxxx] *) - let len_middle = b.start - b.stop in - assert (len_middle >= len); - Array.blit from_buf 0 b.buf b.stop len; - b.stop <- b.stop + len - end; - () - + if capacity b < b.size then + resize b b.size from_buf.(0); + let sub = Array.sub from_buf o len in + let iter i x = + b.start <- i mod capacity b; + Array.set b.buf x b.start in + Array.iteri iter sub + let blit_into b to_buf o len = if o+len > Array.length to_buf then raise (Invalid_argument "BufferIO.blit_into"); @@ -128,9 +114,7 @@ let clear b = let reset b = clear b; - if capacity b > 64 - then b.buf <- Array.sub b.buf 0 64; - () + b.buf <- Array.of_list [] let is_empty b = b.start = b.stop @@ -199,4 +183,10 @@ let get b i = else b.buf.(i - len_end) let to_list b = - Array.to_list (Array.sub b.buf b.start b.stop) + if (b.stop >= b.start) + then Array.to_list (Array.sub b.buf b.start b.stop) + else List.append + (Array.to_list (Array.sub b.buf b.start (Array.length b.buf))) + (Array.to_list (Array.sub b.buf 0 b.stop)) + + From acd1b6e97e5ad052dc0bad5cd9a078b0afd6790f Mon Sep 17 00:00:00 2001 From: carm Date: Wed, 11 Feb 2015 23:08:12 -0500 Subject: [PATCH 04/32] put back more advanced resize heuristic --- src/data/CCBufferIO.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data/CCBufferIO.ml b/src/data/CCBufferIO.ml index 8207540b..91ccd026 100644 --- a/src/data/CCBufferIO.ml +++ b/src/data/CCBufferIO.ml @@ -71,8 +71,8 @@ let blit_from b from_buf o len = if (Array.length from_buf) = 0 then () else let cap = capacity b - length b in (* resize if needed, with a constant to amortize *) - if capacity b < b.size then - resize b b.size from_buf.(0); + if cap < len then + resize b (min b.size (Array.length b.buf + len + 24)) from_buf.(0); let sub = Array.sub from_buf o len in let iter i x = b.start <- i mod capacity b; From 7d92950a4ef17eb3c99b639faafd91cebae2d547 Mon Sep 17 00:00:00 2001 From: carm Date: Thu, 12 Feb 2015 00:20:28 -0500 Subject: [PATCH 05/32] working polymorphic ring buffer --- src/data/CCBufferIO.ml | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/data/CCBufferIO.ml b/src/data/CCBufferIO.ml index 91ccd026..1778ed00 100644 --- a/src/data/CCBufferIO.ml +++ b/src/data/CCBufferIO.ml @@ -52,7 +52,7 @@ let resize b cap elem = assert (cap >= Array.length b.buf); let buf' = Array.make cap elem in (* copy into buf' *) - let len = + let _:int = if b.stop >= b.start then begin Array.blit b.buf b.start buf' 0 (b.stop - b.start); @@ -64,20 +64,23 @@ let resize b cap elem = len_end + b.stop end in - b.buf <- buf'; - () + b.buf <- buf' let blit_from b from_buf o len = if (Array.length from_buf) = 0 then () else let cap = capacity b - length b in (* resize if needed, with a constant to amortize *) if cap < len then - resize b (min b.size (Array.length b.buf + len + 24)) from_buf.(0); + resize b (min (b.size+1) (Array.length b.buf + len + 24)) from_buf.(0); let sub = Array.sub from_buf o len in - let iter i x = - b.start <- i mod capacity b; - Array.set b.buf x b.start in - Array.iteri iter sub + let iter x = + if b.start = 0 then b.start <- capacity b - 1 else b.start <- b.start - 1; + if b.start = b.stop then + begin + if b.stop = 0 then b.stop <- capacity b - 1 else b.stop <- b.stop - 1 + end; + Array.set b.buf b.start x in + Array.iter iter sub let blit_into b to_buf o len = if o+len > Array.length to_buf @@ -184,9 +187,9 @@ let get b i = let to_list b = if (b.stop >= b.start) - then Array.to_list (Array.sub b.buf b.start b.stop) + then Array.to_list (Array.sub b.buf b.start (b.stop-b.start)) else List.append - (Array.to_list (Array.sub b.buf b.start (Array.length b.buf))) + (Array.to_list (Array.sub b.buf b.start (Array.length b.buf - b.start))) (Array.to_list (Array.sub b.buf 0 b.stop)) From 4a994cff388ce532569f4ce0bc1b6d2ac9898120 Mon Sep 17 00:00:00 2001 From: carm Date: Fri, 13 Feb 2015 19:00:04 -0500 Subject: [PATCH 06/32] rename buffer io to ring buffer --- _oasis | 2 +- src/data/{CCBufferIO.ml => CCRingBuffer.ml} | 4 +++- src/data/{CCBufferIO.mli => CCRingBuffer.mli} | 0 3 files changed, 4 insertions(+), 2 deletions(-) rename src/data/{CCBufferIO.ml => CCRingBuffer.ml} (97%) rename src/data/{CCBufferIO.mli => CCRingBuffer.mli} (100%) diff --git a/_oasis b/_oasis index 5338b481..bdf8be95 100644 --- a/_oasis +++ b/_oasis @@ -70,7 +70,7 @@ Library "containers_data" Path: src/data Modules: CCMultiMap, CCMultiSet, CCTrie, CCFlatHashtbl, CCCache, CCPersistentHashtbl, CCDeque, CCFQueue, CCBV, CCMixtbl, - CCBufferIO + CCRingBuffer FindlibParent: containers FindlibName: data diff --git a/src/data/CCBufferIO.ml b/src/data/CCRingBuffer.ml similarity index 97% rename from src/data/CCBufferIO.ml rename to src/data/CCRingBuffer.ml index 1778ed00..8616c37c 100644 --- a/src/data/CCBufferIO.ml +++ b/src/data/CCRingBuffer.ml @@ -1,5 +1,7 @@ (* - * CCBufferIO - Polymorphic circular buffer + * CCRingBufferIO - Polymorphic circular buffer with + * deque semantics for accessing both the head and tail. + * * Copyright (C) 2014 Simon Cruanes * * This library is free software; you can redistribute it and/or diff --git a/src/data/CCBufferIO.mli b/src/data/CCRingBuffer.mli similarity index 100% rename from src/data/CCBufferIO.mli rename to src/data/CCRingBuffer.mli From 2cf485ebee94571e71c2d6b92f681a40ffa21ddb Mon Sep 17 00:00:00 2001 From: carm Date: Fri, 13 Feb 2015 19:21:46 -0500 Subject: [PATCH 07/32] support for unbounded ring buffer --- src/data/CCRingBuffer.ml | 12 +++++++----- src/data/CCRingBuffer.mli | 10 +++++++--- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/data/CCRingBuffer.ml b/src/data/CCRingBuffer.ml index 8616c37c..67ec5798 100644 --- a/src/data/CCRingBuffer.ml +++ b/src/data/CCRingBuffer.ml @@ -26,16 +26,16 @@ type 'a t = { mutable start : int; mutable stop : int; (* excluded *) mutable buf : 'a array; - size: int + max_capacity: int } exception Empty -let create size = +let create ?(max_capacity=max_int) () = { start=0; stop=0; - size; - buf = Array.of_list []; + max_capacity; + buf = Array.of_list [] } let copy b = @@ -44,6 +44,8 @@ let copy b = let capacity b = Array.length b.buf +let max_capacity b = b.max_capacity + let length b = if b.stop >= b.start then b.stop - b.start @@ -73,7 +75,7 @@ let blit_from b from_buf o len = let cap = capacity b - length b in (* resize if needed, with a constant to amortize *) if cap < len then - resize b (min (b.size+1) (Array.length b.buf + len + 24)) from_buf.(0); + resize b (min (b.max_capacity+1) (Array.length b.buf + len + 24)) from_buf.(0); let sub = Array.sub from_buf o len in let iter x = if b.start = 0 then b.start <- capacity b - 1 else b.start <- b.start - 1; diff --git a/src/data/CCRingBuffer.mli b/src/data/CCRingBuffer.mli index 3c6c4784..f717879c 100644 --- a/src/data/CCRingBuffer.mli +++ b/src/data/CCRingBuffer.mli @@ -24,13 +24,14 @@ type 'a t = private { mutable start : int; mutable stop : int; (* excluded *) mutable buf : 'a array; - size : int + max_capacity : int } exception Empty -val create : int -> 'a t -(** [create size] creates a new buffer with given size *) +val create : ?max_capacity:int -> unit -> 'a t +(** [create ~max_capacity ()] creates a new buffer with given maximum capacity. + Defaults to unbounded. *) val copy : 'a t ->'a t (** fresh copy of the buffer *) @@ -38,6 +39,9 @@ val copy : 'a t ->'a t val capacity : 'a t -> int (** length of the inner buffer *) +val max_capacity : 'a t -> int +(** maximum length of the inner buffer *) + val length : 'a t -> int (** number of elements currently stored in the buffer *) From a43145b10790934577c0d751d39bfcdb8edc1e80 Mon Sep 17 00:00:00 2001 From: carm Date: Fri, 13 Feb 2015 20:08:13 -0500 Subject: [PATCH 08/32] bounded/unbounded versions of blit_from --- src/data/CCRingBuffer.ml | 62 +++++++++++++++++++++++++++++++-------- src/data/CCRingBuffer.mli | 13 ++++---- 2 files changed, 56 insertions(+), 19 deletions(-) diff --git a/src/data/CCRingBuffer.ml b/src/data/CCRingBuffer.ml index 67ec5798..ad13c2e5 100644 --- a/src/data/CCRingBuffer.ml +++ b/src/data/CCRingBuffer.ml @@ -26,15 +26,17 @@ type 'a t = { mutable start : int; mutable stop : int; (* excluded *) mutable buf : 'a array; - max_capacity: int + bounded : bool; + size : int } exception Empty -let create ?(max_capacity=max_int) () = +let create ?(bounded=false) size = { start=0; stop=0; - max_capacity; + bounded; + size; buf = Array.of_list [] } @@ -44,7 +46,7 @@ let copy b = let capacity b = Array.length b.buf -let max_capacity b = b.max_capacity +let max_capacity b = if b.bounded then Some b.size else None let length b = if b.stop >= b.start @@ -70,22 +72,56 @@ let resize b cap elem = in b.buf <- buf' -let blit_from b from_buf o len = - if (Array.length from_buf) = 0 then () else - let cap = capacity b - length b in +let blit_from_bounded b from_buf o len = + let cap = capacity b - len in (* resize if needed, with a constant to amortize *) if cap < len then - resize b (min (b.max_capacity+1) (Array.length b.buf + len + 24)) from_buf.(0); + let new_size = + let desired = Array.length b.buf + len + 24 in + min (b.size+1) desired in + resize b new_size from_buf.(0); let sub = Array.sub from_buf o len in + let capacity = capacity b in let iter x = - if b.start = 0 then b.start <- capacity b - 1 else b.start <- b.start - 1; + Array.set b.buf b.stop x; + if b.stop = capacity-1 then b.stop <- 0 else b.stop <- b.stop + 1; if b.start = b.stop then - begin - if b.stop = 0 then b.stop <- capacity b - 1 else b.stop <- b.stop - 1 - end; - Array.set b.buf b.start x in + begin + if b.start = capacity-1 then b.start <- 0 else b.start <- b.start + 1 + end + in Array.iter iter sub + +let blit_from_unbounded b from_buf o len = + let cap = capacity b - len in + (* resize if needed, with a constant to amortize *) + if cap < len then resize b (max b.size (Array.length b.buf + len + 24)) from_buf.(0); + assert (capacity b - length b >= len); + if b.stop >= b.start + then (* [_______ start xxxxxxxxx stop ______] *) + let len_end = Array.length b.buf - b.stop in + if len_end >= len + then (Array.blit from_buf o b.buf b.stop len; + b.stop <- b.stop + len) + else (Array.blit from_buf o b.buf b.stop len_end; + Array.blit from_buf (o+len_end) b.buf 0 (len-len_end); + b.stop <- len-len_end) + else begin (* [xxxxx stop ____________ start xxxxxx] *) + let len_middle = b.start - b.stop in + assert (len_middle >= len); + Array.blit from_buf o b.buf b.stop len; + b.stop <- b.stop + len + end; + () + +let blit_from b from_buf o len = + if (Array.length from_buf) = 0 then () else + if b.bounded then + blit_from_bounded b from_buf o len + else + blit_from_unbounded b from_buf o len + let blit_into b to_buf o len = if o+len > Array.length to_buf then raise (Invalid_argument "BufferIO.blit_into"); diff --git a/src/data/CCRingBuffer.mli b/src/data/CCRingBuffer.mli index f717879c..b7b409e6 100644 --- a/src/data/CCRingBuffer.mli +++ b/src/data/CCRingBuffer.mli @@ -24,14 +24,15 @@ type 'a t = private { mutable start : int; mutable stop : int; (* excluded *) mutable buf : 'a array; - max_capacity : int + bounded: bool; + size : int } exception Empty -val create : ?max_capacity:int -> unit -> 'a t -(** [create ~max_capacity ()] creates a new buffer with given maximum capacity. - Defaults to unbounded. *) +val create : ?bounded:bool -> int -> 'a t +(** [create ?bounded size] creates a new buffer with given size. + Defaults to [bounded=false]. *) val copy : 'a t ->'a t (** fresh copy of the buffer *) @@ -39,8 +40,8 @@ val copy : 'a t ->'a t val capacity : 'a t -> int (** length of the inner buffer *) -val max_capacity : 'a t -> int -(** maximum length of the inner buffer *) +val max_capacity : 'a t -> int option +(** maximum length of the inner buffer, or [None] if unbounded. *) val length : 'a t -> int (** number of elements currently stored in the buffer *) From 07f0afcd28fbd8d44176b6cd02722599b09fa7a7 Mon Sep 17 00:00:00 2001 From: carm Date: Sat, 14 Feb 2015 08:31:54 -0500 Subject: [PATCH 09/32] add deque style functions to ring buffer module, bug fixes --- src/data/CCRingBuffer.ml | 46 ++++++++++++++++++++++++++++----------- src/data/CCRingBuffer.mli | 24 ++++++++++++++------ 2 files changed, 50 insertions(+), 20 deletions(-) diff --git a/src/data/CCRingBuffer.ml b/src/data/CCRingBuffer.ml index ad13c2e5..57fc189d 100644 --- a/src/data/CCRingBuffer.ml +++ b/src/data/CCRingBuffer.ml @@ -1,5 +1,5 @@ (* - * CCRingBufferIO - Polymorphic circular buffer with + * CCRingBuffer - Polymorphic circular buffer with * deque semantics for accessing both the head and tail. * * Copyright (C) 2014 Simon Cruanes @@ -75,22 +75,23 @@ let resize b cap elem = let blit_from_bounded b from_buf o len = let cap = capacity b - len in (* resize if needed, with a constant to amortize *) - if cap < len then + if cap < len then begin let new_size = let desired = Array.length b.buf + len + 24 in min (b.size+1) desired in - resize b new_size from_buf.(0); + resize b new_size from_buf.(0) + end; let sub = Array.sub from_buf o len in - let capacity = capacity b in - let iter x = - Array.set b.buf b.stop x; - if b.stop = capacity-1 then b.stop <- 0 else b.stop <- b.stop + 1; - if b.start = b.stop then + let iter x = + let capacity = capacity b in + Array.set b.buf b.stop x; + if b.stop = capacity-1 then b.stop <- 0 else b.stop <- b.stop + 1; + if b.start = b.stop then begin - if b.start = capacity-1 then b.start <- 0 else b.start <- b.start + 1 + if b.start = capacity-1 then b.start <- 0 else b.start <- b.start + 1 end - in - Array.iter iter sub + in + Array.iter iter sub let blit_from_unbounded b from_buf o len = @@ -117,7 +118,7 @@ let blit_from_unbounded b from_buf o len = let blit_from b from_buf o len = if (Array.length from_buf) = 0 then () else - if b.bounded then + if b.bounded then blit_from_bounded b from_buf o len else blit_from_unbounded b from_buf o len @@ -165,7 +166,7 @@ let next b = if b.start = b.stop then raise Empty; b.buf.(b.start) -let pop b = +let take_front b = if b.start = b.stop then raise Empty; let c = b.buf.(b.start) in if b.start + 1 = Array.length b.buf @@ -173,6 +174,13 @@ let pop b = else b.start <- b.start + 1; c +let take_back b = + if b.start = b.stop then raise Empty; + if b.stop - 1 = 0 + then b.stop <- Array.length b.buf - 1 + else b.stop <- b.stop - 1; + b.buf.(b.stop) + let junk b = if b.start = b.stop then raise Empty; if b.start + 1 = Array.length b.buf @@ -232,4 +240,16 @@ let to_list b = (Array.to_list (Array.sub b.buf b.start (Array.length b.buf - b.start))) (Array.to_list (Array.sub b.buf 0 b.stop)) +let push_back b e = add b (Array.of_list [e]) + +let peek_front b = if is_empty b then + raise Empty else Array.get b.buf b.start + +let peek_back b = if is_empty b then + raise Empty else Array.get b.buf + (if b.stop = 0 then capacity b - 1 else b.stop-1) + + + + diff --git a/src/data/CCRingBuffer.mli b/src/data/CCRingBuffer.mli index b7b409e6..6ec2d42a 100644 --- a/src/data/CCRingBuffer.mli +++ b/src/data/CCRingBuffer.mli @@ -57,9 +57,6 @@ val blit_into : 'a t -> 'a array -> int -> int -> int @return the number of elements actually copied ([min len (length buf)]). @raise Invalid_argument if [o,len] is not a valid slice of [s] *) -val add : 'a t -> 'a array -> unit -(** [add buf t] adds elements [t] at the end of [buf]. *) - val to_list : 'a t -> 'a list (** extract the current content into a list *) @@ -76,10 +73,6 @@ val next : 'a t -> 'a (** obtain next element (the first one of the buffer) @raise Empty if the buffer is empty *) -val pop : 'a t -> 'a -(** obtain and remove next element (the first one) - @raise Empty if the buffer is empty *) - val junk : 'a t -> unit (** Drop next element. @raise Empty if the buffer is already empty *) @@ -96,3 +89,20 @@ val get : 'a t -> int -> 'a (** [get buf i] returns the [i]-th element of [buf], ie the one that is returned by [next buf] after [i-1] calls to [junk buf]. @raise Invalid_argument if the index is invalid (> [length buf]) *) + +val push_back : 'a t -> 'a -> unit + (** Push value at the back *) + +val peek_front : 'a t -> 'a + (** First value, or Empty *) + +val peek_back : 'a t -> 'a + (** Last value, or Empty *) + +val take_back : 'a t -> 'a + (** Take last value, or raise Empty *) + +val take_front : 'a t -> 'a + (** Take first value, or raise Empty *) + + From c7607f8ce774f7b2c4012c17554c1cdf0f12d767 Mon Sep 17 00:00:00 2001 From: carm Date: Mon, 16 Feb 2015 00:19:17 -0500 Subject: [PATCH 10/32] functorize ring buffer over ARRAY sig --- src/data/CCRingBuffer.ml | 393 ++++++++++++++++++++------------------ src/data/CCRingBuffer.mli | 142 ++++++++------ 2 files changed, 291 insertions(+), 244 deletions(-) diff --git a/src/data/CCRingBuffer.ml b/src/data/CCRingBuffer.ml index 57fc189d..91743f41 100644 --- a/src/data/CCRingBuffer.ml +++ b/src/data/CCRingBuffer.ml @@ -22,234 +22,255 @@ (** Polymorphic Circular Buffer for IO *) -type 'a t = { - mutable start : int; - mutable stop : int; (* excluded *) - mutable buf : 'a array; - bounded : bool; - size : int -} +module type ARRAY = sig + type elt + type t -exception Empty + val make: int -> elt -> t + val length: t -> int -let create ?(bounded=false) size = - { start=0; - stop=0; - bounded; - size; - buf = Array.of_list [] + val get: t -> int -> elt + + val set: t -> int -> elt -> unit + + val sub: t -> int -> int -> t + val max_length: int + + val copy : t -> t + val of_list : elt list -> t + val to_list : t -> elt list + val blit : t -> int -> t -> int -> int -> unit + + val iter : (elt -> unit) -> t -> unit +end + +module Make(Array:ARRAY) = +struct + + type t = { + mutable start : int; + mutable stop : int; (* excluded *) + mutable buf : Array.t; + bounded : bool; + size : int } -let copy b = - { b with buf=Array.copy b.buf; } + exception Empty + + let create ?(bounded=false) size = + { start=0; + stop=0; + bounded; + size; + buf = Array.of_list [] + } + + let copy b = + { b with buf=Array.copy b.buf; } -let capacity b = Array.length b.buf + let capacity b = Array.length b.buf -let max_capacity b = if b.bounded then Some b.size else None + let max_capacity b = if b.bounded then Some b.size else None -let length b = - if b.stop >= b.start - then b.stop - b.start - else (Array.length b.buf - b.start) + b.stop - -(* resize [b] so that inner capacity is [cap] *) -let resize b cap elem = - assert (cap >= Array.length b.buf); - let buf' = Array.make cap elem in - (* copy into buf' *) - let _:int = + let length b = if b.stop >= b.start - then begin - Array.blit b.buf b.start buf' 0 (b.stop - b.start); - b.stop - b.start - end else begin - let len_end = Array.length b.buf - b.start in - Array.blit b.buf b.start buf' 0 len_end; - Array.blit b.buf 0 buf' len_end b.stop; - len_end + b.stop - end - in - b.buf <- buf' + then b.stop - b.start + else (Array.length b.buf - b.start) + b.stop -let blit_from_bounded b from_buf o len = - let cap = capacity b - len in - (* resize if needed, with a constant to amortize *) - if cap < len then begin - let new_size = - let desired = Array.length b.buf + len + 24 in - min (b.size+1) desired in - resize b new_size from_buf.(0) - end; - let sub = Array.sub from_buf o len in - let iter x = - let capacity = capacity b in - Array.set b.buf b.stop x; - if b.stop = capacity-1 then b.stop <- 0 else b.stop <- b.stop + 1; - if b.start = b.stop then - begin - if b.start = capacity-1 then b.start <- 0 else b.start <- b.start + 1 + (* resize [b] so that inner capacity is [cap] *) + let resize b cap elem = + assert (cap >= Array.length b.buf); + let buf' = Array.make cap elem in + (* copy into buf' *) + let _:int = + if b.stop >= b.start + then begin + Array.blit b.buf b.start buf' 0 (b.stop - b.start); + b.stop - b.start + end else begin + let len_end = Array.length b.buf - b.start in + Array.blit b.buf b.start buf' 0 len_end; + Array.blit b.buf 0 buf' len_end b.stop; + len_end + b.stop end - in - Array.iter iter sub - + in + b.buf <- buf' -let blit_from_unbounded b from_buf o len = - let cap = capacity b - len in - (* resize if needed, with a constant to amortize *) - if cap < len then resize b (max b.size (Array.length b.buf + len + 24)) from_buf.(0); - assert (capacity b - length b >= len); - if b.stop >= b.start - then (* [_______ start xxxxxxxxx stop ______] *) - let len_end = Array.length b.buf - b.stop in - if len_end >= len - then (Array.blit from_buf o b.buf b.stop len; - b.stop <- b.stop + len) - else (Array.blit from_buf o b.buf b.stop len_end; - Array.blit from_buf (o+len_end) b.buf 0 (len-len_end); - b.stop <- len-len_end) - else begin (* [xxxxx stop ____________ start xxxxxx] *) - let len_middle = b.start - b.stop in - assert (len_middle >= len); - Array.blit from_buf o b.buf b.stop len; - b.stop <- b.stop + len - end; - () + let blit_from_bounded b from_buf o len = + let cap = capacity b - len in + (* resize if needed, with a constant to amortize *) + if cap < len then begin + let new_size = + let desired = Array.length b.buf + len + 24 in + min (b.size+1) desired in + resize b new_size from_buf.(0) + end; + let sub = Array.sub from_buf o len in + let iter x = + let capacity = capacity b in + Array.set b.buf b.stop x; + if b.stop = capacity-1 then b.stop <- 0 else b.stop <- b.stop + 1; + if b.start = b.stop then + begin + if b.start = capacity-1 then b.start <- 0 else b.start <- b.start + 1 + end + in + Array.iter iter sub -let blit_from b from_buf o len = - if (Array.length from_buf) = 0 then () else - if b.bounded then - blit_from_bounded b from_buf o len - else - blit_from_unbounded b from_buf o len -let blit_into b to_buf o len = - if o+len > Array.length to_buf + let blit_from_unbounded b from_buf o len = + let cap = capacity b - len in + (* resize if needed, with a constant to amortize *) + if cap < len then resize b (max b.size (Array.length b.buf + len + 24)) from_buf.(0); + assert (capacity b - length b >= len); + if b.stop >= b.start + then (* [_______ start xxxxxxxxx stop ______] *) + let len_end = Array.length b.buf - b.stop in + if len_end >= len + then (Array.blit from_buf o b.buf b.stop len; + b.stop <- b.stop + len) + else (Array.blit from_buf o b.buf b.stop len_end; + Array.blit from_buf (o+len_end) b.buf 0 (len-len_end); + b.stop <- len-len_end) + else begin (* [xxxxx stop ____________ start xxxxxx] *) + let len_middle = b.start - b.stop in + assert (len_middle >= len); + Array.blit from_buf o b.buf b.stop len; + b.stop <- b.stop + len + end; + () + + let blit_from b from_buf o len = + if (Array.length from_buf) = 0 then () else + if b.bounded then + blit_from_bounded b from_buf o len + else + blit_from_unbounded b from_buf o len + + let blit_into b to_buf o len = + if o+len > Array.length to_buf then raise (Invalid_argument "BufferIO.blit_into"); - if b.stop >= b.start - then - let n = min (b.stop - b.start) len in - let _ = Array.blit b.buf b.start to_buf o n in - n - else begin - let len_end = Array.length b.buf - b.start in - Array.blit b.buf b.start to_buf o (min len_end len); - if len_end >= len - then len (* done *) + if b.stop >= b.start + then + let n = min (b.stop - b.start) len in + let _ = Array.blit b.buf b.start to_buf o n in + n else begin - let n = min b.stop (len - len_end) in - Array.blit b.buf 0 to_buf (o+len_end) n; - n + len_end + let len_end = Array.length b.buf - b.start in + Array.blit b.buf b.start to_buf o (min len_end len); + if len_end >= len + then len (* done *) + else begin + let n = min b.stop (len - len_end) in + Array.blit b.buf 0 to_buf (o+len_end) n; + n + len_end + end end - end -let add b s = blit_from b s 0 (Array.length s) + let add b s = blit_from b s 0 (Array.length s) -(*$Q - (Q.pair Q.printable_string Q.printable_string) (fun (s,s') -> \ + (*$Q + (Q.pair Q.printable_string Q.printable_string) (fun (s,s') -> \ let b = create 24 in add b s; add_string b s'; \ Array.length s + String.length s' = length b) -*) + *) -let clear b = - b.stop <- 0; - b.start <- 0; - () + let clear b = + b.stop <- 0; + b.start <- 0; + () -let reset b = - clear b; - b.buf <- Array.of_list [] + let reset b = + clear b; + b.buf <- Array.of_list [] -let is_empty b = b.start = b.stop + let is_empty b = b.start = b.stop -let next b = - if b.start = b.stop then raise Empty; - b.buf.(b.start) + let next b = + if b.start = b.stop then raise Empty; + b.buf.(b.start) -let take_front b = - if b.start = b.stop then raise Empty; - let c = b.buf.(b.start) in - if b.start + 1 = Array.length b.buf - then b.start <- 0 - else b.start <- b.start + 1; - c + let take_front b = + if b.start = b.stop then raise Empty; + let c = b.buf.(b.start) in + if b.start + 1 = Array.length b.buf + then b.start <- 0 + else b.start <- b.start + 1; + c -let take_back b = - if b.start = b.stop then raise Empty; - if b.stop - 1 = 0 - then b.stop <- Array.length b.buf - 1 - else b.stop <- b.stop - 1; - b.buf.(b.stop) + let take_back b = + if b.start = b.stop then raise Empty; + if b.stop - 1 = 0 + then b.stop <- Array.length b.buf - 1 + else b.stop <- b.stop - 1; + b.buf.(b.stop) -let junk b = - if b.start = b.stop then raise Empty; - if b.start + 1 = Array.length b.buf - then b.start <- 0 - else b.start <- b.start + 1 + let junk b = + if b.start = b.stop then raise Empty; + if b.start + 1 = Array.length b.buf + then b.start <- 0 + else b.start <- b.start + 1 -let skip b len = - if len > length b then raise (Invalid_argument "BufferIO.skip"); - if b.stop >= b.start - then b.start <- b.start + len - else - let len_end = Array.length b.buf - b.start in - if len > len_end - then b.start <- len-len_end (* wrap to the beginning *) - else b.start <- b.start + len + let skip b len = + if len > length b then raise (Invalid_argument "BufferIO.skip"); + if b.stop >= b.start + then b.start <- b.start + len + else + let len_end = Array.length b.buf - b.start in + if len > len_end + then b.start <- len-len_end (* wrap to the beginning *) + else b.start <- b.start + len -(*$Q - (Q.pair Q.printable_string Q.printable_string) (fun (s,s') -> \ + (*$Q + (Q.pair Q.printable_string Q.printable_string) (fun (s,s') -> \ let b = create 24 in add_string b s; add_string b s'; \ add_string b "hello world"; (* big enough *) \ let l = length b in let l' = l/2 in skip b l'; \ length b + l' = l) -*) + *) -let iteri b f = - if b.stop >= b.start - then for i = b.start to b.stop - 1 do f i b.buf.(i) done - else ( - for i = b.start to Array.length b.buf -1 do f i b.buf.(i) done; - for i = 0 to b.stop - 1 do f i b.buf.(i) done; - ) + let iteri b f = + if b.stop >= b.start + then for i = b.start to b.stop - 1 do f i b.buf.(i) done + else ( + for i = b.start to Array.length b.buf -1 do f i b.buf.(i) done; + for i = 0 to b.stop - 1 do f i b.buf.(i) done; + ) -(*$T - let s = "hello world" in \ - let b = of_string s in \ - try iteri b (fun i c -> if s.[i] <> c then raise Exit); true with Exit -> false -*) + (*$T + let s = "hello world" in \ + let b = of_string s in \ + try iteri b (fun i c -> if s.[i] <> c then raise Exit); true with Exit -> false + *) -let get b i = - if b.stop >= b.start - then - if i >= b.stop - b.start - then raise (Invalid_argument "BufferIO.get") - else b.buf.(b.start + i) - else - let len_end = Array.length b.buf - b.start in - if i < len_end + let get b i = + if b.stop >= b.start + then + if i >= b.stop - b.start + then raise (Invalid_argument "BufferIO.get") + else b.buf.(b.start + i) + else + let len_end = Array.length b.buf - b.start in + if i < len_end then b.buf.(b.start + i) - else if i - len_end > b.stop + else if i - len_end > b.stop then raise (Invalid_argument "BufferIO.get") else b.buf.(i - len_end) -let to_list b = - if (b.stop >= b.start) + let to_list b = + if (b.stop >= b.start) then Array.to_list (Array.sub b.buf b.start (b.stop-b.start)) - else List.append - (Array.to_list (Array.sub b.buf b.start (Array.length b.buf - b.start))) - (Array.to_list (Array.sub b.buf 0 b.stop)) - -let push_back b e = add b (Array.of_list [e]) - -let peek_front b = if is_empty b then - raise Empty else Array.get b.buf b.start - -let peek_back b = if is_empty b then - raise Empty else Array.get b.buf - (if b.stop = 0 then capacity b - 1 else b.stop-1) - - + else List.append + (Array.to_list (Array.sub b.buf b.start (Array.length b.buf - b.start))) + (Array.to_list (Array.sub b.buf 0 b.stop)) + let push_back b e = add b (Array.of_list [e]) + let peek_front b = if is_empty b then + raise Empty else Array.get b.buf b.start + let peek_back b = if is_empty b then + raise Empty else Array.get b.buf + (if b.stop = 0 then capacity b - 1 else b.stop-1) +end diff --git a/src/data/CCRingBuffer.mli b/src/data/CCRingBuffer.mli index 6ec2d42a..bc405f43 100644 --- a/src/data/CCRingBuffer.mli +++ b/src/data/CCRingBuffer.mli @@ -20,89 +20,115 @@ (** Circular Polymorphic Buffer for IO *) -type 'a t = private { - mutable start : int; - mutable stop : int; (* excluded *) - mutable buf : 'a array; - bounded: bool; - size : int -} +module type ARRAY = sig + type elt + type t -exception Empty + val make: int -> elt -> t + val length: t -> int -val create : ?bounded:bool -> int -> 'a t -(** [create ?bounded size] creates a new buffer with given size. - Defaults to [bounded=false]. *) + val get: t -> int -> elt -val copy : 'a t ->'a t -(** fresh copy of the buffer *) + val set: t -> int -> elt -> unit -val capacity : 'a t -> int -(** length of the inner buffer *) + val sub: t -> int -> int -> t + val max_length: int -val max_capacity : 'a t -> int option -(** maximum length of the inner buffer, or [None] if unbounded. *) + val copy : t -> t + val of_list : elt list -> t + val to_list : t -> elt list + val blit : t -> int -> t -> int -> int -> unit -val length : 'a t -> int -(** number of elements currently stored in the buffer *) + val iter : (elt -> unit) -> t -> unit +end -val blit_from : 'a t -> 'a array -> 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. - @raise Invalid_argument if [o,len] is not a valid slice of [s] *) -val blit_into : 'a t -> 'a array -> 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] *) +module Make : functor (Array:ARRAY) -> +sig -val to_list : 'a t -> 'a list -(** extract the current content into a list *) + type t = private { + mutable start : int; + mutable stop : int; (* excluded *) + mutable buf : Array.t; + bounded: bool; + size : int + } -val clear : 'a t -> unit -(** clear the content of the buffer. Doesn't actually destroy the content. *) + exception Empty -val reset : 'a t -> unit -(** clear the content of the buffer, and also resize it to a default size *) + val create : ?bounded:bool -> int -> t + (** [create ?bounded size] creates a new buffer with given size. + Defaults to [bounded=false]. *) -val is_empty :'a t -> bool -(** is the buffer empty (i.e. contains no elements)? *) + val copy : t -> t + (** fresh copy of the buffer *) -val next : 'a t -> 'a -(** obtain next element (the first one of the buffer) - @raise Empty if the buffer is empty *) + val capacity : t -> int + (** length of the inner buffer *) -val junk : 'a t -> unit -(** Drop next element. - @raise Empty if the buffer is already empty *) + val max_capacity : t -> int option + (** maximum length of the inner buffer, or [None] if unbounded. *) -val skip : 'a t -> int -> unit -(** [skip b len] removes [len] elements from [b]. - @raise Invalid_argument if [len > length b]. *) + val length : t -> int + (** number of elements currently stored in the buffer *) -val iteri : 'a t -> (int -> 'a -> unit) -> unit -(** [iteri b f] calls [f i t] for each element [t] in [buf], with [i] - being its relative index within [buf]. *) + val blit_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. + @raise Invalid_argument if [o,len] is not a valid slice of [s] *) -val get : 'a t -> int -> 'a -(** [get buf i] returns the [i]-th element of [buf], ie the one that - is returned by [next buf] after [i-1] calls to [junk buf]. - @raise Invalid_argument if the index is invalid (> [length buf]) *) + val blit_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] *) -val push_back : 'a t -> 'a -> unit + val to_list : t -> Array.elt list + (** extract the current content into a list *) + + val clear : t -> unit + (** clear the content of the buffer. Doesn't actually destroy the content. *) + + val reset : t -> unit + (** clear the content of the buffer, and also resize it to a default size *) + + val is_empty :t -> bool + (** is the buffer empty (i.e. contains no elements)? *) + + val next : t -> Array.elt + (** obtain next element (the first one of the buffer) + @raise Empty if the buffer is empty *) + + val junk : t -> unit + (** Drop next element. + @raise Empty if the buffer is already empty *) + + val skip : t -> int -> unit + (** [skip b len] removes [len] elements from [b]. + @raise Invalid_argument if [len > length b]. *) + + val iteri : t -> (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]. *) + + val get : t -> int -> Array.elt + (** [get buf i] returns the [i]-th element of [buf], ie the one that + is returned by [next buf] after [i-1] calls to [junk buf]. + @raise Invalid_argument if the index is invalid (> [length buf]) *) + + val push_back : t -> Array.elt -> unit (** Push value at the back *) -val peek_front : 'a t -> 'a + val peek_front : t -> Array.elt (** First value, or Empty *) -val peek_back : 'a t -> 'a + val peek_back : t -> Array.elt (** Last value, or Empty *) -val take_back : 'a t -> 'a + val take_back : t -> Array.elt (** Take last value, or raise Empty *) -val take_front : 'a t -> 'a + val take_front : t -> Array.elt (** Take first value, or raise Empty *) - +end From 847286597b2b77d3a6407e0f058940da1b2a7735 Mon Sep 17 00:00:00 2001 From: carm Date: Mon, 16 Feb 2015 19:48:31 -0500 Subject: [PATCH 11/32] specialized primitive module arrays, functorized version for remainder --- src/data/CCRingBuffer.ml | 118 ++++++++++++++++++++++++++++++-------- src/data/CCRingBuffer.mli | 49 +++++++++++----- 2 files changed, 129 insertions(+), 38 deletions(-) diff --git a/src/data/CCRingBuffer.ml b/src/data/CCRingBuffer.ml index 91743f41..d860de1b 100644 --- a/src/data/CCRingBuffer.ml +++ b/src/data/CCRingBuffer.ml @@ -22,29 +22,100 @@ (** Polymorphic Circular Buffer for IO *) -module type ARRAY = sig - type elt - type t +module Array = struct - val make: int -> elt -> t - val length: t -> int + module type S = sig + type elt + type t - val get: t -> int -> elt + val empty : t + val make: int -> elt -> t + val length: t -> int - val set: t -> int -> elt -> unit + val get: t -> int -> elt - val sub: t -> int -> int -> t - val max_length: int + val set: t -> int -> elt -> unit - val copy : t -> t - val of_list : elt list -> t - val to_list : t -> elt list - val blit : t -> int -> t -> int -> int -> unit + val sub: t -> int -> int -> t + + val copy : t -> t + val blit : t -> int -> t -> int -> int -> unit + + val iter : (elt -> unit) -> t -> unit + end + + module ByteArray : + S with type elt = char and type t = bytes = struct + type elt = char + include Bytes + end + + module FloatArray : + S with type elt = float and type t = float array = struct + type t = float array + type elt = float + let make = Array.make + let length = Array.length + let get = Array.get + let set = Array.set + let copy = Array.copy + let blit = Array.blit + let iter = Array.iter + let sub = Array.sub + let empty = Array.of_list [] + end + + + module IntArray : + S with type elt = int and type t = int array = struct + type t = int array + type elt = int + let make = Array.make + let length = Array.length + let get = Array.get + let set = Array.set + let copy = Array.copy + let blit = Array.blit + let iter = Array.iter + let sub = Array.sub + let empty = Array.of_list [] + end + + + module BoolArray : + S with type elt = bool and type t = bool array = struct + type t = bool array + type elt = bool + let make = Array.make + let length = Array.length + let get = Array.get + let set = Array.set + let copy = Array.copy + let blit = Array.blit + let iter = Array.iter + let sub = Array.sub + let empty = Array.of_list [] + end + + + module Make(Elt:sig type t end) : + S with type elt = Elt.t and type t = Elt.t array = struct + type elt = Elt.t + type t = Elt.t array + let make = Array.make + let length = Array.length + let get = Array.get + let set = Array.set + let copy = Array.copy + let blit = Array.blit + let iter = Array.iter + let sub = Array.sub + let empty = Array.of_list [] + end - val iter : (elt -> unit) -> t -> unit end -module Make(Array:ARRAY) = +module Make(Array:Array.S) = struct type t = { @@ -62,7 +133,7 @@ struct stop=0; bounded; size; - buf = Array.of_list [] + buf = Array.empty } let copy b = @@ -183,7 +254,7 @@ struct let reset b = clear b; - b.buf <- Array.of_list [] + b.buf <- Array.empty let is_empty b = b.start = b.stop @@ -259,13 +330,13 @@ struct else b.buf.(i - len_end) let to_list b = - if (b.stop >= b.start) - then Array.to_list (Array.sub b.buf b.start (b.stop-b.start)) - else List.append - (Array.to_list (Array.sub b.buf b.start (Array.length b.buf - b.start))) - (Array.to_list (Array.sub b.buf 0 b.stop)) + let len = length b in + let rec build l i = + if i < 0 then l else + build ((get b i)::l) (i-1) in + build [] (len-1) - let push_back b e = add b (Array.of_list [e]) + let push_back b e = add b (Array.make 1 e) let peek_front b = if is_empty b then raise Empty else Array.get b.buf b.start @@ -274,3 +345,4 @@ struct raise Empty else Array.get b.buf (if b.stop = 0 then capacity b - 1 else b.stop-1) end + diff --git a/src/data/CCRingBuffer.mli b/src/data/CCRingBuffer.mli index bc405f43..1affaaf9 100644 --- a/src/data/CCRingBuffer.mli +++ b/src/data/CCRingBuffer.mli @@ -20,30 +20,49 @@ (** Circular Polymorphic Buffer for IO *) -module type ARRAY = sig - type elt - type t +module Array : sig - val make: int -> elt -> t - val length: t -> int + module type S = sig + type elt + type t - val get: t -> int -> elt + val empty : t + val make: int -> elt -> t + val length: t -> int - val set: t -> int -> elt -> unit + val get: t -> int -> elt - val sub: t -> int -> int -> t - val max_length: int + val set: t -> int -> elt -> unit - val copy : t -> t - val of_list : elt list -> t - val to_list : t -> elt list - val blit : t -> int -> t -> int -> int -> unit + val sub: t -> int -> int -> t + + val copy : t -> t + val blit : t -> int -> t -> int -> int -> unit + + val iter : (elt -> unit) -> t -> unit + end + + module ByteArray : + S with type elt = char and type t = bytes + + module FloatArray : + S with type elt = float and type t = float array + + + module IntArray : + S with type elt = int and type t = int array + + module BoolArray : + S with type elt = bool and type t = bool array + + module Make : + functor (Elt:sig type t end) -> + S with type elt = Elt.t and type t = Elt.t array - val iter : (elt -> unit) -> t -> unit end -module Make : functor (Array:ARRAY) -> +module Make : functor (Array:Array.S) -> sig type t = private { From 9787e52e36da2ba46c48cc2013c963585a5ab92e Mon Sep 17 00:00:00 2001 From: carm Date: Tue, 17 Feb 2015 00:47:57 -0500 Subject: [PATCH 12/32] various ring buf convenience functors make explicit signature for ring buffer type --- src/data/CCRingBuffer.ml | 102 +++++++++++++++++++++++++++++++++++++- src/data/CCRingBuffer.mli | 15 ++++-- 2 files changed, 113 insertions(+), 4 deletions(-) diff --git a/src/data/CCRingBuffer.ml b/src/data/CCRingBuffer.ml index d860de1b..d571d6f7 100644 --- a/src/data/CCRingBuffer.ml +++ b/src/data/CCRingBuffer.ml @@ -115,9 +115,101 @@ module Array = struct end -module Make(Array:Array.S) = +module type S = +sig + + module Array : Array.S + + type t = private { + mutable start : int; + mutable stop : int; (* excluded *) + mutable buf : Array.t; + bounded: bool; + size : int + } + exception Empty + + val create : ?bounded:bool -> int -> t + (** [create ?bounded size] creates a new buffer with given size. + Defaults to [bounded=false]. *) + + val copy : t -> t + (** fresh copy of the buffer *) + + val capacity : t -> int + (** length of the inner buffer *) + + val max_capacity : t -> int option + (** maximum length of the inner buffer, or [None] if unbounded. *) + + val length : t -> int + (** number of elements currently stored in the buffer *) + + val blit_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. + @raise Invalid_argument if [o,len] is not a valid slice of [s] *) + + val blit_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] *) + + val to_list : t -> Array.elt list + (** extract the current content into a list *) + + val clear : t -> unit + (** clear the content of the buffer. Doesn't actually destroy the content. *) + + val reset : t -> unit + (** clear the content of the buffer, and also resize it to a default size *) + + val is_empty :t -> bool + (** is the buffer empty (i.e. contains no elements)? *) + + val next : t -> Array.elt + (** obtain next element (the first one of the buffer) + @raise Empty if the buffer is empty *) + + val junk : t -> unit + (** Drop next element. + @raise Empty if the buffer is already empty *) + + val skip : t -> int -> unit + (** [skip b len] removes [len] elements from [b]. + @raise Invalid_argument if [len > length b]. *) + + val iteri : t -> (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]. *) + + val get : t -> int -> Array.elt + (** [get buf i] returns the [i]-th element of [buf], ie the one that + is returned by [next buf] after [i-1] calls to [junk buf]. + @raise Invalid_argument if the index is invalid (> [length buf]) *) + + val push_back : t -> Array.elt -> unit + (** Push value at the back *) + + val peek_front : t -> Array.elt + (** First value, or Empty *) + + val peek_back : t -> Array.elt + (** Last value, or Empty *) + + val take_back : t -> Array.elt + (** Take last value, or raise Empty *) + + val take_front : t -> Array.elt + (** Take first value, or raise Empty *) + +end + +module Make_array(Array:Array.S) = struct + module Array = Array type t = { mutable start : int; mutable stop : int; (* excluded *) @@ -346,3 +438,11 @@ struct (if b.stop = 0 then capacity b - 1 else b.stop-1) end +module Bytes = Make_array(Array.ByteArray) +module Floats = Make_array(Array.FloatArray) +module Ints = Make_array(Array.IntArray) +module Bools = Make_array(Array.BoolArray) + +module Make(Elt:sig type t end) = Make_array(Array.Make(Elt)) + + diff --git a/src/data/CCRingBuffer.mli b/src/data/CCRingBuffer.mli index 1affaaf9..6a10322f 100644 --- a/src/data/CCRingBuffer.mli +++ b/src/data/CCRingBuffer.mli @@ -61,10 +61,11 @@ module Array : sig end - -module Make : functor (Array:Array.S) -> +module type S = sig + module Array : Array.S + type t = private { mutable start : int; mutable stop : int; (* excluded *) @@ -72,7 +73,6 @@ sig bounded: bool; size : int } - exception Empty val create : ?bounded:bool -> int -> t @@ -151,3 +151,12 @@ sig (** Take first value, or raise Empty *) end + +module Make_array : functor (Array:Array.S) -> S with module Array = Array + +module Bytes : S with module Array = Array.ByteArray +module Floats : S with module Array = Array.FloatArray +module Ints : S with module Array = Array.IntArray +module Bools : S with module Array = Array.BoolArray + +module Make: functor(Elt:sig type t end) -> S with module Array = Array.Make(Elt) From 8ec4ba09ac12643ccacde76e120f23281d6af4b6 Mon Sep 17 00:00:00 2001 From: carm Date: Tue, 17 Feb 2015 00:57:08 -0500 Subject: [PATCH 13/32] remove white space --- src/data/CCRingBuffer.ml | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/data/CCRingBuffer.ml b/src/data/CCRingBuffer.ml index d571d6f7..796e9f9d 100644 --- a/src/data/CCRingBuffer.ml +++ b/src/data/CCRingBuffer.ml @@ -444,5 +444,3 @@ module Ints = Make_array(Array.IntArray) module Bools = Make_array(Array.BoolArray) module Make(Elt:sig type t end) = Make_array(Array.Make(Elt)) - - From 00bcb47c4f60f3c72b11c1d0ac9ec3db332d45e9 Mon Sep 17 00:00:00 2001 From: carm Date: Tue, 17 Feb 2015 19:25:50 -0500 Subject: [PATCH 14/32] remove Floats/Ints/Bools modules --- src/data/CCRingBuffer.ml | 4 +--- src/data/CCRingBuffer.mli | 3 --- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/data/CCRingBuffer.ml b/src/data/CCRingBuffer.ml index 796e9f9d..73326bdb 100644 --- a/src/data/CCRingBuffer.ml +++ b/src/data/CCRingBuffer.ml @@ -439,8 +439,6 @@ struct end module Bytes = Make_array(Array.ByteArray) -module Floats = Make_array(Array.FloatArray) -module Ints = Make_array(Array.IntArray) -module Bools = Make_array(Array.BoolArray) module Make(Elt:sig type t end) = Make_array(Array.Make(Elt)) + diff --git a/src/data/CCRingBuffer.mli b/src/data/CCRingBuffer.mli index 6a10322f..f420d0a9 100644 --- a/src/data/CCRingBuffer.mli +++ b/src/data/CCRingBuffer.mli @@ -155,8 +155,5 @@ end module Make_array : functor (Array:Array.S) -> S with module Array = Array module Bytes : S with module Array = Array.ByteArray -module Floats : S with module Array = Array.FloatArray -module Ints : S with module Array = Array.IntArray -module Bools : S with module Array = Array.BoolArray module Make: functor(Elt:sig type t end) -> S with module Array = Array.Make(Elt) From 39cac7bc08051155d8d828a7c3ab766ed7df5e63 Mon Sep 17 00:00:00 2001 From: carm Date: Wed, 18 Feb 2015 00:26:59 -0500 Subject: [PATCH 15/32] converted various functions to _[front|back] style --- src/data/CCRingBuffer.ml | 77 +++++++++++++++------------------------ src/data/CCRingBuffer.mli | 77 +++++++++++++++++++++++---------------- 2 files changed, 76 insertions(+), 78 deletions(-) diff --git a/src/data/CCRingBuffer.ml b/src/data/CCRingBuffer.ml index 73326bdb..8e169a6b 100644 --- a/src/data/CCRingBuffer.ml +++ b/src/data/CCRingBuffer.ml @@ -53,7 +53,7 @@ module Array = struct module FloatArray : S with type elt = float and type t = float array = struct type t = float array - type elt = float + type elt = float let make = Array.make let length = Array.length let get = Array.get @@ -130,79 +130,48 @@ sig exception Empty val create : ?bounded:bool -> int -> t - (** [create ?bounded size] creates a new buffer with given size. - Defaults to [bounded=false]. *) val copy : t -> t - (** fresh copy of the buffer *) val capacity : t -> int - (** length of the inner buffer *) val max_capacity : t -> int option - (** maximum length of the inner buffer, or [None] if unbounded. *) val length : t -> int - (** number of elements currently stored in the buffer *) val blit_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. - @raise Invalid_argument if [o,len] is not a valid slice of [s] *) val blit_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] *) val to_list : t -> Array.elt list - (** extract the current content into a list *) val clear : t -> unit - (** clear the content of the buffer. Doesn't actually destroy the content. *) val reset : t -> unit - (** clear the content of the buffer, and also resize it to a default size *) val is_empty :t -> bool - (** is the buffer empty (i.e. contains no elements)? *) - val next : t -> Array.elt - (** obtain next element (the first one of the buffer) - @raise Empty if the buffer is empty *) + val junk_front : t -> unit - val junk : t -> unit - (** Drop next element. - @raise Empty if the buffer is already empty *) + val junk_back : t -> unit val skip : t -> int -> unit - (** [skip b len] removes [len] elements from [b]. - @raise Invalid_argument if [len > length b]. *) val iteri : t -> (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]. *) - val get : t -> int -> Array.elt - (** [get buf i] returns the [i]-th element of [buf], ie the one that - is returned by [next buf] after [i-1] calls to [junk buf]. - @raise Invalid_argument if the index is invalid (> [length buf]) *) + val get_front : t -> int -> Array.elt + + val get_back : t -> int -> Array.elt val push_back : t -> Array.elt -> unit - (** Push value at the back *) val peek_front : t -> Array.elt - (** First value, or Empty *) val peek_back : t -> Array.elt - (** Last value, or Empty *) val take_back : t -> Array.elt - (** Take last value, or raise Empty *) val take_front : t -> Array.elt - (** Take first value, or raise Empty *) end @@ -350,10 +319,6 @@ struct let is_empty b = b.start = b.stop - let next b = - if b.start = b.stop then raise Empty; - b.buf.(b.start) - let take_front b = if b.start = b.stop then raise Empty; let c = b.buf.(b.start) in @@ -369,12 +334,18 @@ struct else b.stop <- b.stop - 1; b.buf.(b.stop) - let junk b = + let junk_front b = if b.start = b.stop then raise Empty; if b.start + 1 = Array.length b.buf then b.start <- 0 else b.start <- b.start + 1 + let junk_back b = + if b.start = b.stop then raise Empty; + if b.stop - 1 = 0 + then b.stop <- Array.length b.buf - 1 + else b.stop <- b.stop - 1 + let skip b len = if len > length b then raise (Invalid_argument "BufferIO.skip"); if b.stop >= b.start @@ -411,30 +382,42 @@ struct if b.stop >= b.start then if i >= b.stop - b.start - then raise (Invalid_argument "BufferIO.get") + then raise (Invalid_argument "CCRingBuffer.get") else b.buf.(b.start + i) else let len_end = Array.length b.buf - b.start in if i < len_end then b.buf.(b.start + i) else if i - len_end > b.stop - then raise (Invalid_argument "BufferIO.get") + then raise (Invalid_argument "CCRingBuffer.get") else b.buf.(i - len_end) + let get_front b i = + if is_empty b then + raise (Invalid_argument "CCRingBuffer.get_front") + else + get b i + + let get_back b i = + let offset = ((length b) - i - 1) in + if offset < 0 then + raise (Invalid_argument "CCRingBuffer.get_back") + else get b offset + let to_list b = let len = length b in let rec build l i = if i < 0 then l else - build ((get b i)::l) (i-1) in + build ((get_front b i)::l) (i-1) in build [] (len-1) let push_back b e = add b (Array.make 1 e) - let peek_front b = if is_empty b then + let peek_front b = if is_empty b then raise Empty else Array.get b.buf b.start let peek_back b = if is_empty b then - raise Empty else Array.get b.buf + raise Empty else Array.get b.buf (if b.stop = 0 then capacity b - 1 else b.stop-1) end diff --git a/src/data/CCRingBuffer.mli b/src/data/CCRingBuffer.mli index f420d0a9..f1a42ec9 100644 --- a/src/data/CCRingBuffer.mli +++ b/src/data/CCRingBuffer.mli @@ -1,5 +1,5 @@ (** - * CCBufferIO - Polymorphic Circular Buffer + * CCRingBuffer - Polymorphic Circular Buffer * Copyright (C) 2014 Simon Cruanes * * This library is free software; you can redistribute it and/or @@ -27,7 +27,9 @@ module Array : sig type t val empty : t + val make: int -> elt -> t + val length: t -> int val get: t -> int -> elt @@ -37,28 +39,27 @@ module Array : sig val sub: t -> int -> int -> t val copy : t -> t + val blit : t -> int -> t -> int -> int -> unit val iter : (elt -> unit) -> t -> unit end module ByteArray : - S with type elt = char and type t = bytes + S with type elt = char and type t = bytes module FloatArray : - S with type elt = float and type t = float array - + S with type elt = float and type t = float array module IntArray : - S with type elt = int and type t = int array + S with type elt = int and type t = int array module BoolArray : - S with type elt = bool and type t = bool array + S with type elt = bool and type t = bool array - module Make : + module Make : functor (Elt:sig type t end) -> S with type elt = Elt.t and type t = Elt.t array - end module type S = @@ -80,16 +81,16 @@ sig Defaults to [bounded=false]. *) val copy : t -> t - (** fresh copy of the buffer *) + (** Make a fresh copy of the buffer. *) val capacity : t -> int - (** length of the inner buffer *) + (** Length of the inner buffer. *) val max_capacity : t -> int option - (** maximum length of the inner buffer, or [None] if unbounded. *) + (** Maximum length of the inner buffer, or [None] if unbounded. *) val length : t -> int - (** number of elements currently stored in the buffer *) + (** Number of elements currently stored in the buffer. *) val blit_from : t -> Array.t -> int -> int -> unit (** [blit_from buf from_buf o len] copies the slice [o, ... o + len - 1] from @@ -103,57 +104,71 @@ sig @raise Invalid_argument if [o,len] is not a valid slice of [s] *) val to_list : t -> Array.elt list - (** extract the current content into a list *) + (** Extract the current content into a list *) val clear : t -> unit - (** clear the content of the buffer. Doesn't actually destroy the content. *) + (** Clear the content of the buffer. Doesn't actually destroy the content. *) val reset : t -> unit - (** clear the content of the buffer, and also resize it to a default size *) + (** Clear the content of the buffer, and also resize it to a default size *) val is_empty :t -> bool - (** is the buffer empty (i.e. contains no elements)? *) + (** Is the buffer empty (i.e. contains no elements)? *) - val next : t -> Array.elt - (** obtain next element (the first one of the buffer) - @raise Empty if the buffer is empty *) + val junk_front : t -> unit + (** Drop the front element from [t]. + @raise Empty if the buffer is already empty. *) - val junk : t -> unit - (** Drop next element. - @raise Empty if the buffer is already empty *) + val junk_back : t -> unit + (** Drop the back element from [t]. + @raise Empty if the buffer is already empty. *) val skip : t -> int -> unit - (** [skip b len] removes [len] elements from [b]. + (** [skip b len] removes [len] elements from the front of [b]. @raise Invalid_argument if [len > length b]. *) val iteri : t -> (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]. *) - val get : t -> int -> Array.elt - (** [get buf i] returns the [i]-th element of [buf], ie the one that - is returned by [next buf] after [i-1] calls to [junk buf]. + val get_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]) *) + + val get_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]) *) val push_back : t -> Array.elt -> unit - (** Push value at the back *) + (** Push value at the back of [t]. + If [t.bounded=false], the buffer will grow as needed, + otherwise the oldest elements are replaced first. *) val peek_front : t -> Array.elt - (** First value, or Empty *) + (** First value from front of [t]. + @raise Empty if buffer is empty. *) val peek_back : t -> Array.elt - (** Last value, or Empty *) + (** Get the last value from back of [t]. + @raise Empty if buffer is empty. *) val take_back : t -> Array.elt - (** Take last value, or raise Empty *) + (** Take the last value from back of [t]. + @raise Empty if buffer is already empty. *) val take_front : t -> Array.elt - (** Take first value, or raise Empty *) + (** Take the first value from front of [t]. + @raise Empty if buffer is already empty. *) end +(** Makes a ring buffer module given array implementation *) module Make_array : functor (Array:Array.S) -> S with module Array = Array +(** An efficient byte based ring buffer *) module Bytes : S with module Array = Array.ByteArray +(** Makes a ring buffer module given the element type *) module Make: functor(Elt:sig type t end) -> S with module Array = Array.Make(Elt) From 51b2828af391a9dd0526813170370836c83e4594 Mon Sep 17 00:00:00 2001 From: cpiccion Date: Thu, 19 Feb 2015 18:28:20 -0500 Subject: [PATCH 16/32] formatting, qtests --- src/data/CCRingBuffer.ml | 42 +++++++++++++++++++++------------------ src/data/CCRingBuffer.mli | 4 ++-- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/data/CCRingBuffer.ml b/src/data/CCRingBuffer.ml index 8e169a6b..7bc90e94 100644 --- a/src/data/CCRingBuffer.ml +++ b/src/data/CCRingBuffer.ml @@ -29,8 +29,10 @@ module Array = struct type t val empty : t - val make: int -> elt -> t - val length: t -> int + + val make: int -> elt -> t + + val length: t -> int val get: t -> int -> elt @@ -39,12 +41,13 @@ module Array = struct val sub: t -> int -> int -> t val copy : t -> t - val blit : t -> int -> t -> int -> int -> unit + + val blit : t -> int -> t -> int -> int -> unit val iter : (elt -> unit) -> t -> unit end - module ByteArray : + module ByteArray : S with type elt = char and type t = bytes = struct type elt = char include Bytes @@ -200,6 +203,14 @@ struct let copy b = { b with buf=Array.copy b.buf; } + (*$T + let b = ByteBuffer.create 3 in \ + let s = Bytes.of_string "hello world" in \ + ByteBuffer.blit_from b s 0 (Bytes.length s); \ + let b' = ByteBuffer.copy b in \ + try ByteBuffer.iteri b (fun i c -> if ByteBuffer.get_front b' i <> c then raise Exit); true with Exit -> false + *) + let capacity b = Array.length b.buf @@ -300,15 +311,7 @@ struct end end - let add b s = blit_from b s 0 (Array.length s) - - (*$Q - (Q.pair Q.printable_string Q.printable_string) (fun (s,s') -> \ - let b = create 24 in add b s; add_string b s'; \ - Array.length s + String.length s' = length b) - *) - - let clear b = + let clear b = b.stop <- 0; b.start <- 0; () @@ -358,10 +361,11 @@ struct (*$Q (Q.pair Q.printable_string Q.printable_string) (fun (s,s') -> \ - let b = create 24 in add_string b s; add_string b s'; \ - add_string b "hello world"; (* big enough *) \ - let l = length b in let l' = l/2 in skip b l'; \ - length b + l' = l) + (let b = ByteBuffer.create 24 in ByteBuffer.blit_from b s 0 (Bytes.length s); + ByteBuffer.blit_from b s' 0 (Bytes.length s'); \ + ByteBuffer.blit_from b "hello world" 0 (Bytes.length "hello word"); (* big enough *) \ + let l = ByteBuffer.length b in let l' = l/2 in ByteBuffer.skip b l'; \ + ByteBuffer.length b + l' = l)) *) let iteri b f = @@ -411,7 +415,7 @@ struct build ((get_front b i)::l) (i-1) in build [] (len-1) - let push_back b e = add b (Array.make 1 e) + let push_back b e = blit_from b (Array.make 1 e) 0 1 let peek_front b = if is_empty b then raise Empty else Array.get b.buf b.start @@ -421,7 +425,7 @@ struct (if b.stop = 0 then capacity b - 1 else b.stop-1) end -module Bytes = Make_array(Array.ByteArray) +module ByteBuffer = Make_array(Array.ByteArray) module Make(Elt:sig type t end) = Make_array(Array.Make(Elt)) diff --git a/src/data/CCRingBuffer.mli b/src/data/CCRingBuffer.mli index f1a42ec9..43b356db 100644 --- a/src/data/CCRingBuffer.mli +++ b/src/data/CCRingBuffer.mli @@ -46,7 +46,7 @@ module Array : sig end module ByteArray : - S with type elt = char and type t = bytes + S with type elt = char and type t = bytes module FloatArray : S with type elt = float and type t = float array @@ -168,7 +168,7 @@ end module Make_array : functor (Array:Array.S) -> S with module Array = Array (** An efficient byte based ring buffer *) -module Bytes : S with module Array = Array.ByteArray +module ByteBuffer : S with module Array = Array.ByteArray (** Makes a ring buffer module given the element type *) module Make: functor(Elt:sig type t end) -> S with module Array = Array.Make(Elt) From a1ca8ff83180e5e11cadcd47120b22db5e07f45e Mon Sep 17 00:00:00 2001 From: carm Date: Thu, 19 Feb 2015 23:10:19 -0500 Subject: [PATCH 17/32] formatting --- src/data/CCRingBuffer.ml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/data/CCRingBuffer.ml b/src/data/CCRingBuffer.ml index 7bc90e94..fe064467 100644 --- a/src/data/CCRingBuffer.ml +++ b/src/data/CCRingBuffer.ml @@ -29,10 +29,10 @@ module Array = struct type t val empty : t - - val make: int -> elt -> t - - val length: t -> int + + val make: int -> elt -> t + + val length: t -> int val get: t -> int -> elt @@ -41,13 +41,13 @@ module Array = struct val sub: t -> int -> int -> t val copy : t -> t - - val blit : t -> int -> t -> int -> int -> unit + + val blit : t -> int -> t -> int -> int -> unit val iter : (elt -> unit) -> t -> unit end - module ByteArray : + module ByteArray : S with type elt = char and type t = bytes = struct type elt = char include Bytes @@ -203,13 +203,13 @@ struct let copy b = { b with buf=Array.copy b.buf; } - (*$T - let b = ByteBuffer.create 3 in \ - let s = Bytes.of_string "hello world" in \ - ByteBuffer.blit_from b s 0 (Bytes.length s); \ +(*$T + let b = ByteBuffer.create 3 in \ + let s = Bytes.of_string "hello world" in \ + ByteBuffer.blit_from b s 0 (Bytes.length s); \ let b' = ByteBuffer.copy b in \ try ByteBuffer.iteri b (fun i c -> if ByteBuffer.get_front b' i <> c then raise Exit); true with Exit -> false - *) +*) let capacity b = Array.length b.buf @@ -362,7 +362,7 @@ struct (*$Q (Q.pair Q.printable_string Q.printable_string) (fun (s,s') -> \ (let b = ByteBuffer.create 24 in ByteBuffer.blit_from b s 0 (Bytes.length s); - ByteBuffer.blit_from b s' 0 (Bytes.length s'); \ + ByteBuffer.blit_from b s' 0 (Bytes.length s'); \ ByteBuffer.blit_from b "hello world" 0 (Bytes.length "hello word"); (* big enough *) \ let l = ByteBuffer.length b in let l' = l/2 in ByteBuffer.skip b l'; \ ByteBuffer.length b + l' = l)) From 777aca435ae7eee3d847101f7b774d8df659c059 Mon Sep 17 00:00:00 2001 From: cpiccion Date: Fri, 20 Feb 2015 16:20:03 -0500 Subject: [PATCH 18/32] unit test fixes --- src/data/CCRingBuffer.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/CCRingBuffer.ml b/src/data/CCRingBuffer.ml index fe064467..cf19483d 100644 --- a/src/data/CCRingBuffer.ml +++ b/src/data/CCRingBuffer.ml @@ -361,7 +361,7 @@ struct (*$Q (Q.pair Q.printable_string Q.printable_string) (fun (s,s') -> \ - (let b = ByteBuffer.create 24 in ByteBuffer.blit_from b s 0 (Bytes.length s); + (let b = ByteBuffer.create 24 in ByteBuffer.blit_from b s 0 (Bytes.length s); \ ByteBuffer.blit_from b s' 0 (Bytes.length s'); \ ByteBuffer.blit_from b "hello world" 0 (Bytes.length "hello word"); (* big enough *) \ let l = ByteBuffer.length b in let l' = l/2 in ByteBuffer.skip b l'; \ From c22a33c405244faaf3a27a256496de060b45caf9 Mon Sep 17 00:00:00 2001 From: carm Date: Sun, 22 Feb 2015 13:03:59 -0500 Subject: [PATCH 19/32] fix bugs revealed in qtests --- src/data/CCRingBuffer.ml | 95 +++++++++++++++++++++++++++------------- 1 file changed, 64 insertions(+), 31 deletions(-) diff --git a/src/data/CCRingBuffer.ml b/src/data/CCRingBuffer.ml index cf19483d..e3b2e806 100644 --- a/src/data/CCRingBuffer.ml +++ b/src/data/CCRingBuffer.ml @@ -68,7 +68,6 @@ module Array = struct let empty = Array.of_list [] end - module IntArray : S with type elt = int and type t = int array = struct type t = int array @@ -102,7 +101,7 @@ module Array = struct module Make(Elt:sig type t end) : - S with type elt = Elt.t and type t = Elt.t array = struct + S with type elt = Elt.t and type t = Elt.t array = struct type elt = Elt.t type t = Elt.t array let make = Array.make @@ -204,15 +203,17 @@ struct { b with buf=Array.copy b.buf; } (*$T - let b = ByteBuffer.create 3 in \ let s = Bytes.of_string "hello world" in \ - ByteBuffer.blit_from b s 0 (Bytes.length s); \ - let b' = ByteBuffer.copy b in \ - try ByteBuffer.iteri b (fun i c -> if ByteBuffer.get_front b' i <> c then raise Exit); true with Exit -> false + let s_len = Bytes.length s in \ + let b = ByteBuffer.create s_len in \ + ByteBuffer.blit_from b s 0 s_len; \ + let b' = ByteBuffer.copy b in \ + try ByteBuffer.iteri b (fun i c -> if ByteBuffer.get_front b' i <> c then raise Exit); true with Exit -> false *) - - let capacity b = Array.length b.buf + let capacity b = + let len = Array.length b.buf in + match len with 0 -> 0 | l -> l - 1 let max_capacity b = if b.bounded then Some b.size else None @@ -241,17 +242,23 @@ struct b.buf <- buf' let blit_from_bounded b from_buf o len = - let cap = capacity b - len in + let cap = capacity b - length b in (* resize if needed, with a constant to amortize *) if cap < len then begin let new_size = let desired = Array.length b.buf + len + 24 in min (b.size+1) desired in - resize b new_size from_buf.(0) + resize b new_size from_buf.(0); + let good = capacity b - length b >= len in + if not good then begin + print_endline ("capacity " ^ string_of_int (capacity b) ^ " and length " ^ + string_of_int (length b) ^ " difference is less than " ^ + string_of_int len ^ "!");assert(false) + end; end; let sub = Array.sub from_buf o len in let iter x = - let capacity = capacity b in + let capacity = Array.length b.buf in Array.set b.buf b.stop x; if b.stop = capacity-1 then b.stop <- 0 else b.stop <- b.stop + 1; if b.start = b.stop then @@ -263,10 +270,15 @@ struct let blit_from_unbounded b from_buf o len = - let cap = capacity b - len in + let cap = capacity b - length b in (* resize if needed, with a constant to amortize *) - if cap < len then resize b (max b.size (Array.length b.buf + len + 24)) from_buf.(0); - assert (capacity b - length b >= len); + if cap < len then resize b (max (b.size+1) (Array.length b.buf + len + 24)) from_buf.(0); + let good = capacity b - length b >= len in + if not good then begin + print_endline ("capacity " ^ string_of_int (capacity b) ^ " and length " ^ + string_of_int (length b) ^ " difference is less than " ^ + string_of_int len ^ "!");assert(false) + end; if b.stop >= b.start then (* [_______ start xxxxxxxxx stop ______] *) let len_end = Array.length b.buf - b.stop in @@ -285,12 +297,30 @@ struct () let blit_from b from_buf o len = - if (Array.length from_buf) = 0 then () else + if Array.length from_buf = 0 then () else if b.bounded then blit_from_bounded b from_buf o len else blit_from_unbounded b from_buf o len + (*$Q + (Q.pair Q.printable_string Q.printable_string) (fun (s,s') -> \ + (let b = ByteBuffer.create 24 in \ + ByteBuffer.blit_from b s 0 (Bytes.length s); \ + ByteBuffer.blit_from b s' 0 (Bytes.length s'); \ + ByteBuffer.length b = Bytes.length s + Bytes.length s')) + *) + + + (*$Q + (Q.pair Q.printable_string Q.printable_string) (fun (s,s') -> \ + (let b = ByteBuffer.create ~bounded:true (Bytes.length s + Bytes.length s') in \ + ByteBuffer.blit_from b s 0 (Bytes.length s); \ + ByteBuffer.blit_from b s' 0 (Bytes.length s'); \ + ByteBuffer.length b = Bytes.length s + Bytes.length s')) + *) + + let blit_into b to_buf o len = if o+len > Array.length to_buf then raise (Invalid_argument "BufferIO.blit_into"); @@ -311,7 +341,7 @@ struct end end - let clear b = + let clear b = b.stop <- 0; b.start <- 0; () @@ -350,20 +380,22 @@ struct else b.stop <- b.stop - 1 let skip b len = - if len > length b then raise (Invalid_argument "BufferIO.skip"); + if len > length b then raise (Invalid_argument + ("CCRingBufferIO.skip: " ^ string_of_int len)); if b.stop >= b.start then b.start <- b.start + len else let len_end = Array.length b.buf - b.start in if len > len_end - then b.start <- len-len_end (* wrap to the beginning *) - else b.start <- b.start + len + then (print_endline "case B1"; b.start <- len-len_end) (* wrap to the beginning *) + else (print_endline "case B2"; b.start <- b.start + len) (*$Q (Q.pair Q.printable_string Q.printable_string) (fun (s,s') -> \ - (let b = ByteBuffer.create 24 in ByteBuffer.blit_from b s 0 (Bytes.length s); \ + (let b = ByteBuffer.create 24 in \ + ByteBuffer.blit_from b s 0 (Bytes.length s); \ ByteBuffer.blit_from b s' 0 (Bytes.length s'); \ - ByteBuffer.blit_from b "hello world" 0 (Bytes.length "hello word"); (* big enough *) \ + ByteBuffer.blit_from b "hello world" 0 (Bytes.length "hello world"); (* big enough *) \ let l = ByteBuffer.length b in let l' = l/2 in ByteBuffer.skip b l'; \ ByteBuffer.length b + l' = l)) *) @@ -376,36 +408,38 @@ struct for i = 0 to b.stop - 1 do f i b.buf.(i) done; ) - (*$T - let s = "hello world" in \ - let b = of_string s in \ - try iteri b (fun i c -> if s.[i] <> c then raise Exit); true with Exit -> false - *) +(*$T + let s = Bytes.of_string "hello world" in \ + let s_len = Bytes.length s in \ + let b = ByteBuffer.create s_len in \ + ByteBuffer.blit_from b s 0 s_len; \ + try ByteBuffer.iteri b (fun i c -> if ByteBuffer.get_front b i <> c then raise Exit); true with Exit -> false +*) let get b i = if b.stop >= b.start then if i >= b.stop - b.start - then raise (Invalid_argument "CCRingBuffer.get") + then raise (Invalid_argument ("CCRingBuffer.get:" ^ string_of_int i)) else b.buf.(b.start + i) else let len_end = Array.length b.buf - b.start in if i < len_end then b.buf.(b.start + i) else if i - len_end > b.stop - then raise (Invalid_argument "CCRingBuffer.get") + then raise (Invalid_argument ("CCRingBuffer.get: " ^ string_of_int i)) else b.buf.(i - len_end) let get_front b i = if is_empty b then - raise (Invalid_argument "CCRingBuffer.get_front") + raise (Invalid_argument ("CCRingBuffer.get_front: " ^ string_of_int i)) else get b i let get_back b i = let offset = ((length b) - i - 1) in if offset < 0 then - raise (Invalid_argument "CCRingBuffer.get_back") + raise (Invalid_argument ("CCRingBuffer.get_back:" ^ string_of_int i)) else get b offset let to_list b = @@ -428,4 +462,3 @@ end module ByteBuffer = Make_array(Array.ByteArray) module Make(Elt:sig type t end) = Make_array(Array.Make(Elt)) - From a2a6d282298e6a1096510f286a7775542471af9f Mon Sep 17 00:00:00 2001 From: carm Date: Sun, 22 Feb 2015 18:28:45 -0500 Subject: [PATCH 20/32] blit into qtest --- src/data/CCRingBuffer.ml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/data/CCRingBuffer.ml b/src/data/CCRingBuffer.ml index e3b2e806..3be95455 100644 --- a/src/data/CCRingBuffer.ml +++ b/src/data/CCRingBuffer.ml @@ -341,6 +341,16 @@ struct end end + (*$Q + Q.printable_string (fun s -> \ + let b = ByteBuffer.create (Bytes.length s) in \ + ByteBuffer.blit_from b s 0 (Bytes.length s); \ + let to_buf = Bytes.create (Bytes.length s) in \ + let len = ByteBuffer.blit_into b to_buf 0 (Bytes.length s) in \ + to_buf = s && len = Bytes.length s) + *) + + let clear b = b.stop <- 0; b.start <- 0; From aecbbf0dcd9fe8509b5330c7490ee61ee37c6497 Mon Sep 17 00:00:00 2001 From: carm Date: Sun, 22 Feb 2015 18:51:06 -0500 Subject: [PATCH 21/32] ringbuffer clear qtest --- src/data/CCRingBuffer.ml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/data/CCRingBuffer.ml b/src/data/CCRingBuffer.ml index 3be95455..b68d803d 100644 --- a/src/data/CCRingBuffer.ml +++ b/src/data/CCRingBuffer.ml @@ -356,6 +356,16 @@ struct b.start <- 0; () +(*$T + let s = Bytes.of_string "hello world" in \ + let s_len = Bytes.length s in \ + let b = ByteBuffer.create s_len in \ + ByteBuffer.blit_from b s 0 s_len; \ + ByteBuffer.clear b; \ + ByteBuffer.length b = 0 + *) + + let reset b = clear b; b.buf <- Array.empty From d8c2bd9da582a79857810a2e46348d0f0161cf25 Mon Sep 17 00:00:00 2001 From: carm Date: Sun, 22 Feb 2015 18:53:16 -0500 Subject: [PATCH 22/32] ringbuffer reset qtest --- src/data/CCRingBuffer.ml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/data/CCRingBuffer.ml b/src/data/CCRingBuffer.ml index b68d803d..2dae025a 100644 --- a/src/data/CCRingBuffer.ml +++ b/src/data/CCRingBuffer.ml @@ -370,6 +370,16 @@ struct clear b; b.buf <- Array.empty +(*$T + let s = Bytes.of_string "hello world" in \ + let s_len = Bytes.length s in \ + let b = ByteBuffer.create s_len in \ + ByteBuffer.blit_from b s 0 s_len; \ + ByteBuffer.reset b; \ + ByteBuffer.length b = 0 && ByteBuffer.capacity b = 0 + *) + + let is_empty b = b.start = b.stop let take_front b = From 9e0908dc2d23a213b74f0577885899910e1a7dec Mon Sep 17 00:00:00 2001 From: carm Date: Sun, 22 Feb 2015 18:55:36 -0500 Subject: [PATCH 23/32] ringbuffer isempty qtest --- src/data/CCRingBuffer.ml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/data/CCRingBuffer.ml b/src/data/CCRingBuffer.ml index 2dae025a..f044fb9d 100644 --- a/src/data/CCRingBuffer.ml +++ b/src/data/CCRingBuffer.ml @@ -382,6 +382,16 @@ struct let is_empty b = b.start = b.stop +(*$T + let s = Bytes.of_string "hello world" in \ + let s_len = Bytes.length s in \ + let b = ByteBuffer.create s_len in \ + ByteBuffer.blit_from b s 0 s_len; \ + ByteBuffer.skip b s_len; \ + ByteBuffer.is_empty b + *) + + let take_front b = if b.start = b.stop then raise Empty; let c = b.buf.(b.start) in From b57ca9d06a09a42604d8d6e0d19f16f2935c06ae Mon Sep 17 00:00:00 2001 From: carm Date: Sun, 22 Feb 2015 19:18:14 -0500 Subject: [PATCH 24/32] fix to junk_back, take/junk qtests --- src/data/CCRingBuffer.ml | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/data/CCRingBuffer.ml b/src/data/CCRingBuffer.ml index f044fb9d..3741ab0f 100644 --- a/src/data/CCRingBuffer.ml +++ b/src/data/CCRingBuffer.ml @@ -400,6 +400,15 @@ struct else b.start <- b.start + 1; c +(*$Q + Q.printable_string (fun s -> \ + let s_len = Bytes.length s in \ + let b = ByteBuffer.create s_len in \ + ByteBuffer.blit_from b s 0 s_len; \ + try let front = ByteBuffer.take_front b in \ + front = Bytes.get s 0 with ByteBuffer.Empty -> s_len = 0) + *) + let take_back b = if b.start = b.stop then raise Empty; if b.stop - 1 = 0 @@ -407,18 +416,45 @@ struct else b.stop <- b.stop - 1; b.buf.(b.stop) +(*$Q + Q.printable_string (fun s -> \ + let s_len = Bytes.length s in \ + let b = ByteBuffer.create s_len in \ + ByteBuffer.blit_from b s 0 s_len; \ + try let back = ByteBuffer.take_back b in \ + back = Bytes.get s (Bytes.length s - 1) with ByteBuffer.Empty -> s_len = 0) + *) + let junk_front b = if b.start = b.stop then raise Empty; if b.start + 1 = Array.length b.buf then b.start <- 0 else b.start <- b.start + 1 +(*$Q + Q.printable_string (fun s -> \ + let s_len = Bytes.length s in \ + let b = ByteBuffer.create s_len in \ + ByteBuffer.blit_from b s 0 s_len; \ + try let () = ByteBuffer.junk_front b in \ + s_len - 1 = ByteBuffer.length b with ByteBuffer.Empty -> s_len = 0) + *) + let junk_back b = if b.start = b.stop then raise Empty; - if b.stop - 1 = 0 + if b.stop = 0 then b.stop <- Array.length b.buf - 1 else b.stop <- b.stop - 1 +(*$Q + Q.printable_string (fun s -> \ + let s_len = Bytes.length s in \ + let b = ByteBuffer.create s_len in \ + ByteBuffer.blit_from b s 0 s_len; \ + try let () = ByteBuffer.junk_back b in \ + s_len - 1 = ByteBuffer.length b with ByteBuffer.Empty -> s_len = 0) + *) + let skip b len = if len > length b then raise (Invalid_argument ("CCRingBufferIO.skip: " ^ string_of_int len)); From 420f7c6bccbe8fca0e937540482a459bcd7736bc Mon Sep 17 00:00:00 2001 From: carm Date: Sun, 22 Feb 2015 19:52:15 -0500 Subject: [PATCH 25/32] fix to blit_from_bounded, several more qtests --- src/data/CCRingBuffer.ml | 65 +++++++++++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 8 deletions(-) diff --git a/src/data/CCRingBuffer.ml b/src/data/CCRingBuffer.ml index 3741ab0f..98303005 100644 --- a/src/data/CCRingBuffer.ml +++ b/src/data/CCRingBuffer.ml @@ -202,26 +202,75 @@ struct let copy b = { b with buf=Array.copy b.buf; } -(*$T - let s = Bytes.of_string "hello world" in \ +(*$Q + Q.printable_string (fun s -> \ let s_len = Bytes.length s in \ let b = ByteBuffer.create s_len in \ ByteBuffer.blit_from b s 0 s_len; \ let b' = ByteBuffer.copy b in \ - try ByteBuffer.iteri b (fun i c -> if ByteBuffer.get_front b' i <> c then raise Exit); true with Exit -> false + try ByteBuffer.iteri b (fun i c -> if ByteBuffer.get_front b' i <> c then raise Exit); true with Exit -> false) *) let capacity b = let len = Array.length b.buf in match len with 0 -> 0 | l -> l - 1 +(*$Q + Q.printable_string (fun s -> \ + let s_len = Bytes.length s in \ + let b = ByteBuffer.create s_len in \ + ByteBuffer.blit_from b s 0 s_len; \ + ByteBuffer.capacity b >= Bytes.length s) + *) + +(*$Q + (Q.pair Q.small_int Q.printable_string) (fun (i, s) -> \ + let i = abs i in \ + let s_len = Bytes.length s in \ + let b = ByteBuffer.create ~bounded:true i in \ + ByteBuffer.blit_from b s 0 s_len; \ + ByteBuffer.capacity b <= i) + *) + let max_capacity b = if b.bounded then Some b.size else None +(*$Q + Q.small_int (fun i -> \ + let i = abs i in \ + let b = ByteBuffer.create i in \ + ByteBuffer.max_capacity b = None) + *) + +(*$Q + Q.small_int (fun i -> \ + let i = abs i in \ + let b = ByteBuffer.create ~bounded:true i in \ + ByteBuffer.max_capacity b = Some i) + *) + let length b = if b.stop >= b.start then b.stop - b.start else (Array.length b.buf - b.start) + b.stop +(*$Q + (Q.pair Q.small_int Q.printable_string) (fun (i, s) -> \ + let i = abs i in \ + let s_len = Bytes.length s in \ + let b = ByteBuffer.create i in \ + ByteBuffer.blit_from b s 0 s_len; \ + ByteBuffer.length b = s_len) + *) + +(*$Q + (Q.pair Q.small_int Q.printable_string) (fun (i, s) -> \ + let i = abs i in \ + let s_len = Bytes.length s in \ + let b = ByteBuffer.create ~bounded:true i in \ + ByteBuffer.blit_from b s 0 s_len; \ + ByteBuffer.length b <= i) + *) + (* resize [b] so that inner capacity is [cap] *) let resize b cap elem = assert (cap >= Array.length b.buf); @@ -249,7 +298,7 @@ struct let desired = Array.length b.buf + len + 24 in min (b.size+1) desired in resize b new_size from_buf.(0); - let good = capacity b - length b >= len in + let good = capacity b = b.size || capacity b - length b >= len in if not good then begin print_endline ("capacity " ^ string_of_int (capacity b) ^ " and length " ^ string_of_int (length b) ^ " difference is less than " ^ @@ -273,7 +322,7 @@ struct let cap = capacity b - length b in (* resize if needed, with a constant to amortize *) if cap < len then resize b (max (b.size+1) (Array.length b.buf + len + 24)) from_buf.(0); - let good = capacity b - length b >= len in + let good = capacity b - length b >= len in if not good then begin print_endline ("capacity " ^ string_of_int (capacity b) ^ " and length " ^ string_of_int (length b) ^ " difference is less than " ^ @@ -484,12 +533,12 @@ struct for i = 0 to b.stop - 1 do f i b.buf.(i) done; ) -(*$T - let s = Bytes.of_string "hello world" in \ +(*$Q + Q.printable_string (fun s -> \ let s_len = Bytes.length s in \ let b = ByteBuffer.create s_len in \ ByteBuffer.blit_from b s 0 s_len; \ - try ByteBuffer.iteri b (fun i c -> if ByteBuffer.get_front b i <> c then raise Exit); true with Exit -> false + try ByteBuffer.iteri b (fun i c -> if ByteBuffer.get_front b i <> c then raise Exit); true with Exit -> false) *) let get b i = From d66a5bc86f03ff1d0213fd7f41dc7b2945a1ca03 Mon Sep 17 00:00:00 2001 From: carm Date: Sun, 22 Feb 2015 19:57:17 -0500 Subject: [PATCH 26/32] ringbuffer create qtest --- src/data/CCRingBuffer.ml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/data/CCRingBuffer.ml b/src/data/CCRingBuffer.ml index 98303005..77608728 100644 --- a/src/data/CCRingBuffer.ml +++ b/src/data/CCRingBuffer.ml @@ -199,6 +199,22 @@ struct buf = Array.empty } +(*$Q + Q.small_int (fun i -> \ + let i = abs i in \ + let b = ByteBuffer.create i in \ + let open ByteBuffer in \ + b.size = i && b.bounded = false) + *) + +(*$Q + Q.small_int (fun i -> \ + let i = abs i in \ + let b = ByteBuffer.create ~bounded:true i in \ + let open ByteBuffer in \ + b.size = i && b.bounded = true) + *) + let copy b = { b with buf=Array.copy b.buf; } From ed126fa6bb3d2ffe5acd2527fd6674014980ee23 Mon Sep 17 00:00:00 2001 From: carm Date: Sun, 22 Feb 2015 19:58:46 -0500 Subject: [PATCH 27/32] check for non-negative length --- src/data/CCRingBuffer.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/CCRingBuffer.ml b/src/data/CCRingBuffer.ml index 77608728..ba3fbc90 100644 --- a/src/data/CCRingBuffer.ml +++ b/src/data/CCRingBuffer.ml @@ -284,7 +284,7 @@ struct let s_len = Bytes.length s in \ let b = ByteBuffer.create ~bounded:true i in \ ByteBuffer.blit_from b s 0 s_len; \ - ByteBuffer.length b <= i) + ByteBuffer.length b >= 0 && ByteBuffer.length b <= i) *) (* resize [b] so that inner capacity is [cap] *) From ec92dfaa94818bb3639b851ab47d561cb7e73809 Mon Sep 17 00:00:00 2001 From: carm Date: Sun, 22 Feb 2015 20:01:47 -0500 Subject: [PATCH 28/32] remove debugging, better is_empty test --- src/data/CCRingBuffer.ml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/data/CCRingBuffer.ml b/src/data/CCRingBuffer.ml index ba3fbc90..bdf27dde 100644 --- a/src/data/CCRingBuffer.ml +++ b/src/data/CCRingBuffer.ml @@ -447,13 +447,13 @@ struct let is_empty b = b.start = b.stop -(*$T - let s = Bytes.of_string "hello world" in \ +(*$Q + Q.printable_string (fun s -> \ let s_len = Bytes.length s in \ let b = ByteBuffer.create s_len in \ ByteBuffer.blit_from b s 0 s_len; \ ByteBuffer.skip b s_len; \ - ByteBuffer.is_empty b + ByteBuffer.is_empty b) *) @@ -528,8 +528,8 @@ struct else let len_end = Array.length b.buf - b.start in if len > len_end - then (print_endline "case B1"; b.start <- len-len_end) (* wrap to the beginning *) - else (print_endline "case B2"; b.start <- b.start + len) + then b.start <- len-len_end (* wrap to the beginning *) + else b.start <- b.start + len (*$Q (Q.pair Q.printable_string Q.printable_string) (fun (s,s') -> \ From 356f6934dd21b6f505513e36ee2e33371158e0b0 Mon Sep 17 00:00:00 2001 From: carm Date: Sun, 22 Feb 2015 20:10:16 -0500 Subject: [PATCH 29/32] ringbuffer get front/back qtests --- src/data/CCRingBuffer.ml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/data/CCRingBuffer.ml b/src/data/CCRingBuffer.ml index bdf27dde..5f218ea4 100644 --- a/src/data/CCRingBuffer.ml +++ b/src/data/CCRingBuffer.ml @@ -577,12 +577,36 @@ struct else get b i +(*$Q + (Q.pair Q.small_int Q.printable_string) (fun (i, s) -> \ + let s = s ^ " " in \ + let s_len = Bytes.length s in \ + let b = ByteBuffer.create s_len in \ + ByteBuffer.blit_from b s 0 s_len; \ + let index = abs (i mod ByteBuffer.length b) in \ + let front = ByteBuffer.get_front b index in \ + front = Bytes.get s index) + *) + let get_back b i = let offset = ((length b) - i - 1) in if offset < 0 then raise (Invalid_argument ("CCRingBuffer.get_back:" ^ string_of_int i)) else get b offset +(*$Q + (Q.pair Q.small_int Q.printable_string) (fun (i, s) -> \ + let s = s ^ " " in \ + let s_len = Bytes.length s in \ + let b = ByteBuffer.create s_len in \ + ByteBuffer.blit_from b s 0 s_len; \ + let index = abs (i mod ByteBuffer.length b) in \ + let back = ByteBuffer.get_back b index in \ + back = Bytes.get s (s_len - index - 1)) + *) + + + let to_list b = let len = length b in let rec build l i = From 67eae77105856b43044089068729e74d28e4ed62 Mon Sep 17 00:00:00 2001 From: carm Date: Sun, 22 Feb 2015 20:27:26 -0500 Subject: [PATCH 30/32] final set of qtests for ringbuffer --- src/data/CCRingBuffer.ml | 44 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/src/data/CCRingBuffer.ml b/src/data/CCRingBuffer.ml index 5f218ea4..3dc37a1b 100644 --- a/src/data/CCRingBuffer.ml +++ b/src/data/CCRingBuffer.ml @@ -606,7 +606,6 @@ struct *) - let to_list b = let len = length b in let rec build l i = @@ -614,14 +613,57 @@ struct build ((get_front b i)::l) (i-1) in build [] (len-1) +(*$Q + Q.printable_string (fun s -> \ + let s_len = Bytes.length s in \ + let b = ByteBuffer.create s_len in \ + ByteBuffer.blit_from b s 0 s_len; \ + let l = ByteBuffer.to_list b in \ + let explode s = let rec exp i l = \ + if i < 0 then l else exp (i - 1) (s.[i] :: l) in \ + exp (String.length s - 1) [] in \ + explode s = l) + *) + let push_back b e = blit_from b (Array.make 1 e) 0 1 +(*$Q + Q.printable_string (fun s -> \ + let s_len = Bytes.length s in \ + let b = ByteBuffer.create s_len in \ + ByteBuffer.blit_from b s 0 s_len; \ + ByteBuffer.push_back b 'X'; \ + ByteBuffer.peek_back b = 'X') + *) + + let peek_front b = if is_empty b then raise Empty else Array.get b.buf b.start +(*$Q + Q.printable_string (fun s -> \ + let s_len = Bytes.length s in \ + let b = ByteBuffer.create s_len in \ + ByteBuffer.blit_from b s 0 s_len; \ + try let back = ByteBuffer.peek_front b in \ + back = Bytes.get s 0 with ByteBuffer.Empty -> s_len = 0) + *) + let peek_back b = if is_empty b then raise Empty else Array.get b.buf (if b.stop = 0 then capacity b - 1 else b.stop-1) + +(*$Q + Q.printable_string (fun s -> \ + let s_len = Bytes.length s in \ + let b = ByteBuffer.create s_len in \ + ByteBuffer.blit_from b s 0 s_len; \ + try let back = ByteBuffer.peek_back b in \ + back = Bytes.get s (s_len - 1) with ByteBuffer.Empty -> s_len = 0) + *) + + + end module ByteBuffer = Make_array(Array.ByteArray) From 7c0ed782e422847e6e5a19c0ebd1b5abe38ef48b Mon Sep 17 00:00:00 2001 From: carm Date: Sun, 22 Feb 2015 20:29:13 -0500 Subject: [PATCH 31/32] make some tests more random --- src/data/CCRingBuffer.ml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/data/CCRingBuffer.ml b/src/data/CCRingBuffer.ml index 3dc37a1b..dde33241 100644 --- a/src/data/CCRingBuffer.ml +++ b/src/data/CCRingBuffer.ml @@ -421,13 +421,13 @@ struct b.start <- 0; () -(*$T - let s = Bytes.of_string "hello world" in \ +(*$Q + Q.printable_string (fun s -> \ let s_len = Bytes.length s in \ let b = ByteBuffer.create s_len in \ ByteBuffer.blit_from b s 0 s_len; \ ByteBuffer.clear b; \ - ByteBuffer.length b = 0 + ByteBuffer.length b = 0) *) @@ -435,13 +435,13 @@ struct clear b; b.buf <- Array.empty -(*$T - let s = Bytes.of_string "hello world" in \ +(*$Q + Q.printable_string (fun s -> \ let s_len = Bytes.length s in \ let b = ByteBuffer.create s_len in \ ByteBuffer.blit_from b s 0 s_len; \ ByteBuffer.reset b; \ - ByteBuffer.length b = 0 && ByteBuffer.capacity b = 0 + ByteBuffer.length b = 0 && ByteBuffer.capacity b = 0) *) From 6f788d3a2a36537fc9f4c1806ca484d5e7ce2a5d Mon Sep 17 00:00:00 2001 From: carm Date: Sun, 22 Feb 2015 21:03:16 -0500 Subject: [PATCH 32/32] ringbuffer doc updates --- src/data/CCRingBuffer.ml | 2 +- src/data/CCRingBuffer.mli | 35 +++++++++++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/data/CCRingBuffer.ml b/src/data/CCRingBuffer.ml index dde33241..b1507052 100644 --- a/src/data/CCRingBuffer.ml +++ b/src/data/CCRingBuffer.ml @@ -2,7 +2,7 @@ * CCRingBuffer - Polymorphic circular buffer with * deque semantics for accessing both the head and tail. * - * Copyright (C) 2014 Simon Cruanes + * Copyright (C) 2015 Simon Cruanes, Carmelo Piccione * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/src/data/CCRingBuffer.mli b/src/data/CCRingBuffer.mli index 43b356db..100a15b8 100644 --- a/src/data/CCRingBuffer.mli +++ b/src/data/CCRingBuffer.mli @@ -1,6 +1,6 @@ (** * CCRingBuffer - Polymorphic Circular Buffer - * Copyright (C) 2014 Simon Cruanes + * Copyright (C) 2015 Simon Cruanes, Carmelo Piccione * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,53 +20,82 @@ (** Circular Polymorphic Buffer for IO *) +(** The array module, with optimized versions of [Byte], [Float], and + [Int], [Bool]. A [Make] functor is provided for polymorphic types. *) module Array : sig + (** The abstract type for arrays *) module type S = sig + + (** The element type *) type elt + + (** The type of an array instance *) type t val empty : t + (** The empty array *) val make: int -> elt -> t + (** [make s e] makes an array of size [s] with [e] elements *) val length: t -> int + (** [length t] gets the total number of elements currently in [t] *) val get: t -> int -> elt + (** [get t i] gets the element at position [i] *) val set: t -> int -> elt -> unit + (** [set t i e] sets the element at position [i] to [e] *) val sub: t -> int -> int -> t + (** [sub t i len] gets the subarray of [t] from + position [i] to [i + len] *) val copy : t -> t + (** [copy t] makes a fresh copy of the array [t] *) val blit : 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] *) val iter : (elt -> unit) -> t -> unit + (** [iter f t] iterates over the array [t] invoking [f] with + the current element, in array order *) end + (** Efficient array version for the [char] type *) module ByteArray : - S with type elt = char and type t = bytes + S with type elt = char and type t = bytes + (** Efficient array version for the [float] type *) module FloatArray : S with type elt = float and type t = float array + (** Efficient array version for the [int] type *) module IntArray : S with type elt = int and type t = int array + (** Efficient array version for the [bool] type *) module BoolArray : S with type elt = bool and type t = bool array + (** Makes an array given an arbitrary element type *) module Make : functor (Elt:sig type t end) -> S with type elt = Elt.t and type t = Elt.t array end +(** The abstract ring buffer type, made concrete by choice of + [Array] module implementation *) module type S = sig + (** The module type of Array for this ring buffer *) module Array : Array.S + (** Defines the ring buffer type, with both bounded and + unbounded flavors *) type t = private { mutable start : int; mutable stop : int; (* excluded *) @@ -74,6 +103,8 @@ sig bounded: bool; size : int } + + (** Raised in querying functions when the buffer is empty *) exception Empty val create : ?bounded:bool -> int -> t