summaryrefslogtreecommitdiffstats
path: root/contrib/restricted/wavm/Include/WAVM/Inline/RandomStream.h
blob: 5f1d3a6eb8b7be3f6c25c587d10c47d150b1c3be (plain) (blame)
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
#pragma once

#include "WAVM/Inline/Assert.h"
#include "WAVM/Inline/BasicTypes.h"

namespace WAVM {
	// A stream that uses a combination of a PRNG and input data to produce pseudo-random values.
	struct RandomStream
	{
		RandomStream(const U8* inData, Uptr numBytes)
		: next(inData), end(inData + numBytes), denominator(0), numerator(0), seed(0)
		{
			refill();
		}

		// Returns a pseudo-random value between 0 and maxResult, inclusive.
		template<typename Result> Result get(Result maxResult)
		{
			Result result = Result(get64(maxResult));
			WAVM_ASSERT(result <= maxResult);
			return result;
		}

	private:
		const U8* next;
		const U8* end;

		U64 denominator;
		U64 numerator;

		U64 seed;

		void refill()
		{
			while(denominator <= UINT32_MAX)
			{
				if(next < end) { numerator += (denominator + 1) * *next++; }
				denominator += 255 * (denominator + 1);
			};
		}

		U32 get32(U32 maxResult)
		{
			if(maxResult == 0) { return 0; }

			WAVM_ASSERT(denominator >= maxResult);
			seed ^= numerator;
			const U32 result = U32(seed % (U64(maxResult) + 1));
			seed /= (U64(maxResult) + 1);
			numerator /= (U64(maxResult) + 1);
			denominator /= (U64(maxResult) + 1);
			seed = 6364136223846793005 * seed + 1442695040888963407;
			refill();
			return result;
		}

		U64 get64(U64 maxResult)
		{
			U64 result = get32(U32(maxResult));
			result += U64(get32(U32(maxResult >> 32))) << 32;
			WAVM_ASSERT(result <= maxResult);
			return result;
		}
	};
}