/src/mruby/mrbgems/mruby-random/src/random.c
Line | Count | Source |
1 | | /* |
2 | | ** random.c - Random module |
3 | | ** |
4 | | ** See Copyright Notice in mruby.h |
5 | | */ |
6 | | |
7 | | #include <mruby.h> |
8 | | #include <mruby/variable.h> |
9 | | #include <mruby/class.h> |
10 | | #include <mruby/data.h> |
11 | | #include <mruby/array.h> |
12 | | #include <mruby/istruct.h> |
13 | | #include <mruby/presym.h> |
14 | | #include <mruby/range.h> |
15 | | #include <mruby/string.h> |
16 | | #include <mruby/internal.h> |
17 | | |
18 | | #include <time.h> |
19 | | |
20 | | /* PCG Random Number Generation |
21 | | Based on the PCG family by Melissa O'Neill <oneill@pcg-random.org> |
22 | | |
23 | | This implements PCG-XSH-RR with 64-bit state and 32-bit output. |
24 | | On 32-bit platforms, uses an optimized 32-bit multiplier for better |
25 | | performance. On 64-bit platforms, uses the standard 64-bit multiplier |
26 | | for maximum statistical quality. |
27 | | |
28 | | See <https://www.pcg-random.org/> for details. */ |
29 | | |
30 | | /* Platform-adaptive multiplier selection: |
31 | | - 32-bit platforms: 0xf13283ad requires only 2 multiplies instead of 3 |
32 | | - 64-bit platforms: standard multiplier for best statistical quality */ |
33 | | #ifdef MRB_32BIT |
34 | | # define PCG_MULTIPLIER 0xf13283adULL |
35 | | #else |
36 | | # define PCG_MULTIPLIER 6364136223846793005ULL |
37 | | #endif |
38 | | #define PCG_INCREMENT 1442695040888963407ULL |
39 | | |
40 | | typedef struct rand_state { |
41 | | #ifdef MRB_32BIT |
42 | | /* On 32-bit platforms, split state to avoid alignment padding */ |
43 | | uint32_t state_lo; |
44 | | uint32_t state_hi; |
45 | | #else |
46 | | uint64_t state; |
47 | | #endif |
48 | | uint32_t seed_value; /* Track last seed for srand compatibility */ |
49 | | } rand_state; |
50 | | |
51 | | /* Helper macros for 64-bit state access */ |
52 | | #ifdef MRB_32BIT |
53 | | # define GET_STATE(t) (((uint64_t)(t)->state_hi << 32) | (t)->state_lo) |
54 | | # define SET_STATE(t, val) do { \ |
55 | | uint64_t v_ = (val); \ |
56 | | (t)->state_lo = (uint32_t)v_; \ |
57 | | (t)->state_hi = (uint32_t)(v_ >> 32); \ |
58 | | } while (0) |
59 | | #else |
60 | 14.6k | # define GET_STATE(t) ((t)->state) |
61 | 18.6k | # define SET_STATE(t, val) ((t)->state = (val)) |
62 | | #endif |
63 | | |
64 | | static void |
65 | | rand_init(rand_state *t) |
66 | 1.32k | { |
67 | 1.32k | SET_STATE(t, 0x853c49e6748fea9bULL); |
68 | 1.32k | t->seed_value = 521288629; |
69 | 1.32k | } |
70 | | |
71 | | static uint32_t rand_uint32(rand_state *state); |
72 | | |
73 | | static uint32_t |
74 | | rand_seed(rand_state *t, uint32_t seed) |
75 | 1.32k | { |
76 | 1.32k | uint32_t old_seed = t->seed_value; |
77 | | |
78 | | /* PCG initialization: state=0, step, add seed, step, then mix */ |
79 | 1.32k | SET_STATE(t, 0); |
80 | 1.32k | rand_uint32(t); |
81 | 1.32k | SET_STATE(t, GET_STATE(t) + seed); |
82 | 14.6k | for (int i = 0; i < 10; i++) { |
83 | 13.2k | rand_uint32(t); |
84 | 13.2k | } |
85 | | |
86 | 1.32k | t->seed_value = seed; |
87 | 1.32k | return old_seed; |
88 | 1.32k | } |
89 | | |
90 | | static uint32_t |
91 | | rand_uint32(rand_state *rng) |
92 | 14.6k | { |
93 | | /* PCG-XSH-RR: XorShift High (xorshift), then Random Rotate */ |
94 | 14.6k | uint64_t oldstate = GET_STATE(rng); |
95 | | |
96 | | /* LCG step: advance internal state */ |
97 | 14.6k | SET_STATE(rng, oldstate * PCG_MULTIPLIER + PCG_INCREMENT); |
98 | | |
99 | | /* Output function: xorshift, then rotate by top bits */ |
100 | 14.6k | uint32_t xorshifted = (uint32_t)(((oldstate >> 18u) ^ oldstate) >> 27u); |
101 | 14.6k | uint32_t rot = (uint32_t)(oldstate >> 59u); |
102 | | |
103 | | /* Rotate right by rot bits (handles rot=0 case correctly) */ |
104 | 14.6k | return (xorshifted >> rot) | (xorshifted << ((32 - rot) & 31)); |
105 | 14.6k | } |
106 | | |
107 | | #ifndef MRB_NO_FLOAT |
108 | | static double |
109 | | rand_real(rand_state *t) |
110 | 0 | { |
111 | 0 | uint32_t x = rand_uint32(t); |
112 | 0 | return x*(1.0/4294967296.0); |
113 | 0 | } |
114 | | #endif |
115 | | |
116 | | static mrb_value |
117 | | random_rand(mrb_state *mrb, rand_state *t, mrb_int max) |
118 | 0 | { |
119 | 0 | if (max == 0) { |
120 | 0 | #ifndef MRB_NO_FLOAT |
121 | 0 | return mrb_float_value(mrb, rand_real(t)); |
122 | | #else |
123 | | max = 100; |
124 | | #endif |
125 | 0 | } |
126 | 0 | return mrb_int_value(mrb, rand_uint32(t) % max); |
127 | 0 | } |
128 | | |
129 | | static mrb_int |
130 | | rand_i(rand_state *t, mrb_int max) |
131 | 0 | { |
132 | | /* return uniform integer in [0, max) without modulo bias */ |
133 | 0 | if (max <= 0) return 0; |
134 | 0 | uint32_t threshold = (uint32_t)(-max) % (uint32_t)max; /* power-of-two fast path => 0 */ |
135 | 0 | uint32_t r; |
136 | 0 | do { |
137 | 0 | r = rand_uint32(t); |
138 | 0 | } while (r < threshold); |
139 | 0 | return (mrb_int)(r % (uint32_t)max); |
140 | 0 | } |
141 | | |
142 | | static mrb_value |
143 | | rand_range_int(mrb_state *mrb, rand_state *t, mrb_int begin, |
144 | 0 | mrb_int end, mrb_bool excl) { |
145 | 0 | mrb_int span = end - begin + (excl ? 0 : 1); |
146 | 0 | if (span <= 0) |
147 | 0 | return mrb_nil_value(); |
148 | | |
149 | 0 | return mrb_int_value(mrb, (rand_i(t, span)) + begin); |
150 | 0 | } |
151 | | |
152 | | #ifndef MRB_NO_FLOAT |
153 | | static mrb_value |
154 | | rand_range_float(mrb_state *mrb, rand_state *t, |
155 | | mrb_float begin, mrb_float end, |
156 | 0 | mrb_bool excl) { |
157 | 0 | mrb_float span = end - begin + (excl ? 0.0 : 1.0); |
158 | 0 | if (span <= 0.0) |
159 | 0 | return mrb_nil_value(); |
160 | | |
161 | 0 | return mrb_float_value(mrb, rand_real(t) * span + begin); |
162 | 0 | } |
163 | | #endif |
164 | | |
165 | | static mrb_noreturn void |
166 | | range_error(mrb_state *mrb, mrb_value v) |
167 | 0 | { |
168 | 0 | mrb_raisef(mrb, E_TYPE_ERROR, "no implicit conversion of %Y into Integer", v); |
169 | 0 | } |
170 | | |
171 | | static mrb_value |
172 | | random_range(mrb_state *mrb, rand_state *t, mrb_value rv) |
173 | 0 | { |
174 | 0 | struct RRange *r = mrb_range_ptr(mrb, rv); |
175 | 0 | if (mrb_integer_p(RANGE_BEG(r)) && mrb_integer_p(RANGE_END(r))) { |
176 | 0 | return rand_range_int(mrb, t, mrb_integer(RANGE_BEG(r)), |
177 | 0 | mrb_integer(RANGE_END(r)), RANGE_EXCL(r)); |
178 | 0 | } |
179 | | |
180 | 0 | #define cast_to_float(v) \ |
181 | 0 | (mrb_float_p(v) ? mrb_float(v) \ |
182 | 0 | : mrb_integer_p(v) ? (mrb_float)mrb_integer(v) \ |
183 | 0 | : (range_error(mrb, v), 0.0)) |
184 | | |
185 | 0 | return rand_range_float(mrb, t, cast_to_float(RANGE_BEG(r)), |
186 | 0 | cast_to_float(RANGE_END(r)), RANGE_EXCL(r)); |
187 | 0 | #undef cast_to_float |
188 | 0 | } |
189 | | |
190 | | static mrb_value |
191 | | random_rand_impl(mrb_state *mrb, rand_state *t, mrb_value self) |
192 | 0 | { |
193 | 0 | mrb_value arg; |
194 | 0 | if (mrb_get_args(mrb, "|o", &arg) == 0) { |
195 | 0 | return random_rand(mrb, t, 0); |
196 | 0 | } |
197 | | |
198 | 0 | if (mrb_float_p(arg)) { |
199 | 0 | return random_rand(mrb, t, (mrb_int)mrb_float(arg)); |
200 | 0 | } |
201 | | |
202 | 0 | if (mrb_integer_p(arg)) { |
203 | 0 | return random_rand(mrb, t, mrb_integer(arg)); |
204 | 0 | } |
205 | | |
206 | 0 | if (mrb_range_p(arg)) { |
207 | 0 | return random_range(mrb, t, arg); |
208 | 0 | } |
209 | | |
210 | 0 | #ifdef MRB_USE_BIGINT |
211 | 0 | if (mrb_bigint_p(arg)) { |
212 | 0 | if (mrb_bint_sign(mrb, arg) < 0) { |
213 | 0 | mrb_raise(mrb, E_ARGUMENT_ERROR, "negative value as random limit"); |
214 | 0 | } |
215 | 0 | mrb_int size = mrb_bint_size(mrb, arg); |
216 | 0 | mrb_value bytes = mrb_str_new(mrb, NULL, size); |
217 | 0 | uint8_t *p = (uint8_t*)RSTRING_PTR(bytes); |
218 | 0 | for (mrb_int i = 0; i < size; i++) { |
219 | 0 | p[i] = (uint8_t)rand_uint32(t); |
220 | 0 | } |
221 | 0 | mrb_value rand_bint = mrb_bint_from_bytes(mrb, p, size); |
222 | 0 | return mrb_bint_mod(mrb, rand_bint, arg); |
223 | 0 | } |
224 | 0 | #endif |
225 | | |
226 | 0 | range_error(mrb, arg); |
227 | 0 | } |
228 | | |
229 | 2.65k | #define ID_RANDOM MRB_SYM(mruby_Random) |
230 | | |
231 | | static mrb_value |
232 | | random_default(mrb_state *mrb) |
233 | 0 | { |
234 | 0 | struct RClass *c = mrb_class_get_id(mrb, ID_RANDOM); |
235 | 0 | mrb_value d = mrb_iv_get(mrb, mrb_obj_value(c), ID_RANDOM); |
236 | 0 | if (!mrb_obj_is_kind_of(mrb, d, c)) { |
237 | 0 | mrb_raise(mrb, E_RUNTIME_ERROR, "[BUG] default Random replaced"); |
238 | 0 | } |
239 | 0 | return d; |
240 | 0 | } |
241 | | |
242 | 2.65k | #define random_ptr(v) (rand_state*)mrb_istruct_ptr(v) |
243 | 0 | #define random_default_state(mrb) random_ptr(random_default(mrb)) |
244 | | |
245 | | /* |
246 | | * call-seq: |
247 | | * Random.new(seed = nil) -> random |
248 | | * |
249 | | * Creates a new random number generator. If seed is omitted or nil, |
250 | | * the generator is initialized with a default seed. Otherwise, |
251 | | * the generator is initialized with the given seed. |
252 | | * |
253 | | * Random.new #=> #<Random:0x...> |
254 | | * Random.new(1234) #=> #<Random:0x...> |
255 | | */ |
256 | | static mrb_value |
257 | | random_m_init(mrb_state *mrb, mrb_value self) |
258 | 1.32k | { |
259 | 1.32k | mrb_int seed; |
260 | 1.32k | rand_state *t = random_ptr(self); |
261 | | |
262 | 1.32k | if (mrb_get_args(mrb, "|i", &seed) == 0) { |
263 | 1.32k | rand_init(t); |
264 | 1.32k | } |
265 | 0 | else { |
266 | 0 | rand_seed(t, (uint32_t)seed); |
267 | 0 | } |
268 | | |
269 | 1.32k | return self; |
270 | 1.32k | } |
271 | | |
272 | | /* |
273 | | * call-seq: |
274 | | * random.rand -> float |
275 | | * random.rand(max) -> number |
276 | | * random.rand(range) -> number |
277 | | * |
278 | | * Returns a random number. When called without arguments, returns a |
279 | | * random float between 0.0 and 1.0. When called with a positive integer, |
280 | | * returns a random integer between 0 and max-1. When called with a range, |
281 | | * returns a random number within that range. |
282 | | * |
283 | | * prng = Random.new |
284 | | * prng.rand #=> 0.2725926052826416 |
285 | | * prng.rand(10) #=> 7 |
286 | | * prng.rand(1..6) #=> 4 |
287 | | */ |
288 | | static mrb_value |
289 | | random_m_rand(mrb_state *mrb, mrb_value self) |
290 | 0 | { |
291 | 0 | rand_state *t = random_ptr(self); |
292 | 0 | return random_rand_impl(mrb, t, self); |
293 | 0 | } |
294 | | |
295 | | /* |
296 | | * call-seq: |
297 | | * random.srand(seed = nil) -> old_seed |
298 | | * |
299 | | * Seeds the random number generator with the given seed. If seed is |
300 | | * omitted or nil, uses a combination of current time and internal state. |
301 | | * Returns the previous seed value. |
302 | | * |
303 | | * prng = Random.new |
304 | | * prng.srand(1234) #=> (previous seed) |
305 | | * prng.srand #=> 1234 |
306 | | */ |
307 | | static mrb_value |
308 | | random_m_srand(mrb_state *mrb, mrb_value self) |
309 | 0 | { |
310 | 0 | uint32_t seed; |
311 | 0 | mrb_int i; |
312 | 0 | rand_state *t = random_ptr(self); |
313 | |
|
314 | 0 | if (mrb_get_args(mrb, "|i", &i) == 0) { |
315 | 0 | seed = (uint32_t)time(NULL) ^ rand_uint32(t) ^ (uint32_t)(uintptr_t)t; |
316 | 0 | } |
317 | 0 | else { |
318 | 0 | seed = (uint32_t)i; |
319 | 0 | } |
320 | |
|
321 | 0 | uint32_t old_seed = rand_seed(t, seed); |
322 | 0 | return mrb_int_value(mrb, (mrb_int)old_seed); |
323 | 0 | } |
324 | | |
325 | | /* |
326 | | * call-seq: |
327 | | * random.bytes(size) -> string |
328 | | * |
329 | | * Returns a string of random bytes of the specified size. |
330 | | * |
331 | | * prng = Random.new |
332 | | * prng.bytes(4) #=> "\x8F\x12\xA3\x7C" |
333 | | * prng.bytes(10).length #=> 10 |
334 | | */ |
335 | | static mrb_value |
336 | | random_m_bytes(mrb_state *mrb, mrb_value self) |
337 | 0 | { |
338 | 0 | rand_state *t = random_ptr(self); |
339 | 0 | mrb_int i = mrb_as_int(mrb, mrb_get_arg1(mrb)); |
340 | 0 | if (i < 0) mrb_raise(mrb, E_ARGUMENT_ERROR, "negative string size"); |
341 | 0 | mrb_value bytes = mrb_str_new(mrb, NULL, i); |
342 | 0 | uint8_t *p = (uint8_t*)RSTRING_PTR(bytes); |
343 | | |
344 | | /* write 4 bytes per PRNG call */ |
345 | 0 | while (i >= 4) { |
346 | 0 | uint32_t x = rand_uint32(t); |
347 | 0 | p[0] = (uint8_t)(x); |
348 | 0 | p[1] = (uint8_t)(x >> 8); |
349 | 0 | p[2] = (uint8_t)(x >> 16); |
350 | 0 | p[3] = (uint8_t)(x >> 24); |
351 | 0 | p += 4; |
352 | 0 | i -= 4; |
353 | 0 | } |
354 | 0 | if (i > 0) { |
355 | 0 | uint32_t x = rand_uint32(t); |
356 | 0 | while (i-- > 0) { |
357 | 0 | *p++ = (uint8_t)x; |
358 | 0 | x >>= 8; |
359 | 0 | } |
360 | 0 | } |
361 | |
|
362 | 0 | return bytes; |
363 | 0 | } |
364 | | |
365 | | static rand_state* |
366 | | check_random_arg(mrb_state *mrb, mrb_value r) |
367 | 0 | { |
368 | 0 | struct RClass *c = mrb_class_get_id(mrb, ID_RANDOM); |
369 | 0 | rand_state *random; |
370 | |
|
371 | 0 | if (mrb_undef_p(r)) { |
372 | 0 | random = random_default_state(mrb); |
373 | 0 | } |
374 | 0 | else if (mrb_istruct_p(r) && mrb_obj_is_kind_of(mrb, r, c)){ |
375 | 0 | random = (rand_state*)mrb_istruct_ptr(r); |
376 | 0 | } |
377 | 0 | else { |
378 | 0 | mrb_raise(mrb, E_TYPE_ERROR, "Random object required"); |
379 | 0 | } |
380 | 0 | return random; |
381 | 0 | } |
382 | | /* |
383 | | * call-seq: |
384 | | * ary.shuffle! -> ary |
385 | | * |
386 | | * Shuffles elements in self in place. |
387 | | */ |
388 | | |
389 | | static mrb_value |
390 | | mrb_ary_shuffle_bang(mrb_state *mrb, mrb_value ary) |
391 | 0 | { |
392 | 0 | if (RARRAY_LEN(ary) > 1) { |
393 | 0 | mrb_sym kname = MRB_SYM(random); |
394 | 0 | mrb_value r; |
395 | 0 | const mrb_kwargs kw = {1, 0, &kname, &r, NULL}; |
396 | |
|
397 | 0 | mrb_get_args(mrb, ":", &kw); |
398 | 0 | rand_state *random = check_random_arg(mrb, r); |
399 | 0 | mrb_ary_modify(mrb, mrb_ary_ptr(ary)); |
400 | 0 | mrb_int len = RARRAY_LEN(ary); |
401 | 0 | mrb_value *ptr = RARRAY_PTR(ary); |
402 | 0 | for (mrb_int i = len - 1; i > 0; i--) { |
403 | 0 | mrb_int j = rand_i(random, i + 1); |
404 | 0 | mrb_value tmp = ptr[i]; |
405 | 0 | ptr[i] = ptr[j]; |
406 | 0 | ptr[j] = tmp; |
407 | 0 | } |
408 | 0 | } |
409 | |
|
410 | 0 | return ary; |
411 | 0 | } |
412 | | |
413 | | /* |
414 | | * call-seq: |
415 | | * ary.shuffle -> new_ary |
416 | | * |
417 | | * Returns a new array with elements of self shuffled. |
418 | | */ |
419 | | |
420 | | static mrb_value |
421 | | mrb_ary_shuffle(mrb_state *mrb, mrb_value ary) |
422 | 0 | { |
423 | 0 | mrb_value new_ary = mrb_ary_dup(mrb, ary); |
424 | 0 | mrb_ary_shuffle_bang(mrb, new_ary); |
425 | |
|
426 | 0 | return new_ary; |
427 | 0 | } |
428 | | |
429 | | /* |
430 | | * call-seq: |
431 | | * ary.sample -> obj |
432 | | * ary.sample(n) -> new_ary |
433 | | * |
434 | | * Choose a random element or `n` random elements from the array. |
435 | | * |
436 | | * The elements are chosen by using random and unique indices into the array |
437 | | * in order to ensure that an element doesn't repeat itself unless the array |
438 | | * already contained duplicate elements. |
439 | | * |
440 | | * If the array is empty the first form returns `nil` and the second form |
441 | | * returns an empty array. |
442 | | */ |
443 | | |
444 | | static mrb_value |
445 | | mrb_ary_sample(mrb_state *mrb, mrb_value ary) |
446 | 0 | { |
447 | 0 | mrb_int n = 0; |
448 | 0 | mrb_bool given; |
449 | 0 | mrb_sym kname = MRB_SYM(random); |
450 | 0 | mrb_value r; |
451 | 0 | const mrb_kwargs kw = {1, 0, &kname, &r, NULL}; |
452 | |
|
453 | 0 | mrb_get_args(mrb, "|i?:", &n, &given, &kw); |
454 | 0 | rand_state *random = check_random_arg(mrb, r); |
455 | 0 | mrb_int len = RARRAY_LEN(ary); |
456 | 0 | if (!given) { /* pick one element */ |
457 | 0 | switch (len) { |
458 | 0 | case 0: |
459 | 0 | return mrb_nil_value(); |
460 | 0 | case 1: |
461 | 0 | return RARRAY_PTR(ary)[0]; |
462 | 0 | default: |
463 | 0 | return RARRAY_PTR(ary)[rand_i(random, len)]; |
464 | 0 | } |
465 | 0 | } |
466 | 0 | else { |
467 | 0 | if (n < 0) mrb_raise(mrb, E_ARGUMENT_ERROR, "negative sample number"); |
468 | 0 | if (n > len) n = len; |
469 | | /* collect unique indices without allocating Ruby Integers */ |
470 | 0 | mrb_int *idx = (mrb_int*)mrb_alloca(mrb, sizeof(mrb_int) * (n > 0 ? n : 1)); |
471 | 0 | for (mrb_int i = 0; i < n; i++) { |
472 | 0 | mrb_int v; |
473 | 0 | for (;;) { |
474 | 0 | retry: |
475 | 0 | v = rand_i(random, len); |
476 | 0 | for (mrb_int j = 0; j < i; j++) { |
477 | 0 | if (idx[j] == v) goto retry; /* retry if duplicate */ |
478 | 0 | } |
479 | 0 | break; |
480 | 0 | } |
481 | 0 | idx[i] = v; |
482 | 0 | } |
483 | 0 | mrb_value result = mrb_ary_new_capa(mrb, n); |
484 | 0 | for (mrb_int i = 0; i < n; i++) { |
485 | 0 | mrb_ary_push(mrb, result, RARRAY_PTR(ary)[idx[i]]); |
486 | 0 | } |
487 | |
|
488 | 0 | return result; |
489 | 0 | } |
490 | 0 | } |
491 | | |
492 | | /* |
493 | | * call-seq: |
494 | | * Random.rand -> float |
495 | | * Random.rand(max) -> number |
496 | | * Random.rand(range) -> number |
497 | | * rand -> float |
498 | | * rand(max) -> number |
499 | | * rand(range) -> number |
500 | | * |
501 | | * Returns a random number using the default random number generator. |
502 | | * Equivalent to Random.new.rand. When called without arguments, returns |
503 | | * a random float between 0.0 and 1.0. When called with a positive integer, |
504 | | * returns a random integer between 0 and max-1. When called with a range, |
505 | | * returns a random number within that range. |
506 | | * |
507 | | * Random.rand #=> 0.8444218515250481 |
508 | | * Random.rand(10) #=> 5 |
509 | | * rand(1..6) #=> 3 |
510 | | */ |
511 | | static mrb_value |
512 | | random_f_rand(mrb_state *mrb, mrb_value self) |
513 | 0 | { |
514 | 0 | rand_state *t = random_default_state(mrb); |
515 | 0 | return random_rand_impl(mrb, t, self); |
516 | 0 | } |
517 | | |
518 | | /* |
519 | | * call-seq: |
520 | | * Random.srand(seed = nil) -> old_seed |
521 | | * srand(seed = nil) -> old_seed |
522 | | * |
523 | | * Seeds the default random number generator with the given seed. |
524 | | * If seed is omitted or nil, uses current time and internal state. |
525 | | * Returns the previous seed value. |
526 | | * |
527 | | * Random.srand(1234) #=> (previous seed) |
528 | | * srand #=> 1234 |
529 | | */ |
530 | | static mrb_value |
531 | | random_f_srand(mrb_state *mrb, mrb_value self) |
532 | 0 | { |
533 | 0 | mrb_value random = random_default(mrb); |
534 | 0 | return random_m_srand(mrb, random); |
535 | 0 | } |
536 | | |
537 | | /* |
538 | | * call-seq: |
539 | | * Random.bytes(size) -> string |
540 | | * |
541 | | * Returns a string of random bytes of the specified size using |
542 | | * the default random number generator. |
543 | | * |
544 | | * Random.bytes(4) #=> "\x8F\x12\xA3\x7C" |
545 | | * Random.bytes(10).length #=> 10 |
546 | | */ |
547 | | static mrb_value |
548 | | random_f_bytes(mrb_state *mrb, mrb_value self) |
549 | 0 | { |
550 | 0 | mrb_value random = random_default(mrb); |
551 | 0 | return random_m_bytes(mrb, random); |
552 | 0 | } |
553 | | |
554 | | |
555 | | void mrb_mruby_random_gem_init(mrb_state *mrb) |
556 | 1.32k | { |
557 | 1.32k | struct RClass *array = mrb->array_class; |
558 | | |
559 | 1.32k | mrb_static_assert(sizeof(rand_state) <= ISTRUCT_DATA_SIZE); |
560 | | |
561 | 1.32k | mrb_define_private_method_id(mrb, mrb->kernel_module, MRB_SYM(rand), random_f_rand, MRB_ARGS_OPT(1)); |
562 | 1.32k | mrb_define_private_method_id(mrb, mrb->kernel_module, MRB_SYM(srand), random_f_srand, MRB_ARGS_OPT(1)); |
563 | | |
564 | 1.32k | struct RClass *random = mrb_define_class_id(mrb, MRB_SYM(Random), mrb->object_class); |
565 | 1.32k | mrb_const_set(mrb, mrb_obj_value(mrb->object_class), ID_RANDOM, mrb_obj_value(random)); // for class check |
566 | 1.32k | MRB_SET_INSTANCE_TT(random, MRB_TT_ISTRUCT); |
567 | 1.32k | mrb_define_class_method_id(mrb, random, MRB_SYM(rand), random_f_rand, MRB_ARGS_OPT(1)); |
568 | 1.32k | mrb_define_class_method_id(mrb, random, MRB_SYM(srand), random_f_srand, MRB_ARGS_OPT(1)); |
569 | 1.32k | mrb_define_class_method_id(mrb, random, MRB_SYM(bytes), random_f_bytes, MRB_ARGS_REQ(1)); |
570 | | |
571 | 1.32k | mrb_define_method_id(mrb, random, MRB_SYM(initialize), random_m_init, MRB_ARGS_OPT(1)); |
572 | 1.32k | mrb_define_method_id(mrb, random, MRB_SYM(rand), random_m_rand, MRB_ARGS_OPT(1)); |
573 | 1.32k | mrb_define_method_id(mrb, random, MRB_SYM(srand), random_m_srand, MRB_ARGS_OPT(1)); |
574 | 1.32k | mrb_define_method_id(mrb, random, MRB_SYM(bytes), random_m_bytes, MRB_ARGS_REQ(1)); |
575 | | |
576 | 1.32k | mrb_define_method_id(mrb, array, MRB_SYM(shuffle), mrb_ary_shuffle, MRB_ARGS_OPT(1)); |
577 | 1.32k | mrb_define_method_id(mrb, array, MRB_SYM_B(shuffle), mrb_ary_shuffle_bang, MRB_ARGS_OPT(1)); |
578 | 1.32k | mrb_define_method_id(mrb, array, MRB_SYM(sample), mrb_ary_sample, MRB_ARGS_OPT(2)); |
579 | | |
580 | 1.32k | mrb_value d = mrb_obj_new(mrb, random, 0, NULL); |
581 | 1.32k | rand_state *t = random_ptr(d); |
582 | 1.32k | mrb_iv_set(mrb, mrb_obj_value(random), ID_RANDOM, d); |
583 | | |
584 | 1.32k | uint32_t seed = (uint32_t)time(NULL); |
585 | 1.32k | rand_seed(t, seed ^ (uint32_t)(uintptr_t)t); |
586 | 1.32k | } |
587 | | |
588 | | void mrb_mruby_random_gem_final(mrb_state *mrb) |
589 | 1.32k | { |
590 | 1.32k | } |