From 7b0ee01310a49a182e4196a2499ecb549861ee44 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 19 Jul 2025 12:34:15 +0900 Subject: [PATCH] mruby-random: support bigint in rand method To achieve this, the following changes were made: - Exported `mrb_bint_size`, `mrb_bint_from_bytes`, and `mrb_bint_sign` functions from `mruby-bigint` to be used in other mrbgems. - Modified `mruby-random` to use these new functions to handle Bigint arguments in the `rand` method. Co-authored-by: Gemini --- include/mruby/internal.h | 3 +++ mrbgems/mruby-bigint/core/bigint.c | 28 ++++++++++++++++++++++++++++ mrbgems/mruby-random/src/random.c | 17 +++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/include/mruby/internal.h b/include/mruby/internal.h index a9e43848f..83738506f 100644 --- a/include/mruby/internal.h +++ b/include/mruby/internal.h @@ -258,6 +258,9 @@ void mrb_bint_copy(mrb_state *mrb, mrb_value x, mrb_value y); size_t mrb_bint_memsize(mrb_value x); mrb_value mrb_bint_hash(mrb_state *mrb, mrb_value x); mrb_value mrb_bint_sqrt(mrb_state *mrb, mrb_value x); +mrb_int mrb_bint_size(mrb_state *mrb, mrb_value bint); +mrb_value mrb_bint_from_bytes(mrb_state *mrb, const uint8_t *bytes, mrb_int len); +mrb_int mrb_bint_sign(mrb_state *mrb, mrb_value bint); #endif #endif /* MRUBY_INTERNAL_H */ diff --git a/mrbgems/mruby-bigint/core/bigint.c b/mrbgems/mruby-bigint/core/bigint.c index 1b722bd74..faf725722 100644 --- a/mrbgems/mruby-bigint/core/bigint.c +++ b/mrbgems/mruby-bigint/core/bigint.c @@ -2756,6 +2756,34 @@ mrb_bint_sqrt(mrb_state *mrb, mrb_value x) return bint_norm(mrb, bint_new(mrb, &z)); } +mrb_int +mrb_bint_sign(mrb_state *mrb, mrb_value bint) +{ + return RBIGINT_SIGN(RBIGINT(bint)); +} + +mrb_int +mrb_bint_size(mrb_state *mrb, mrb_value bint) +{ + mpz_t z; + bint_as_mpz(RBIGINT(bint), &z); + return z.sz * sizeof(mp_limb); +} + +mrb_value +mrb_bint_from_bytes(mrb_state *mrb, const uint8_t *bytes, mrb_int len) +{ + mpz_t z; + mpz_init(mrb, &z); + size_t limb_len = (len + sizeof(mp_limb) - 1) / sizeof(mp_limb); + mpz_realloc(mrb, &z, limb_len); + memcpy(z.p, bytes, len); + z.sn = (len > 0) ? 1 : 0; + z.sz = limb_len; + trim(&z); + return bint_norm(mrb, bint_new(mrb, &z)); +} + mrb_value mrb_bint_hash(mrb_state *mrb, mrb_value x) { diff --git a/mrbgems/mruby-random/src/random.c b/mrbgems/mruby-random/src/random.c index aa9a0799e..2cba627e3 100644 --- a/mrbgems/mruby-random/src/random.c +++ b/mrbgems/mruby-random/src/random.c @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -210,6 +211,22 @@ random_rand_impl(mrb_state *mrb, rand_state *t, mrb_value self) return random_range(mrb, t, arg); } +#ifdef MRB_USE_BIGINT + if (mrb_bigint_p(arg)) { + if (mrb_bint_sign(mrb, arg) < 0) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "negative value as random limit"); + } + mrb_int size = mrb_bint_size(mrb, arg); + mrb_value bytes = mrb_str_new(mrb, NULL, size); + uint8_t *p = (uint8_t*)RSTRING_PTR(bytes); + for (mrb_int i = 0; i < size; i++) { + p[i] = (uint8_t)rand_uint32(t); + } + mrb_value rand_bint = mrb_bint_from_bytes(mrb, p, size); + return mrb_bint_mod(mrb, rand_bint, arg); + } +#endif + range_error(mrb, arg); }