Add Random.NextFrom([ReadOnly]Span<T>)

This commit is contained in:
Oliver Booth 2023-02-27 13:15:20 +00:00
parent d1454a1170
commit 3fc2e7259e
No known key found for this signature in database
GPG Key ID: 20BEB9DC87961025
3 changed files with 115 additions and 0 deletions

View File

@ -38,6 +38,7 @@
- X10D: Added `PopCount()` for built-in integer types - X10D: Added `PopCount()` for built-in integer types
- X10D: Added `Quaternion.ToAxisAngle(out float, out float)` - X10D: Added `Quaternion.ToAxisAngle(out float, out float)`
- X10D: Added `Quaternion.ToVector3()` - X10D: Added `Quaternion.ToVector3()`
- X10D: Added `Random.NextFrom(Span<T>)` and `Random.NextFrom(ReadOnlySpan<T>)`
- X10D: Added `ReadOnlySpan<char>.CountSubstring(char)` - X10D: Added `ReadOnlySpan<char>.CountSubstring(char)`
- X10D: Added `ReadOnlySpan<char>.CountSubstring(ReadOnlySpan<char>[, StringComparison])` - X10D: Added `ReadOnlySpan<char>.CountSubstring(ReadOnlySpan<char>[, StringComparison])`
- X10D: Added `ReadOnlySpan<char>.ToTimeSpan()` - X10D: Added `ReadOnlySpan<char>.ToTimeSpan()`

View File

@ -1,4 +1,5 @@
using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting;
using X10D.Collections;
using X10D.Core; using X10D.Core;
namespace X10D.Tests.Core; namespace X10D.Tests.Core;
@ -126,6 +127,48 @@ public class RandomTests
Assert.AreEqual(0, random.NextFrom(Source())); Assert.AreEqual(0, random.NextFrom(Source()));
} }
[TestMethod]
public void NextFromSpan_ShouldThrow_GivenNullRandom()
{
Random? random = null;
Assert.ThrowsException<ArgumentNullException>(() =>
{
Span<int> span = stackalloc int[1];
return random!.NextFrom(span);
});
}
[TestMethod]
public void NextFromReadOnlySpan_ShouldThrow_GivenNullRandom()
{
Random? random = null;
Assert.ThrowsException<ArgumentNullException>(() =>
{
Span<int> span = stackalloc int[1];
return random!.NextFrom(span.AsReadOnly());
});
}
[TestMethod]
public void NextFromSpan_ShouldReturnOnlyValue_GivenSpanWithLength1()
{
Span<int> 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<int> span = stackalloc int[1];
span[0] = 42;
var random = new Random(1234);
Assert.AreEqual(42, random.NextFrom(span.AsReadOnly()));
}
[TestMethod] [TestMethod]
public void NextInt16_ShouldBe13076_GivenSeed1234() public void NextInt16_ShouldBe13076_GivenSeed1234()
{ {

View File

@ -185,6 +185,77 @@ public static class RandomExtensions
return list[random.Next(list.Count)]; return list[random.Next(list.Count)];
} }
/// <summary>
/// Returns a random element from the specified span of elements using the current <see cref="System.Random" /> instance.
/// </summary>
/// <typeparam name="T">The element type.</typeparam>
/// <param name="random">The <see cref="System.Random" /> instance.</param>
/// <param name="source">The span of elements from which to draw.</param>
/// <returns>A random element of type <typeparamref name="T" /> from <paramref name="source" />.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="random" /> is is <see langword="null" />
/// -or-
/// <paramref name="source" /> is <see langword="null" />.
/// </exception>
/// <example>
/// <code lang="csharp">
/// Span&lt;int&gt; span = stackalloc span[5];
/// // populate the span ...
///
/// var random = new Random();
/// var number = random.NextFrom(span);
/// </code>
/// </example>
public static T NextFrom<T>(this Random random, Span<T> 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)];
}
/// <summary>
/// Returns a random element from the specified readonly span of elements using the current <see cref="System.Random" />
/// instance.
/// </summary>
/// <typeparam name="T">The element type.</typeparam>
/// <param name="random">The <see cref="System.Random" /> instance.</param>
/// <param name="source">The readonly span of elements from which to draw.</param>
/// <returns>A random element of type <typeparamref name="T" /> from <paramref name="source" />.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="random" /> is is <see langword="null" />
/// -or-
/// <paramref name="source" /> is <see langword="null" />.
/// </exception>
/// <example>
/// <code lang="csharp">
/// Span&lt;int&gt; span = stackalloc span[5];
/// // populate the span ...
///
/// var random = new Random();
/// var number = random.NextFrom(span.AsReadOnly());
/// </code>
/// </example>
public static T NextFrom<T>(this Random random, ReadOnlySpan<T> 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)];
}
/// <summary> /// <summary>
/// Returns a non-negative random integer. /// Returns a non-negative random integer.
/// </summary> /// </summary>