From a47df54502b4ad5213759c038c58717ab518af5a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 8 Mar 2026 18:09:39 +0000 Subject: [PATCH 1/3] Fix CircularBuffer.Enqueue(array) advancing head by count instead of 1 When enqueueing an array of count elements, the head pointer was only advanced by 1 instead of count, causing subsequent array enqueues to overwrite incorrect positions in the buffer. The fix separates the start position calculation from the head update: - startPos = (head + 1) % bufferSize (where writing begins) - head = (head + count) % bufferSize (where head ends after writing) Also enables the three ptest tests that were previously pending due to this bug, confirming they now pass. Closes #125 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/FSharpx.Collections/CircularBuffer.fs | 6 ++++-- tests/FSharpx.Collections.Tests/CircularBufferTests.fs | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/FSharpx.Collections/CircularBuffer.fs b/src/FSharpx.Collections/CircularBuffer.fs index ea44f8db..406b1f8a 100644 --- a/src/FSharpx.Collections/CircularBuffer.fs +++ b/src/FSharpx.Collections/CircularBuffer.fs @@ -53,12 +53,14 @@ type CircularBuffer<'T>(bufferSize: int) = let mutable offset = offset - head <- (head + 1) % bufferSize + let startPos = (head + 1) % bufferSize - for x, y in nextBuffer head count do + for x, y in nextBuffer startPos count do Array.blit value offset buffer x y offset <- offset + y + head <- (head + count) % bufferSize + if length = bufferSize then tail <- (tail + count) % bufferSize else diff --git a/tests/FSharpx.Collections.Tests/CircularBufferTests.fs b/tests/FSharpx.Collections.Tests/CircularBufferTests.fs index ae455d44..16f66113 100644 --- a/tests/FSharpx.Collections.Tests/CircularBufferTests.fs +++ b/tests/FSharpx.Collections.Tests/CircularBufferTests.fs @@ -84,7 +84,7 @@ module CircularBufferTests = Expect.throwsT "" f } - ptest "Printing after multiple enqueue circles" { + test "Printing after multiple enqueue circles" { let circularBuffer = CircularBuffer 5 circularBuffer.Enqueue [| 1; 2; 3; 4; 5 |] @@ -96,7 +96,7 @@ module CircularBufferTests = - ptest "Printing from a queue 1..8 and dequeue 5, then enqueue 1..3 and dequeue 3, from array" { + test "Printing from a queue 1..8 and dequeue 5, then enqueue 1..3 and dequeue 3, from array" { let circularBuffer = CircularBuffer 5 circularBuffer.Enqueue([| 1; 2; 3; 4; 5 |]) @@ -106,7 +106,7 @@ module CircularBufferTests = Expect.equal "buffer" [| 1; 2; 3 |] <| circularBuffer.Dequeue 3 } - ptest "Consider a large array with various, incoming array segments" { + test "Consider a large array with various, incoming array segments" { let circularBuffer = CircularBuffer 5 let source = From 624dffc11edc18c661ec5f21bca3e80ec52786a3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 8 Mar 2026 18:13:46 +0000 Subject: [PATCH 2/3] ci: trigger checks From 028c9f90e6e57aa43e2756bd162f5f720f800bed Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 29 Mar 2026 17:45:11 +0000 Subject: [PATCH 3/3] Add offset/count input validation to CircularBuffer.Enqueue and tests Agent-Logs-Url: https://github.com/fsprojects/FSharpx.Collections/sessions/650cdd45-dd1e-4c67-8bc3-2a4dcbc5e426 Co-authored-by: gdziadkiewicz <8547855+gdziadkiewicz@users.noreply.github.com> --- src/FSharpx.Collections/CircularBuffer.fs | 12 +++++++++ .../CircularBufferTests.fs | 27 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/FSharpx.Collections/CircularBuffer.fs b/src/FSharpx.Collections/CircularBuffer.fs index 406b1f8a..5359b20b 100644 --- a/src/FSharpx.Collections/CircularBuffer.fs +++ b/src/FSharpx.Collections/CircularBuffer.fs @@ -48,6 +48,18 @@ type CircularBuffer<'T>(bufferSize: int) = dequeued member this.Enqueue(value: _[], offset, count) = + if isNull value then + invalidArg "value" "value must not be null." + + if offset < 0 then + invalidArg "offset" "offset must not be negative." + + if count < 0 then + invalidArg "count" "count must not be negative." + + if offset + count > value.Length then + invalidArg "count" "offset and count exceed the length of the source array." + if count > bufferSize then invalidOp "Requested count is too large." diff --git a/tests/FSharpx.Collections.Tests/CircularBufferTests.fs b/tests/FSharpx.Collections.Tests/CircularBufferTests.fs index 16f66113..d371ddc7 100644 --- a/tests/FSharpx.Collections.Tests/CircularBufferTests.fs +++ b/tests/FSharpx.Collections.Tests/CircularBufferTests.fs @@ -84,6 +84,33 @@ module CircularBufferTests = Expect.throwsT "" f } + test "fail on negative offset" { + let f = + fun _ -> + let circularBuffer = CircularBuffer 5 + circularBuffer.Enqueue([| 1; 2; 3 |], -1, 2) + + Expect.throwsT "" f + } + + test "fail on negative count" { + let f = + fun _ -> + let circularBuffer = CircularBuffer 5 + circularBuffer.Enqueue([| 1; 2; 3 |], 0, -1) + + Expect.throwsT "" f + } + + test "fail when offset + count exceeds array length" { + let f = + fun _ -> + let circularBuffer = CircularBuffer 5 + circularBuffer.Enqueue([| 1; 2; 3 |], 2, 3) + + Expect.throwsT "" f + } + test "Printing after multiple enqueue circles" { let circularBuffer = CircularBuffer 5