mruby-random: split 64-bit state into two 32-bit values on 32-bit platforms

on 32-bit systems, the rand_state struct with uint64_t state (8 bytes,
8-byte aligned) followed by uint32_t seed_value (4 bytes) resulted in
16 bytes due to padding, exceeding the 12-byte ISTRUCT_DATA_SIZE limit.
this caused the static_assert at line 540 to fail.

split the state field into state_lo and state_hi on MRB_32BIT platforms
to achieve perfect 12-byte alignment (4+4+4) without padding. add
GET_STATE/SET_STATE macros to provide uniform access across platforms.

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Yukihiro "Matz" Matsumoto
2025-10-16 17:50:03 +09:00
parent 1efaaa5570
commit 6dd5f05525
+24 -5
View File
@@ -38,14 +38,33 @@
#define PCG_INCREMENT 1442695040888963407ULL
typedef struct rand_state {
#ifdef MRB_32BIT
/* On 32-bit platforms, split state to avoid alignment padding */
uint32_t state_lo;
uint32_t state_hi;
#else
uint64_t state;
#endif
uint32_t seed_value; /* Track last seed for srand compatibility */
} rand_state;
/* Helper macros for 64-bit state access */
#ifdef MRB_32BIT
# define GET_STATE(t) (((uint64_t)(t)->state_hi << 32) | (t)->state_lo)
# define SET_STATE(t, val) do { \
uint64_t v_ = (val); \
(t)->state_lo = (uint32_t)v_; \
(t)->state_hi = (uint32_t)(v_ >> 32); \
} while (0)
#else
# define GET_STATE(t) ((t)->state)
# define SET_STATE(t, val) ((t)->state = (val))
#endif
static void
rand_init(rand_state *t)
{
t->state = 0x853c49e6748fea9bULL;
SET_STATE(t, 0x853c49e6748fea9bULL);
t->seed_value = 521288629;
}
@@ -57,9 +76,9 @@ rand_seed(rand_state *t, uint32_t seed)
uint32_t old_seed = t->seed_value;
/* PCG initialization: state=0, step, add seed, step, then mix */
t->state = 0;
SET_STATE(t, 0);
rand_uint32(t);
t->state += seed;
SET_STATE(t, GET_STATE(t) + seed);
for (int i = 0; i < 10; i++) {
rand_uint32(t);
}
@@ -72,10 +91,10 @@ static uint32_t
rand_uint32(rand_state *rng)
{
/* PCG-XSH-RR: XorShift High (xorshift), then Random Rotate */
uint64_t oldstate = rng->state;
uint64_t oldstate = GET_STATE(rng);
/* LCG step: advance internal state */
rng->state = oldstate * PCG_MULTIPLIER + PCG_INCREMENT;
SET_STATE(rng, oldstate * PCG_MULTIPLIER + PCG_INCREMENT);
/* Output function: xorshift, then rotate by top bits */
uint32_t xorshifted = (uint32_t)(((oldstate >> 18u) ^ oldstate) >> 27u);