From 0621c246a0db7e8ac07a8c4fad31ff2fbeff3163 Mon Sep 17 00:00:00 2001 From: Oliver Booth Date: Thu, 6 Apr 2023 02:31:22 +0100 Subject: [PATCH] feat: add Span.Replace --- CHANGELOG.md | 1 + X10D.Tests/src/Collections/SpanTest.cs | 24 +++++++++++++++++++++++ X10D/src/Collections/SpanExtensions.cs | 27 +++++++++++++++++++++++++- 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c978814..a0fcace 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - X10D: Added extension methods for `DateOnly`, for parity with `DateTime` and `DateTimeOffset`. - X10D: Added math-related extension methods for `BigInteger`. +- X10D: Added `Span.Replace(T, T)`. ### Changed - X10D: `DateTime.Age(DateTime)` and `DateTimeOffset.Age(DateTimeOffset)` parameter renamed from `asOf` to `referenceDate`. diff --git a/X10D.Tests/src/Collections/SpanTest.cs b/X10D.Tests/src/Collections/SpanTest.cs index 5df5acd..0c59d1c 100644 --- a/X10D.Tests/src/Collections/SpanTest.cs +++ b/X10D.Tests/src/Collections/SpanTest.cs @@ -46,6 +46,30 @@ public class SpanTest Assert.That(count, Is.EqualTo(8)); } + [Test] + public void Replace_ShouldReplaceAllElements_GivenSpanOfInt32() + { + Span span = stackalloc int[16] {1, 2, 3, 2, 5, 2, 7, 2, 9, 2, 11, 2, 13, 2, 15, 2}; + span.Replace(2, 4); + Assert.That(span.ToArray(), Is.EqualTo(new[] {1, 4, 3, 4, 5, 4, 7, 4, 9, 4, 11, 4, 13, 4, 15, 4})); + } + + [Test] + public void Replace_ShouldReplaceAllElements_GivenSpanOfChar() + { + Span chars = stackalloc char[12] {'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!'}; + chars.Replace('l', 'w'); + CollectionAssert.AreEqual(chars.ToArray(), "Hewwo worwd!".ToCharArray()); + } + + [Test] + public void Replace_ShouldDoNothing_GivenSpanWithNoMatchingElements() + { + Span span = stackalloc int[16] {1, 2, 3, 2, 5, 2, 7, 2, 9, 2, 11, 2, 13, 2, 15, 2}; + span.Replace(4, 8); + Assert.That(span.ToArray(), Is.EqualTo(new[] {1, 2, 3, 2, 5, 2, 7, 2, 9, 2, 11, 2, 13, 2, 15, 2})); + } + [Test] public void Split_OnEmptySpan_ShouldYieldNothing_UsingCharDelimiter_GivenReadOnlySpan() { diff --git a/X10D/src/Collections/SpanExtensions.cs b/X10D/src/Collections/SpanExtensions.cs index 78d6c8b..1aee61d 100644 --- a/X10D/src/Collections/SpanExtensions.cs +++ b/X10D/src/Collections/SpanExtensions.cs @@ -1,4 +1,9 @@ -namespace X10D.Collections; +#if NET5_0_OR_GREATER +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#endif + +namespace X10D.Collections; /// /// Extension methods for and @@ -53,6 +58,26 @@ public static class SpanExtensions return source; } + /// + /// Replaces all occurrences of a specified element in a span of elements with another specified element. + /// + /// The source span. + /// The element to replace. + /// The replacement element. + /// The type of elements in . + public static void Replace(this Span haystack, T needle, T replacement) where T : struct + { + var comparer = EqualityComparer.Default; + + for (var index = 0; index < haystack.Length; index++) + { + if (comparer.Equals(haystack[index], needle)) + { + haystack[index] = replacement; + } + } + } + /// /// Splits a span of elements into sub-spans based on a delimiting element. ///