1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
|
using System.Buffers;
using System.Runtime.InteropServices;
namespace System.Security.Cryptography
{
partial class RandomNumberGenerator
{
public static void Fill (Span<byte> data)
{
FillSpan (data);
}
internal static unsafe void FillSpan (Span<byte> data)
{
if (data.Length > 0) {
fixed (byte* ptr = data) Interop.GetRandomBytes (ptr, data.Length);
}
}
public virtual void GetBytes(Span<byte> data)
{
byte[] array = ArrayPool<byte>.Shared.Rent(data.Length);
try
{
GetBytes(array, 0, data.Length);
new ReadOnlySpan<byte>(array, 0, data.Length).CopyTo(data);
}
finally
{
Array.Clear(array, 0, data.Length);
ArrayPool<byte>.Shared.Return(array);
}
}
public virtual void GetNonZeroBytes(Span<byte> data)
{
byte[] array = ArrayPool<byte>.Shared.Rent(data.Length);
try
{
// NOTE: There is no GetNonZeroBytes(byte[], int, int) overload, so this call
// may end up retrieving more data than was intended, if the array pool
// gives back a larger array than was actually needed.
GetNonZeroBytes(array);
new ReadOnlySpan<byte>(array, 0, data.Length).CopyTo(data);
}
finally
{
Array.Clear(array, 0, data.Length);
ArrayPool<byte>.Shared.Return(array);
}
}
public static int GetInt32(int fromInclusive, int toExclusive)
{
if (fromInclusive >= toExclusive)
throw new ArgumentException(SR.Argument_InvalidRandomRange);
// The total possible range is [0, 4,294,967,295).
// Subtract one to account for zero being an actual possibility.
uint range = (uint)toExclusive - (uint)fromInclusive - 1;
// If there is only one possible choice, nothing random will actually happen, so return
// the only possibility.
if (range == 0)
{
return fromInclusive;
}
// Create a mask for the bits that we care about for the range. The other bits will be
// masked away.
uint mask = range;
mask |= mask >> 1;
mask |= mask >> 2;
mask |= mask >> 4;
mask |= mask >> 8;
mask |= mask >> 16;
Span<uint> resultSpan = stackalloc uint[1];
uint result;
do
{
FillSpan(MemoryMarshal.AsBytes(resultSpan));
result = mask & resultSpan[0];
}
while (result > range);
return (int)result + fromInclusive;
}
public static int GetInt32(int toExclusive)
{
if (toExclusive <= 0)
throw new ArgumentOutOfRangeException(nameof(toExclusive), SR.ArgumentOutOfRange_NeedPosNum);
return GetInt32(0, toExclusive);
}
}
}
|