From fdde1980cada77656e28fb75784282fdd47f908f Mon Sep 17 00:00:00 2001 From: Steven Giesel Date: Thu, 8 Jun 2023 21:23:18 +0200 Subject: [PATCH] feat: Builder can be used in foreach loops --- CHANGELOG.md | 4 ++ .../ValueStringBuilder.Enumerator.cs | 48 +++++++++++++++++++ stylecop.analyzers.ruleset | 2 + .../ValueStringBuilderTests.cs | 14 ++++++ 4 files changed, 68 insertions(+) create mode 100644 src/LinkDotNet.StringBuilder/ValueStringBuilder.Enumerator.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index abb2f7a..478943c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ All notable changes to **ValueStringBuilder** will be documented in this file. T ## [Unreleased] +### Added + +- Added custom enumerator to `ValueStringBuilder` so it can be used in `foreach` loops + ## [1.17.0] - 2023-04-13 ### Added diff --git a/src/LinkDotNet.StringBuilder/ValueStringBuilder.Enumerator.cs b/src/LinkDotNet.StringBuilder/ValueStringBuilder.Enumerator.cs new file mode 100644 index 0000000..08b829f --- /dev/null +++ b/src/LinkDotNet.StringBuilder/ValueStringBuilder.Enumerator.cs @@ -0,0 +1,48 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace LinkDotNet.StringBuilder; + +public ref partial struct ValueStringBuilder +{ + public readonly Enumerator GetEnumerator() => new(buffer[..bufferPosition]); + + /// Enumerates the elements of a . + [StructLayout(LayoutKind.Auto)] + public ref struct Enumerator + { + private readonly Span span; + private int index; + + /// Initializes a new instance of the struct. + /// The span to enumerate. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(Span span) + { + this.span = span; + index = -1; + } + + /// Gets the element at the current position of the enumerator. + public ref char Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref span[index]; + } + + /// Advances the enumerator to the next element of the span. + /// True if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the span. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + var nextIndex = index + 1; + if (nextIndex < span.Length) + { + index = nextIndex; + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/stylecop.analyzers.ruleset b/stylecop.analyzers.ruleset index 3c61a4c..660192c 100644 --- a/stylecop.analyzers.ruleset +++ b/stylecop.analyzers.ruleset @@ -9,6 +9,8 @@ + + diff --git a/tests/LinkDotNet.StringBuilder.UnitTests/ValueStringBuilderTests.cs b/tests/LinkDotNet.StringBuilder.UnitTests/ValueStringBuilderTests.cs index 655a296..44d8528 100644 --- a/tests/LinkDotNet.StringBuilder.UnitTests/ValueStringBuilderTests.cs +++ b/tests/LinkDotNet.StringBuilder.UnitTests/ValueStringBuilderTests.cs @@ -489,4 +489,18 @@ public void GivenAString_WhenCallingToStringWithRange_ThenShouldReturnSubstring( builder.ToString(1..4).Should().Be("ell"); } + + [Fact] + public void GivenAString_WhenEnumerating_ThenShouldReturnCharacters() + { + using var builder = new ValueStringBuilder("Hello World"); + var output = string.Empty; + + foreach (var c in builder) + { + output += c; + } + + output.Should().Be("Hello World"); + } } \ No newline at end of file