RandomExtensions
Provides random data generation.
using DotNext.Buffers;
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
namespace DotNext
{
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
public static class RandomExtensions
{
[System.Runtime.CompilerServices.NullableContext(0)]
private interface IRandomStringGenerator
{
void NextString(Span<char> buffer, ReadOnlySpan<char> allowedChars);
}
[StructLayout(LayoutKind.Auto)]
[System.Runtime.CompilerServices.NullableContext(0)]
private readonly struct PseudoRandomStringGenerator : IRandomStringGenerator
{
[System.Runtime.CompilerServices.Nullable(1)]
private readonly Random rng;
[System.Runtime.CompilerServices.NullableContext(1)]
internal PseudoRandomStringGenerator(Random random)
{
rng = random;
}
void IRandomStringGenerator.NextString(Span<char> buffer, ReadOnlySpan<char> allowedChars)
{
ref char reference = ref MemoryMarshal.GetReference(allowedChars);
Span<char> span = buffer;
for (int i = 0; i < span.Length; i++) {
span[i] = Unsafe.Add(ref reference, rng.Next(0, allowedChars.Length));
}
}
}
[StructLayout(LayoutKind.Auto)]
[System.Runtime.CompilerServices.NullableContext(0)]
private readonly struct RandomStringGenerator : IRandomStringGenerator
{
[System.Runtime.CompilerServices.Nullable(1)]
private readonly RandomNumberGenerator rng;
[System.Runtime.CompilerServices.NullableContext(1)]
internal RandomStringGenerator(RandomNumberGenerator random)
{
rng = random;
}
unsafe void IRandomStringGenerator.NextString(Span<char> buffer, ReadOnlySpan<char> allowedChars)
{
int num = buffer.Length * 4;
MemoryRental<byte> memoryRental;
if (num > MemoryRental<byte>.StackallocThreshold)
memoryRental = new MemoryRental<byte>(num);
else {
int num2 = num;
memoryRental = new Span<byte>(stackalloc byte[(int)(uint)num2], num2);
}
MemoryRental<byte> memoryRental2 = memoryRental;
try {
rng.GetBytes(memoryRental2.Span);
num = 0;
ref char reference = ref MemoryMarshal.GetReference(allowedChars);
Span<char> span = buffer;
for (int num2 = 0; num2 < span.Length; num2++) {
ref char reference2 = ref span[num2];
int elementOffset = (BitConverter.ToInt32(memoryRental2.Span.Slice(num)) & 2147483647) % allowedChars.Length;
reference2 = Unsafe.Add(ref reference, elementOffset);
num += 4;
}
} finally {
memoryRental2.Dispose();
}
}
}
internal static readonly int BitwiseHashSalt = new Random().Next();
[System.Runtime.CompilerServices.NullableContext(0)]
[return: System.Runtime.CompilerServices.Nullable(1)]
private unsafe static string NextString<TGenerator>(TGenerator generator, ReadOnlySpan<char> allowedChars, int length) where TGenerator : struct, IRandomStringGenerator
{
if (length < 0)
throw new ArgumentOutOfRangeException("length");
if (length != 0 && !allowedChars.IsEmpty) {
MemoryRental<char> memoryRental = (length <= MemoryRental<char>.StackallocThreshold) ? ((MemoryRental<char>)new Span<char>((void*)stackalloc byte[(int)checked(unchecked((ulong)(uint)length) * 2)], length)) : new MemoryRental<char>(length);
MemoryRental<char> memoryRental2 = memoryRental;
try {
generator.NextString(memoryRental2.Span, allowedChars);
return new string(memoryRental2.Span);
} finally {
memoryRental2.Dispose();
}
}
return string.Empty;
}
public static string NextString(this Random random, [System.Runtime.CompilerServices.Nullable(0)] ReadOnlySpan<char> allowedChars, int length)
{
return NextString(new PseudoRandomStringGenerator(random), allowedChars, length);
}
public static string NextString(this Random random, char[] allowedChars, int length)
{
return random.NextString(new ReadOnlySpan<char>(allowedChars), length);
}
public static string NextString(this Random random, string allowedChars, int length)
{
return random.NextString(allowedChars.AsSpan(), length);
}
public static string NextString(this RandomNumberGenerator random, [System.Runtime.CompilerServices.Nullable(0)] ReadOnlySpan<char> allowedChars, int length)
{
return NextString(new RandomStringGenerator(random), allowedChars, length);
}
public static string NextString(this RandomNumberGenerator random, char[] allowedChars, int length)
{
return random.NextString(new ReadOnlySpan<char>(allowedChars), length);
}
public static string NextString(this RandomNumberGenerator random, string allowedChars, int length)
{
return random.NextString(allowedChars.AsSpan(), length);
}
public static bool NextBoolean(this Random random, double trueProbability = 0.5)
{
if (!trueProbability.Between(0, 1, BoundType.Closed))
throw new ArgumentOutOfRangeException("trueProbability");
return random.NextDouble() >= 1 - trueProbability;
}
public static int Next(this RandomNumberGenerator random)
{
return random.Next<int>() & 2147483647;
}
public static bool NextBoolean(this RandomNumberGenerator random, double trueProbability = 0.5)
{
if (!trueProbability.Between(0, 1, BoundType.Closed))
throw new ArgumentOutOfRangeException("trueProbability");
return random.NextDouble() >= 1 - trueProbability;
}
public static double NextDouble(this RandomNumberGenerator random)
{
double num = (double)random.Next();
return num / (num + 1);
}
[System.Runtime.CompilerServices.NullableContext(0)]
public unsafe static T Next<[System.Runtime.CompilerServices.IsUnmanaged] T>([System.Runtime.CompilerServices.Nullable(1)] this Random random) where T : struct
{
T result = default(T);
random.NextBytes(new Span<byte>((void*)(&result), sizeof(T)));
return result;
}
[System.Runtime.CompilerServices.NullableContext(0)]
public unsafe static T Next<[System.Runtime.CompilerServices.IsUnmanaged] T>([System.Runtime.CompilerServices.Nullable(1)] this RandomNumberGenerator random) where T : struct
{
T result = default(T);
random.GetBytes(new Span<byte>((void*)(&result), sizeof(T)));
return result;
}
}
}