Skip to content

fix: throw when a RingBuffer is modified during enumeration [patch] - #100

Merged
matt-edmondson merged 1 commit into
mainfrom
fix/ringbuffer-fail-fast-86
Oct 6, 2026
Merged

matt-edmondson merged 1 commit into
mainfrom
fix/ringbuffer-fail-fast-86

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Summary

After #70 / #84, RingBuffer<T> was the only container whose enumerator did not fail fast. On a full buffer, calling PushBack inside a foreach shifts every logical index, so the loop silently skipped an element. Calling Resample or Resize mid-loop also corrupted the enumeration without raising an error.

This follows the ContiguousCollection pattern:

  • a private version field, incremented in PushBack, Clear and AllocateBuffer. AllocateBuffer covers both Resize and Resample.
  • GetEnumerator() now returns Enumerate(version), which calls Enumeration.ThrowIfModified before each yield and once after the loop.

Tests

  • New tests check that a modification during foreach throws InvalidOperationException for each mutator: PushBack, Clear, Resize and Resample.
  • Another test covers a modification after the last element, which throws on the final MoveNext.
  • A control test confirms that modifying the buffer between two enumerations does not throw.
  • I ran the five throwing tests against the unfixed code first and all five failed. They pass with the change.
  • Full suite: 429/429 pass locally (net10.0).

This PR is independent of #99 (#85, eviction leak). Both touch PushBack but in different lines, so they merge cleanly in either order.

Fixes #86

🤖 Generated with Claude Code

https://claude.ai/code/session_01UoSUYMQMykgfsb5y6AhnKb


Generated by Claude Code

RingBuffer was the last container whose enumerator did not fail fast.
On a full buffer PushBack shifts every logical index, so pushing inside
a foreach silently skipped an element, and Resample or Resize
repeated or dropped elements without any error.

Add a version field bumped by PushBack, Clear and AllocateBuffer (which
covers Resize and Resample), and check it through
Enumeration.ThrowIfModified the same way ContiguousCollection does.

Fixes #86

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UoSUYMQMykgfsb5y6AhnKb
@sonarqubecloud

sonarqubecloud Bot commented Oct 6, 2026

Copy link
Copy Markdown

@matt-edmondson
matt-edmondson merged commit 6047b5f into main Oct 6, 2026
14 checks passed
@matt-edmondson
matt-edmondson deleted the fix/ringbuffer-fail-fast-86 branch October 6, 2026 02:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Modifying a RingBuffer during foreach silently skips or repeats elements instead of throwing

2 participants