File: RandomNumberGenerator.cs

package info (click to toggle)
mono 6.8.0.105%2Bdfsg-3.3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 1,284,512 kB
  • sloc: cs: 11,172,132; xml: 2,850,069; ansic: 671,653; cpp: 122,091; perl: 59,366; javascript: 30,841; asm: 22,168; makefile: 20,093; sh: 15,020; python: 4,827; pascal: 925; sql: 859; sed: 16; php: 1
file content (99 lines) | stat: -rw-r--r-- 2,504 bytes parent folder | download | duplicates (5)
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);
		}
	}
}