1 | cfg_rt! { |
---|---|

2 | mod rt; |

3 | pub(crate) use rt::RngSeedGenerator; |

4 | |

5 | cfg_unstable! { |

6 | mod rt_unstable; |

7 | } |

8 | } |

9 | |

10 | /// A seed for random number generation. |

11 | /// |

12 | /// In order to make certain functions within a runtime deterministic, a seed |

13 | /// can be specified at the time of creation. |

14 | #[allow(unreachable_pub)] |

15 | #[derive(Clone, Debug)] |

16 | pub struct RngSeed { |

17 | s: u32, |

18 | r: u32, |

19 | } |

20 | |

21 | /// Fast random number generate. |

22 | /// |

23 | /// Implement xorshift64+: 2 32-bit xorshift sequences added together. |

24 | /// Shift triplet `[17,7,16]` was calculated as indicated in Marsaglia's |

25 | /// Xorshift paper: <https://www.jstatsoft.org/article/view/v008i14/xorshift.pdf> |

26 | /// This generator passes the SmallCrush suite, part of TestU01 framework: |

27 | /// <http://simul.iro.umontreal.ca/testu01/tu01.html> |

28 | #[derive(Clone, Copy, Debug)] |

29 | pub(crate) struct FastRand { |

30 | one: u32, |

31 | two: u32, |

32 | } |

33 | |

34 | impl RngSeed { |

35 | /// Creates a random seed using loom internally. |

36 | pub(crate) fn new() -> Self { |

37 | Self::from_u64(crate::loom::rand::seed()) |

38 | } |

39 | |

40 | fn from_u64(seed: u64) -> Self { |

41 | let one = (seed >> 32) as u32; |

42 | let mut two = seed as u32; |

43 | |

44 | if two == 0 { |

45 | // This value cannot be zero |

46 | two = 1; |

47 | } |

48 | |

49 | Self::from_pair(one, two) |

50 | } |

51 | |

52 | fn from_pair(s: u32, r: u32) -> Self { |

53 | Self { s, r } |

54 | } |

55 | } |

56 | |

57 | impl FastRand { |

58 | /// Initialize a new fast random number generator using the default source of entropy. |

59 | pub(crate) fn new() -> FastRand { |

60 | FastRand::from_seed(RngSeed::new()) |

61 | } |

62 | |

63 | /// Initializes a new, thread-local, fast random number generator. |

64 | pub(crate) fn from_seed(seed: RngSeed) -> FastRand { |

65 | FastRand { |

66 | one: seed.s, |

67 | two: seed.r, |

68 | } |

69 | } |

70 | |

71 | #[cfg(any( |

72 | feature = "macros", |

73 | feature = "rt-multi-thread", |

74 | all(feature = "sync", feature = "rt") |

75 | ))] |

76 | pub(crate) fn fastrand_n(&mut self, n: u32) -> u32 { |

77 | // This is similar to fastrand() % n, but faster. |

78 | // See https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ |

79 | let mul = (self.fastrand() as u64).wrapping_mul(n as u64); |

80 | (mul >> 32) as u32 |

81 | } |

82 | |

83 | fn fastrand(&mut self) -> u32 { |

84 | let mut s1 = self.one; |

85 | let s0 = self.two; |

86 | |

87 | s1 ^= s1 << 17; |

88 | s1 = s1 ^ s0 ^ s1 >> 7 ^ s0 >> 16; |

89 | |

90 | self.one = s0; |

91 | self.two = s1; |

92 | |

93 | s0.wrapping_add(s1) |

94 | } |

95 | } |

96 |