| // Copyright Microsoft and CHERIoT Contributors. | 
 | // SPDX-License-Identifier: MIT | 
 | // | 
 | // Imported from snmalloc 4f9d991449380ed7d881a25ba02cc5668c1ff394. | 
 |  | 
 | #pragma once | 
 |  | 
 | #include <cstdint> | 
 | #include <cstdlib> | 
 | #include <debug.hh> | 
 | #include <initializer_list> | 
 |  | 
 | namespace ds::xoroshiro | 
 | { | 
 |  | 
 | 	namespace detail | 
 | 	{ | 
 | 		using Debug = ConditionalDebug<false, "xoroshiro">; | 
 |  | 
 | 		/** | 
 | 		 * The xoroshiro+ (not ++) generator(s) of Blackman and Vigna's | 
 | 		 * Scrambled Linear Pseudorandom Number Generators | 
 | 		 * (https://arxiv.org/abs/1805.01407, Figure 1). | 
 | 		 * | 
 | 		 * This spelling is parameterized on the type of the two state | 
 | 		 * variables used internally (State), the type of each sample (Result), | 
 | 		 * and the seed state values (A, B, C). | 
 | 		 */ | 
 | 		template<typename State, | 
 | 		         typename Result, | 
 | 		         State A, | 
 | 		         State B, | 
 | 		         State C, | 
 | 		         State Jump0     = 0, | 
 | 		         State Jump1     = 0, | 
 | 		         State LongJump0 = 0, | 
 | 		         State LongJump1 = 0> | 
 | 		class XorOshiro | 
 | 		{ | 
 | 			private: | 
 | 			static constexpr unsigned StateBits  = 8 * sizeof(State); | 
 | 			static constexpr unsigned ResultBits = 8 * sizeof(Result); | 
 |  | 
 | 			static_assert(StateBits >= ResultBits, | 
 | 			              "State must have at least as many bits as Result"); | 
 |  | 
 | 			/* Parameters must be valid shifts */ | 
 | 			static_assert(0 <= A && A <= StateBits); | 
 | 			static_assert(0 <= B && B <= StateBits); | 
 | 			static_assert(0 <= C && C <= StateBits); | 
 |  | 
 | 			State x; | 
 | 			State y; | 
 |  | 
 | 			static inline State rotl(State x, State k) | 
 | 			{ | 
 | 				return (x << k) | (x >> (StateBits - k)); | 
 | 			} | 
 |  | 
 | 			void jump(State jump0, State jump1) | 
 | 			{ | 
 | 				const State Jump[] = {jump0, jump1}; | 
 | 				uint64_t    s0     = 0; | 
 | 				uint64_t    s1     = 0; | 
 | 				for (int i : {0, 1}) | 
 | 				{ | 
 | 					for (int b = 0; b < 64; b++) | 
 | 					{ | 
 | 						if (Jump[i] & uint64_t(1) << b) | 
 | 						{ | 
 | 							s0 ^= x; | 
 | 							s1 ^= y; | 
 | 						} | 
 | 						next(); | 
 | 					} | 
 | 				} | 
 | 				x = s0; | 
 | 				y = s1; | 
 | 			} | 
 |  | 
 | 			public: | 
 | 			XorOshiro(State x = 5489, State y = 0) : x(x), y(y) | 
 | 			{ | 
 | 				// If both zero, then this does not work | 
 | 				Debug::Invariant((x != 0) || (y != 0), | 
 | 				                 "Invalid state, both x and y are zero"); | 
 |  | 
 | 				next(); | 
 | 			} | 
 |  | 
 | 			void set_state(State nx, State ny = 0) | 
 | 			{ | 
 | 				// If both zero, then this does not work | 
 | 				Debug::Invariant((nx != 0) || (ny != 0), | 
 | 				                 "Invalid state, both nx and ny are zero"); | 
 |  | 
 | 				x = nx; | 
 | 				y = ny; | 
 | 				next(); | 
 | 			} | 
 |  | 
 | 			Result next() | 
 | 			{ | 
 | 				State oldX = x; | 
 | 				State oldY = y; | 
 | 				State r    = x + y; | 
 | 				y ^= x; | 
 | 				x = rotl(x, A) ^ y ^ (y << B); | 
 | 				y = rotl(y, C); | 
 | 				// If both zero, then this does not work | 
 | 				Debug::Invariant((x != 0) || (y != 0), | 
 | 				                 "Invalid state, both x and y are zero after " | 
 | 				                 "next() with x: {}, y: {}", | 
 | 				                 oldX, | 
 | 				                 oldY); | 
 | 				return r >> (StateBits - ResultBits); | 
 | 			} | 
 |  | 
 | 			Result operator()() | 
 | 			{ | 
 | 				return next(); | 
 | 			} | 
 |  | 
 | 			/** | 
 | 			 * Jump.  If supported, this is equivalent to 2^64 calls to next(). | 
 | 			 */ | 
 | 			void jump() requires(Jump0 != 0) && (Jump1 != 0) | 
 | 			{ | 
 | 				jump(Jump0, Jump1); | 
 | 			} | 
 |  | 
 | 			/** | 
 | 			 * Jump a *really* long way.  If supported, this is equivalent to | 
 | 			 * 2^96 calls to next(). | 
 | 			 */ | 
 | 			void long_jump() requires(LongJump0 != 0) && (LongJump1 != 0) | 
 | 			{ | 
 | 				jump(LongJump0, LongJump1); | 
 | 			} | 
 | 		}; | 
 | 	} // namespace detail | 
 |  | 
 | 	/** | 
 | 	 * xoroshiro128+ with 64-bit output using the 2018 parameters. | 
 | 	 * | 
 | 	 * Parameters (including jump parameters) from: | 
 | 	 * https://prng.di.unimi.it/xoroshiro128plus.c | 
 | 	 */ | 
 | 	using P128R64 = detail::XorOshiro<uint64_t, | 
 | 	                                  uint64_t, | 
 | 	                                  24, | 
 | 	                                  16, | 
 | 	                                  37, | 
 | 	                                  0xdf900294d8f554a5, | 
 | 	                                  0x170865df4b3201fc, | 
 | 	                                  0xd2a98b26625eee7b, | 
 | 	                                  0xdddf9b1090aa7ac1>; | 
 |  | 
 | 	/** | 
 | 	 * xoroshiro128+ with 32-bit output using the 2018 parameters. | 
 | 	 * | 
 | 	 * Parameters as per P128R64, above. | 
 | 	 */ | 
 | 	using P128R32 = detail::XorOshiro<uint64_t, uint32_t, 24, 16, 37>; | 
 |  | 
 | 	/** | 
 | 	 * A "xoroshiro64+" with 32-bit outputs. | 
 | 	 * | 
 | 	 * As per Sebastino Vigna himself, writing in | 
 | 	 * https://groups.google.com/g/prng/c/Ll-KDIbpO8k/m/bfHK4FlUCwAJ, these | 
 | 	 * parameters are one of may full-period triples. | 
 | 	 */ | 
 | 	using P64R32 = detail::XorOshiro<uint32_t, uint32_t, 27, 7, 20>; | 
 |  | 
 | 	/** | 
 | 	 * A "xoroshiro64+" with 16-bit outputs. | 
 | 	 * | 
 | 	 * Parameters as per P64R32, above. | 
 | 	 */ | 
 | 	using P64R16 = detail::XorOshiro<uint32_t, uint16_t, 27, 7, 20>; | 
 |  | 
 | 	/** | 
 | 	 * A "xoroshiro32+" with 16-bit outputs. | 
 | 	 * | 
 | 	 * Parameters as per the Parallax Propeller 2 PRNG (discarding the "++" | 
 | 	 * variant's fourth parameter "R").  See | 
 | 	 * https://forums.parallax.com/discussion/comment/1448894 . | 
 | 	 */ | 
 | 	using P32R16 = detail::XorOshiro<uint16_t, uint16_t, 13, 5, 10>; | 
 |  | 
 | 	/** | 
 | 	 * A "xoroshiro32+" with 16-bit outputs. | 
 | 	 * | 
 | 	 * Parameters as per P32R16, above. | 
 | 	 */ | 
 | 	using P32R8 = detail::XorOshiro<uint16_t, uint8_t, 13, 5, 10>; | 
 |  | 
 | 	/** | 
 | 	 * A "xoroshiro16+" with 8-bit outputs. | 
 | 	 * | 
 | 	 * As per Sebastino Vigna himself, writing in | 
 | 	 * https://groups.google.com/g/prng/c/MWJjq11zRis/m/7nM_cwRzAQAJ , the | 
 | 	 * parameters are one of may full-period triples, but "There are no good | 
 | 	 * 16-bit generators". | 
 | 	 */ | 
 | 	using P16R8 = detail::XorOshiro<uint8_t, uint8_t, 4, 7, 3>; | 
 | } // namespace ds::xoroshiro |