diff --git a/CHANGELOG.md b/CHANGELOG.md index 13fa098..f77f0e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ - X10D: Added `PopCount()` for built-in integer types - X10D: Added `Quaternion.ToAxisAngle(out float, out float)` - X10D: Added `Quaternion.ToVector3()` +- X10D: Added `Random.NextFrom(Span)` and `Random.NextFrom(ReadOnlySpan)` - X10D: Added `ReadOnlySpan.CountSubstring(char)` - X10D: Added `ReadOnlySpan.CountSubstring(ReadOnlySpan[, StringComparison])` - X10D: Added `ReadOnlySpan.ToTimeSpan()` diff --git a/X10D.Tests/src/Core/RandomTests.cs b/X10D.Tests/src/Core/RandomTests.cs index 41d182b..698cc74 100644 --- a/X10D.Tests/src/Core/RandomTests.cs +++ b/X10D.Tests/src/Core/RandomTests.cs @@ -1,4 +1,5 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; +using X10D.Collections; using X10D.Core; namespace X10D.Tests.Core; @@ -126,6 +127,48 @@ public class RandomTests Assert.AreEqual(0, random.NextFrom(Source())); } + [TestMethod] + public void NextFromSpan_ShouldThrow_GivenNullRandom() + { + Random? random = null; + Assert.ThrowsException(() => + { + Span span = stackalloc int[1]; + return random!.NextFrom(span); + }); + } + + [TestMethod] + public void NextFromReadOnlySpan_ShouldThrow_GivenNullRandom() + { + Random? random = null; + Assert.ThrowsException(() => + { + Span span = stackalloc int[1]; + return random!.NextFrom(span.AsReadOnly()); + }); + } + + [TestMethod] + public void NextFromSpan_ShouldReturnOnlyValue_GivenSpanWithLength1() + { + Span span = stackalloc int[1]; + span[0] = 42; + + var random = new Random(1234); + Assert.AreEqual(42, random.NextFrom(span)); + } + + [TestMethod] + public void NextFromReadOnlySpan_ShouldReturnOnlyValue_GivenSpanWithLength1() + { + Span span = stackalloc int[1]; + span[0] = 42; + + var random = new Random(1234); + Assert.AreEqual(42, random.NextFrom(span.AsReadOnly())); + } + [TestMethod] public void NextInt16_ShouldBe13076_GivenSeed1234() { diff --git a/X10D/src/Core/RandomExtensions.cs b/X10D/src/Core/RandomExtensions.cs index c5faa0f..c4cc672 100644 --- a/X10D/src/Core/RandomExtensions.cs +++ b/X10D/src/Core/RandomExtensions.cs @@ -185,6 +185,77 @@ public static class RandomExtensions return list[random.Next(list.Count)]; } + /// + /// Returns a random element from the specified span of elements using the current instance. + /// + /// The element type. + /// The instance. + /// The span of elements from which to draw. + /// A random element of type from . + /// + /// is is + /// -or- + /// is . + /// + /// + /// + /// Span<int> span = stackalloc span[5]; + /// // populate the span ... + /// + /// var random = new Random(); + /// var number = random.NextFrom(span); + /// + /// + public static T NextFrom(this Random random, Span source) + { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(random); +#else + if (random is null) + { + throw new ArgumentNullException(nameof(random)); + } +#endif + + return source[random.Next(source.Length)]; + } + + /// + /// Returns a random element from the specified readonly span of elements using the current + /// instance. + /// + /// The element type. + /// The instance. + /// The readonly span of elements from which to draw. + /// A random element of type from . + /// + /// is is + /// -or- + /// is . + /// + /// + /// + /// Span<int> span = stackalloc span[5]; + /// // populate the span ... + /// + /// var random = new Random(); + /// var number = random.NextFrom(span.AsReadOnly()); + /// + /// + public static T NextFrom(this Random random, ReadOnlySpan source) + { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(random); +#else + if (random is null) + { + throw new ArgumentNullException(nameof(random)); + } +#endif + + return source[random.Next(source.Length)]; + } + /// /// Returns a non-negative random integer. ///