7 people like it.
Like the snippet!
Circular Buffer
A Circular, or Ring, Buffer that flattens incoming arrays and allows consumers to take arbitrary-sized chunks. Improvements and suggestions welcome. Fork my gist at https://gist.github.com/1648579.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
|
type CircularBuffer<'a> (bufferSize: int) =
do if bufferSize <= 0 then invalidArg "bufferSize" "The bufferSize must be greater than 0."
let buffer = Array.zeroCreate<'a> bufferSize
let mutable head = bufferSize - 1
let mutable tail = 0
let mutable length = 0
let rec nextBuffer offset count =
seq {
let overflow = count + offset - bufferSize
if overflow > 0 then
yield (offset, bufferSize - offset)
yield! nextBuffer 0 overflow
else
yield (offset, count)
}
member this.Dequeue(count) =
if length = 0 then invalidOp "Queue exhausted."
if count > length then invalidOp "Requested count is too large."
let dequeued = Array.concat [| for o, c in nextBuffer tail count -> buffer.[o..o+c-1] |]
tail <- (tail + count) % bufferSize
length <- length - count
dequeued
member this.Enqueue(value) =
head <- (head + 1) % bufferSize
buffer.[head] <- value
if length = bufferSize then
tail <- (tail + 1) % bufferSize
else
length <- length + 1
member this.Enqueue(value: 'a[]) =
for x in value do this.Enqueue(x)
|
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
|
let queue = CircularBuffer(5)
let stopwatch = Stopwatch.StartNew()
// Printing from a queue 1..5
queue.Enqueue(1)
queue.Enqueue(2)
queue.Enqueue(3)
queue.Enqueue(4)
queue.Enqueue(5)
Debug.Assert([|1;2;3;4;5|] = queue.Dequeue(5))
// Printing from a queue 1..8, twice
queue.Enqueue(1)
queue.Enqueue(2)
queue.Enqueue(3)
queue.Enqueue(4)
queue.Enqueue(5) // <---
queue.Enqueue(6)
queue.Enqueue(7)
queue.Enqueue(8)
queue.Enqueue(1)
queue.Enqueue(2) // <---
queue.Enqueue(3)
queue.Enqueue(4)
queue.Enqueue(5)
queue.Enqueue(6)
queue.Enqueue(7) // <---
queue.Enqueue(8)
Debug.Assert([|4;5;6;7;8|] = queue.Dequeue(5))
// Printing from a queue 1..5
queue.Enqueue(1)
queue.Enqueue(2)
queue.Enqueue(3)
queue.Enqueue(4)
queue.Enqueue(5)
Debug.Assert([|1;2;3|] = queue.Dequeue(3))
// Clear out the rest
queue.Dequeue(2)
// Printing from a queue 1..3
queue.Enqueue(1)
queue.Enqueue(2)
queue.Enqueue(3)
Debug.Assert([|1;2;3|] = queue.Dequeue(3))
// Printing from a queue 1..8 and dequeue 5, then enqueue 1..3 and dequeue 3
queue.Enqueue(1)
queue.Enqueue(2)
queue.Enqueue(3)
queue.Enqueue(4)
queue.Enqueue(5) // <---
queue.Enqueue(6)
queue.Enqueue(7)
queue.Enqueue(8)
Debug.Assert([|4;5;6;7;8|] = queue.Dequeue(5))
queue.Enqueue(1)
queue.Enqueue(2)
queue.Enqueue(3)
Debug.Assert([|1;2;3|] = queue.Dequeue(3))
printfn "Enqueue(value) tests passed in %d ms" stopwatch.ElapsedMilliseconds
stopwatch.Reset()
stopwatch.Start()
// Printing from a queue 1..5
queue.Enqueue([|1;2;3;4;5|])
Debug.Assert([|1;2;3;4;5|] = queue.Dequeue(5))
// Printing from a queue 1..8, twice
queue.Enqueue([|1;2;3;4;5;6;7;8;1;2;3;4;5;6;7;8|])
Debug.Assert([|4;5;6;7;8|] = queue.Dequeue(5))
// Printing from a queue 1..5
queue.Enqueue([|1;2;3;4;5|])
Debug.Assert([|1;2;3|] = queue.Dequeue(3))
// Clear out the rest
queue.Dequeue(2)
// Printing from a queue 1..3
queue.Enqueue([|1;2;3|])
Debug.Assert([|1;2;3|] = queue.Dequeue(3))
// Printing from a queue 1..8 and dequeue 5, then enqueue 1..3 and dequeue 3
queue.Enqueue([|1;2;3;4;5;6;7;8|])
Debug.Assert([|4;5;6;7;8|] = queue.Dequeue(5))
queue.Enqueue([|1;2;3|])
Debug.Assert([|1;2;3|] = queue.Dequeue(3))
printfn "Enqueue(array) tests passed in %d ms" stopwatch.ElapsedMilliseconds
|
Multiple items
type CircularBuffer<'a> =
new : bufferSize:int -> CircularBuffer<'a>
member Dequeue : count:int -> 'a []
member Enqueue : value:'a -> unit
member Enqueue : value:'a [] -> unit
Full name: Script.CircularBuffer<_>
--------------------
new : bufferSize:int -> CircularBuffer<'a>
val bufferSize : int
Multiple items
val int : value:'T -> int (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.Operators.int
--------------------
type int = int32
Full name: Microsoft.FSharp.Core.int
--------------------
type int<'Measure> = int
Full name: Microsoft.FSharp.Core.int<_>
val invalidArg : argumentName:string -> message:string -> 'T
Full name: Microsoft.FSharp.Core.Operators.invalidArg
val buffer : 'a []
module Array
from Microsoft.FSharp.Collections
val zeroCreate : count:int -> 'T []
Full name: Microsoft.FSharp.Collections.Array.zeroCreate
val mutable head : int
val mutable tail : int
val mutable length : int
val nextBuffer : (int -> int -> seq<int * int>)
val offset : int
val count : int
Multiple items
val seq : sequence:seq<'T> -> seq<'T>
Full name: Microsoft.FSharp.Core.Operators.seq
--------------------
type seq<'T> = System.Collections.Generic.IEnumerable<'T>
Full name: Microsoft.FSharp.Collections.seq<_>
val overflow : int
val this : CircularBuffer<'a>
member CircularBuffer.Dequeue : count:int -> 'a []
Full name: Script.CircularBuffer`1.Dequeue
val invalidOp : message:string -> 'T
Full name: Microsoft.FSharp.Core.Operators.invalidOp
val dequeued : 'a []
val concat : arrays:seq<'T []> -> 'T []
Full name: Microsoft.FSharp.Collections.Array.concat
val o : int
val c : int
member CircularBuffer.Enqueue : value:'a -> unit
Full name: Script.CircularBuffer`1.Enqueue
val value : 'a
member CircularBuffer.Enqueue : value:'a [] -> unit
Full name: Script.CircularBuffer`1.Enqueue
val value : 'a []
val x : 'a
member CircularBuffer.Enqueue : value:'a -> unit
member CircularBuffer.Enqueue : value:'a [] -> unit
val queue : CircularBuffer<int>
Full name: Script.queue
val stopwatch : Stopwatch
Full name: Script.stopwatch
Multiple items
type Stopwatch =
new : unit -> Stopwatch
member Elapsed : TimeSpan
member ElapsedMilliseconds : int64
member ElapsedTicks : int64
member IsRunning : bool
member Reset : unit -> unit
member Restart : unit -> unit
member Start : unit -> unit
member Stop : unit -> unit
static val Frequency : int64
...
Full name: System.Diagnostics.Stopwatch
--------------------
Stopwatch() : unit
Stopwatch.StartNew() : Stopwatch
type Debug =
static member Assert : condition:bool -> unit + 3 overloads
static member AutoFlush : bool with get, set
static member Close : unit -> unit
static member Fail : message:string -> unit + 1 overload
static member Flush : unit -> unit
static member Indent : unit -> unit
static member IndentLevel : int with get, set
static member IndentSize : int with get, set
static member Listeners : TraceListenerCollection
static member Print : message:string -> unit + 1 overload
...
Full name: System.Diagnostics.Debug
Debug.Assert(condition: bool) : unit
Debug.Assert(condition: bool, message: string) : unit
Debug.Assert(condition: bool, message: string, detailMessage: string) : unit
Debug.Assert(condition: bool, message: string, detailMessageFormat: string, [<System.ParamArray>] args: obj []) : unit
member CircularBuffer.Dequeue : count:int -> 'a []
val printfn : format:Printf.TextWriterFormat<'T> -> 'T
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
property Stopwatch.ElapsedMilliseconds: int64
Stopwatch.Reset() : unit
Stopwatch.Start() : unit
More information