|
@@ -24,14 +24,20 @@ pub static mut N: u8 = 31;
|
|
|
pub static mut I: u8 = 3;
|
|
|
pub static mut J: u8 = 0;
|
|
|
|
|
|
-/* Unlike in C, we can't take the address of the initializing array
|
|
|
- * outside of a function. */
|
|
|
-pub static mut X_PTR: *mut u32 = ptr::null_mut();
|
|
|
+/* As such, random() and related functions work on u32 values, but POSIX
|
|
|
+ * allows the user to supply a custom state data array as a `char *`
|
|
|
+ * with no requirements on alignment. Thus, we must assume the worst in
|
|
|
+ * terms of alignment and convert back and forth from [u8; 4].
|
|
|
+ *
|
|
|
+ * Also, unlike in C, we can't take the address of the initializing
|
|
|
+ * array outside of a function. */
|
|
|
+pub static mut X_PTR: *mut [u8; 4] = ptr::null_mut();
|
|
|
|
|
|
// To be called in any function that may read from X_PTR
|
|
|
pub unsafe fn ensure_x_ptr_init() {
|
|
|
if X_PTR.is_null() {
|
|
|
- X_PTR = &mut X_INIT[1];
|
|
|
+ let x_u32_ptr: *mut u32 = &mut X_INIT[1];
|
|
|
+ X_PTR = x_u32_ptr.cast::<[u8; 4]>();
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -43,24 +49,26 @@ pub fn lcg64_step(x: u64) -> u64 {
|
|
|
6364136223846793005_u64.wrapping_mul(x).wrapping_add(1_u64)
|
|
|
}
|
|
|
|
|
|
-pub unsafe fn save_state() -> *mut u32 {
|
|
|
+pub unsafe fn save_state() -> *mut [u8; 4] {
|
|
|
ensure_x_ptr_init();
|
|
|
- *X_PTR.offset(-1) = (u32::from(N) << 16) | (u32::from(I) << 8) | u32::from(J);
|
|
|
+
|
|
|
+ let stash_value: u32 = (u32::from(N) << 16) | (u32::from(I) << 8) | u32::from(J);
|
|
|
+ *X_PTR.offset(-1) = stash_value.to_ne_bytes();
|
|
|
X_PTR.offset(-1)
|
|
|
}
|
|
|
|
|
|
-pub unsafe fn load_state(state_ptr: *mut u32) {
|
|
|
- let prev_x = *state_ptr;
|
|
|
+pub unsafe fn load_state(state_ptr: *mut [u8; 4]) {
|
|
|
+ let stash_value = u32::from_ne_bytes(*state_ptr);
|
|
|
X_PTR = state_ptr.offset(1);
|
|
|
|
|
|
/* This calculation of N does not have a bit mask in the musl
|
|
|
* original, in principle resulting in a u16, but obtaining a value
|
|
|
* larger than 63 can probably be dismissed as pathological. */
|
|
|
- N = u8::try_from((prev_x >> 16) & 0xff).unwrap();
|
|
|
+ N = u8::try_from((stash_value >> 16) & 0xff).unwrap();
|
|
|
|
|
|
// I and J calculations are straight from musl
|
|
|
- I = u8::try_from((prev_x >> 8) & 0xff).unwrap();
|
|
|
- J = u8::try_from(prev_x & 0xff).unwrap();
|
|
|
+ I = u8::try_from((stash_value >> 8) & 0xff).unwrap();
|
|
|
+ J = u8::try_from(stash_value & 0xff).unwrap();
|
|
|
}
|
|
|
|
|
|
pub unsafe fn seed(seed: c_uint) {
|
|
@@ -69,7 +77,7 @@ pub unsafe fn seed(seed: c_uint) {
|
|
|
let mut s = seed as u64;
|
|
|
|
|
|
if N == 0 {
|
|
|
- *X_PTR = s as u32;
|
|
|
+ *X_PTR = (s as u32).to_ne_bytes();
|
|
|
} else {
|
|
|
I = if N == 31 || N == 7 { 3 } else { 1 };
|
|
|
|
|
@@ -80,10 +88,10 @@ pub unsafe fn seed(seed: c_uint) {
|
|
|
|
|
|
// Conversion will always succeed (value is a 32-bit right-
|
|
|
// shift of a 64-bit integer).
|
|
|
- *X_PTR.add(k) = u32::try_from(s >> 32).unwrap();
|
|
|
+ *X_PTR.add(k) = u32::try_from(s >> 32).unwrap().to_ne_bytes();
|
|
|
}
|
|
|
|
|
|
// ensure X contains at least one odd number
|
|
|
- *X_PTR |= 1;
|
|
|
+ *X_PTR = (u32::from_ne_bytes(*X_PTR) | 1).to_ne_bytes();
|
|
|
}
|
|
|
}
|