Skip to content

[Repo Assist] Fix CircularBuffer.Enqueue(array) - head pointer advances by count, not 1#233

Merged
gdziadkiewicz merged 5 commits intomasterfrom
repo-assist/fix-issue-125-circular-buffer-array-enqueue-806b1b4611ff3be2
Mar 29, 2026
Merged

[Repo Assist] Fix CircularBuffer.Enqueue(array) - head pointer advances by count, not 1#233
gdziadkiewicz merged 5 commits intomasterfrom
repo-assist/fix-issue-125-circular-buffer-array-enqueue-806b1b4611ff3be2

Conversation

@github-actions
Copy link
Copy Markdown
Contributor

@github-actions github-actions bot commented Mar 8, 2026

🤖 This PR was created by Repo Assist, an automated AI assistant.

Closes #125

Root Cause

In CircularBuffer.Enqueue(value: _[], offset, count), the head pointer was unconditionally advanced by 1, regardless of how many elements were being enqueued:

head <- (head + 1) % bufferSize   // BUG: always +1
for x, y in nextBuffer head count do
    Array.blit value offset buffer x y

This meant that after enqueueing an array of N elements, head pointed to the start of the written region, not the end. Subsequent enqueue operations then computed the wrong start position, causing data to be written to incorrect buffer locations and the tail pointer to be miscalculated.

Fix

Separate the start-position calculation from the head update, and add upfront input validation:

let startPos = (head + 1) % bufferSize   // where writing begins
for x, y in nextBuffer startPos count do
    Array.blit value offset buffer x y
    offset <- offset + y
head <- (head + count) % bufferSize      // head ends at last written position

For count = 1 (single-element enqueue, which delegates here) the behaviour is identical to before.

Input validation is now performed before any buffer mutation:

  • value must not be null
  • offset must be non-negative
  • count must be non-negative
  • offset + count must not exceed value.Length

Changes

  • src/FSharpx.Collections/CircularBuffer.fs — fix the head advancement logic; add upfront offset/count validation to prevent partial buffer corruption on bad input
  • tests/FSharpx.Collections.Tests/CircularBufferTests.fs — promote the three ptest (pending/skipped) tests to test since they now pass; add three new tests covering invalid offset/count arguments

Test Status

FSharpx.Collections.Tests: 839 passed, 2 ignored, 0 failed (includes the three newly-enabled CircularBuffer array tests and three new validation tests)

⚠️ FSharpx.Collections.Experimental.Tests: killed with exit code 137 (OOM) — this is a pre-existing infrastructure issue unrelated to this change (see issues #115 and #116).

Generated by Repo Assist ·

To install this agentic workflow, run

gh aw add githubnext/agentics/workflows/repo-assist.md@30f2254f2a7a944da1224df45d181a3f8faefd0d

🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.

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>
@dsyme
Copy link
Copy Markdown
Contributor

dsyme commented Mar 8, 2026

@gdziadkiewicz Over to you :)

@dsyme
Copy link
Copy Markdown
Contributor

dsyme commented Mar 8, 2026

@gdziadkiewicz Repo Assist creates all PRs in draft mode. There is a CI trigger in place so CI will run automatically. If it's green you can usually take them out of draft mode and assess.

@gdziadkiewicz
Copy link
Copy Markdown
Collaborator

Hi @dsyme , I somehow missed your comment here, sorry! I'm going through the PRs, reviewing and merging (starting with the stuff that is less risky or I feel more confident about). Where can I find more about repo-assist? Why did it got disabled in the repo? Can I reenable it?

I'm happy with the experience, especially when mixing repos assists with Copilot review + Copliot "do that" and with human review.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes incorrect head advancement when enqueueing multiple elements into CircularBuffer, ensuring subsequent enqueues/dequeues operate on the correct positions and previously-pending tests can be enabled.

Changes:

  • Correct CircularBuffer.Enqueue(array, offset, count) to compute the write start position separately and advance head by count.
  • Enable three previously-pending CircularBuffer array enqueue tests now that they pass.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/FSharpx.Collections/CircularBuffer.fs Fixes head update logic for array enqueues to advance by count rather than 1.
tests/FSharpx.Collections.Tests/CircularBufferTests.fs Promotes three ptest cases to active test coverage for array enqueue scenarios.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +56 to 60
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
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enqueue(value: _[], offset, count) doesn't validate offset/count against value.Length (and non-negative). If Array.blit throws (e.g., offset + count > value.Length), the buffer may already be partially overwritten (especially when length = bufferSize), leaving the collection in a corrupted state. Consider validating inputs upfront so the operation either completes fully or fails without mutating the underlying buffer.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Add validation of count and offset and add tests for it

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in commit 028c9f9. Enqueue(value, offset, count) now validates upfront (before any mutation):

  • value is not null
  • offset is non-negative
  • count is non-negative
  • offset + count does not exceed value.Length

Three new tests cover each of the invalid-argument cases.

@gdziadkiewicz gdziadkiewicz merged commit 02dc9c1 into master Mar 29, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Circular buffer does not enque arrays properly

4 participants