c_scape/
rand48.rs

1use libc::{c_double, c_long, c_ushort};
2
3use core::cell::SyncUnsafeCell;
4use core::ptr::addr_of;
5
6#[cfg(test)]
7static_assertions::assert_eq_size!(c_ushort, u16);
8#[cfg(test)]
9static_assertions::assert_type_eq_all!(c_double, f64);
10
11#[repr(C)]
12#[derive(Clone, Copy, Debug)]
13struct LCongData {
14    a_mult: [c_ushort; 3],
15    c: c_ushort,
16}
17
18#[repr(C)]
19#[derive(Clone, Copy, Debug)]
20struct RngData {
21    x_subi: [c_ushort; 3],
22    data: LCongData,
23}
24
25static STORAGE: SyncUnsafeCell<RngData> = SyncUnsafeCell::new(RngData {
26    x_subi: [0, 0, 0],
27    data: LCongData {
28        a_mult: [0xe66d, 0xdeec, 0x5],
29        c: 0xb,
30    },
31});
32
33unsafe fn next_lcong(x_subi: *mut [c_ushort; 3], data: *const LCongData) -> u64 {
34    let x: u64 = ((*x_subi)[0] as u64) | ((*x_subi)[1] as u64) << 16 | ((*x_subi)[2] as u64) << 32;
35    let a: u64 = ((*data).a_mult[0] as u64)
36        | ((*data).a_mult[1] as u64) << 16
37        | ((*data).a_mult[2] as u64) << 32;
38
39    let res = a.wrapping_mul(x).wrapping_add((*data).c as u64);
40    (*x_subi)[0] = res as c_ushort;
41    (*x_subi)[1] = (res >> 16) as c_ushort;
42    (*x_subi)[2] = (res >> 32) as c_ushort;
43    res & 0xffff_ffff_ffff
44}
45
46#[no_mangle]
47unsafe extern "C" fn drand48() -> c_double {
48    libc!(libc::drand48());
49
50    erand48((*STORAGE.get()).x_subi.as_mut_ptr())
51}
52
53#[no_mangle]
54unsafe extern "C" fn erand48(x_subi: *mut c_ushort) -> c_double {
55    libc!(libc::erand48(x_subi));
56
57    let x_subi: *mut [c_ushort; 3] = x_subi.cast();
58
59    let next_integral = next_lcong(x_subi, addr_of!((*STORAGE.get()).data));
60
61    f64::from_bits(16.0_f64.to_bits() + next_integral) - 16.0
62}
63
64#[no_mangle]
65unsafe extern "C" fn lrand48() -> c_long {
66    libc!(libc::lrand48());
67
68    nrand48((*STORAGE.get()).x_subi.as_mut_ptr())
69}
70
71#[no_mangle]
72unsafe extern "C" fn nrand48(x_subi: *mut c_ushort) -> c_long {
73    libc!(libc::nrand48(x_subi));
74
75    let x_subi: *mut [c_ushort; 3] = x_subi.cast();
76
77    (next_lcong(x_subi, addr_of!((*STORAGE.get()).data)) >> 17) as c_long
78}
79
80#[no_mangle]
81unsafe extern "C" fn mrand48() -> c_long {
82    libc!(libc::mrand48());
83
84    jrand48((*STORAGE.get()).x_subi.as_mut_ptr())
85}
86
87#[no_mangle]
88unsafe extern "C" fn jrand48(x_subi: *mut c_ushort) -> c_long {
89    libc!(libc::jrand48(x_subi));
90
91    let x_subi: *mut [c_ushort; 3] = x_subi.cast();
92
93    // Cast to i32 so the sign extension works properly
94    (next_lcong(x_subi, addr_of!((*STORAGE.get()).data)) >> 16) as i32 as c_long
95}
96
97#[no_mangle]
98unsafe extern "C" fn srand48(seed: c_long) {
99    libc!(libc::srand48(seed));
100
101    seed48(&mut [0x330e, seed as c_ushort, (seed >> 16) as c_ushort]);
102}
103
104#[no_mangle]
105unsafe extern "C" fn seed48(seed: *mut [c_ushort; 3]) -> *mut c_ushort {
106    static PREV_SEED: SyncUnsafeCell<[c_ushort; 3]> = SyncUnsafeCell::new([0, 0, 0]);
107
108    *PREV_SEED.get() = (*STORAGE.get()).x_subi;
109    (*STORAGE.get()) = RngData {
110        x_subi: *seed,
111        data: LCongData {
112            a_mult: [0xe66d, 0xdeec, 0x5],
113            c: 0xb,
114        },
115    };
116
117    PREV_SEED.get().cast::<u16>()
118}
119
120#[no_mangle]
121unsafe extern "C" fn lcong48(param: *mut c_ushort) {
122    libc!(libc::lcong48(param));
123
124    let param: *mut [c_ushort; 7] = param.cast();
125
126    *STORAGE.get().cast::<[c_ushort; 7]>() = *param;
127}