Coverage Report

Created: 2025-06-13 07:32

/src/mruby/mrbgems/mruby-random/src/random.c
Line
Count
Source (jump to first uncovered line)
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
17
#include <time.h>
18
19
/*  Written in 2019 by David Blackman and Sebastiano Vigna (vigna@acm.org)
20
21
To the extent possible under law, the author has dedicated all copyright
22
and related and neighboring rights to this software to the public domain
23
worldwide. This software is distributed without any warranty.
24
25
See <https://creativecommons.org/publicdomain/zero/1.0/>. */
26
27
/* This is xoshiro128++ 1.0, one of our 32-bit all-purpose, rock-solid
28
   generators. It has excellent speed, a state size (128 bits) that is
29
   large enough for mild parallelism, and it passes all tests we are aware
30
   of.
31
32
   For generating just single-precision (i.e., 32-bit) floating-point
33
   numbers, xoshiro128+ is even faster.
34
35
   The state must be seeded so that it is not everywhere zero. */
36
37
38
#ifdef MRB_32BIT
39
# define XORSHIFT96
40
# define NSEEDS 3
41
# define SEEDPOS 2
42
#else
43
# define NSEEDS 4
44
4.10k
# define SEEDPOS 0
45
#endif
46
#define LASTSEED (NSEEDS-1)
47
48
typedef struct rand_state {
49
  uint32_t seed[NSEEDS];
50
} rand_state;
51
52
static void
53
rand_init(rand_state *t)
54
4.10k
{
55
4.10k
  t->seed[0] = 123456789;
56
4.10k
  t->seed[1] = 362436069;
57
4.10k
  t->seed[2] = 521288629;
58
4.10k
#ifndef XORSHIFT96
59
4.10k
  t->seed[3] = 88675123;
60
4.10k
#endif
61
4.10k
}
62
63
static uint32_t rand_uint32(rand_state *state);
64
65
static uint32_t
66
rand_seed(rand_state *t, uint32_t seed)
67
2.05k
{
68
2.05k
  uint32_t old_seed = t->seed[SEEDPOS];
69
2.05k
  rand_init(t);
70
2.05k
  t->seed[SEEDPOS] = seed;
71
22.5k
  for (int i = 0; i < 10; i++) {
72
20.5k
    rand_uint32(t);
73
20.5k
  }
74
2.05k
  return old_seed;
75
2.05k
}
76
77
#ifndef XORSHIFT96
78
static inline uint32_t
79
41.0k
rotl(const uint32_t x, int k) {
80
41.0k
  return (x << k) | (x >> (32 - k));
81
41.0k
}
82
#endif
83
84
static uint32_t
85
rand_uint32(rand_state *state)
86
20.5k
{
87
#ifdef XORSHIFT96
88
  uint32_t *seed = state->seed;
89
  uint32_t x = seed[0];
90
  uint32_t y = seed[1];
91
  uint32_t z = seed[2];
92
  uint32_t t = (x ^ (x << 3)) ^ (y ^ (y >> 19)) ^ (z ^ (z << 6));
93
94
  x = y; y = z; z = t;
95
  seed[0] = x;
96
  seed[1] = y;
97
  seed[2] = z;
98
99
  return z;
100
#else
101
20.5k
  uint32_t *s = state->seed;
102
20.5k
  const uint32_t result = rotl(s[0] + s[3], 7) + s[0];
103
20.5k
  const uint32_t t = s[1] << 9;
104
105
20.5k
  s[2] ^= s[0];
106
20.5k
  s[3] ^= s[1];
107
20.5k
  s[1] ^= s[2];
108
20.5k
  s[0] ^= s[3];
109
110
20.5k
  s[2] ^= t;
111
20.5k
  s[3] = rotl(s[3], 11);
112
113
20.5k
  return result;
114
20.5k
#endif  /* XORSHIFT96 */
115
20.5k
  }
116
117
#ifndef MRB_NO_FLOAT
118
static double
119
rand_real(rand_state *t)
120
0
{
121
0
  uint32_t x = rand_uint32(t);
122
0
  return x*(1.0/4294967296.0);
123
0
}
124
#endif
125
126
static mrb_value
127
random_rand(mrb_state *mrb, rand_state *t, mrb_int max)
128
0
{
129
0
  if (max == 0) {
130
0
#ifndef MRB_NO_FLOAT
131
0
    return mrb_float_value(mrb, rand_real(t));
132
#else
133
    max = 100;
134
#endif
135
0
  }
136
0
  return mrb_int_value(mrb, rand_uint32(t) % max);
137
0
}
138
139
static mrb_int
140
rand_i(rand_state *t, mrb_int max)
141
0
{
142
0
  return rand_uint32(t) % max;
143
0
}
144
145
static mrb_value
146
rand_range_int(mrb_state *mrb, rand_state *t, mrb_int begin,
147
0
               mrb_int end, mrb_bool excl) {
148
0
  mrb_int span = end - begin + (excl ? 0 : 1);
149
0
  if (span <= 0)
150
0
    return mrb_nil_value();
151
152
0
  return mrb_int_value(mrb, (rand_i(t, span)) + begin);
153
0
}
154
155
#ifndef MRB_NO_FLOAT
156
static mrb_value
157
rand_range_float(mrb_state *mrb, rand_state *t,
158
                 mrb_float begin, mrb_float end,
159
0
                 mrb_bool excl) {
160
0
  mrb_float span = end - begin + (excl ? 0.0 : 1.0);
161
0
  if (span <= 0.0)
162
0
    return mrb_nil_value();
163
164
0
  return mrb_float_value(mrb, rand_real(t) * span + begin);
165
0
}
166
#endif
167
168
static mrb_noreturn void
169
range_error(mrb_state *mrb, mrb_value v)
170
0
{
171
0
  mrb_raisef(mrb, E_TYPE_ERROR, "no implicit conversion of %Y into Integer", v);
172
0
}
173
174
static mrb_value
175
random_range(mrb_state *mrb, rand_state *t, mrb_value rv)
176
0
{
177
0
  struct RRange *r = mrb_range_ptr(mrb, rv);
178
0
  if (mrb_integer_p(RANGE_BEG(r)) && mrb_integer_p(RANGE_END(r))) {
179
0
    return rand_range_int(mrb, t, mrb_integer(RANGE_BEG(r)),
180
0
                          mrb_integer(RANGE_END(r)), RANGE_EXCL(r));
181
0
  }
182
183
0
#define cast_to_float(v)                                                       \
184
0
  (mrb_float_p(v)     ? mrb_float(v)                                           \
185
0
   : mrb_integer_p(v) ? (mrb_float)mrb_integer(v)                              \
186
0
                      : (range_error(mrb, v), 0.0))
187
188
0
  return rand_range_float(mrb, t, cast_to_float(RANGE_BEG(r)),
189
0
                          cast_to_float(RANGE_END(r)), RANGE_EXCL(r));
190
0
#undef cast_to_float
191
0
}
192
193
static mrb_value
194
random_rand_impl(mrb_state *mrb, rand_state *t, mrb_value self)
195
0
{
196
0
  mrb_value arg;
197
0
  if (mrb_get_args(mrb, "|o", &arg) == 0) {
198
0
    return random_rand(mrb, t, 0);
199
0
  }
200
201
0
  if (mrb_float_p(arg)) {
202
0
    return random_rand(mrb, t, (mrb_int)mrb_float(arg));
203
0
  }
204
205
0
  if (mrb_integer_p(arg)) {
206
0
    return random_rand(mrb, t, mrb_integer(arg));
207
0
  }
208
209
0
  if (mrb_range_p(arg)) {
210
0
    return random_range(mrb, t, arg);
211
0
  }
212
213
0
  range_error(mrb, arg);
214
0
}
215
216
4.10k
#define ID_RANDOM MRB_SYM(mruby_Random)
217
218
static mrb_value
219
random_default(mrb_state *mrb)
220
0
{
221
0
  struct RClass *c = mrb_class_get_id(mrb, ID_RANDOM);
222
0
  mrb_value d = mrb_iv_get(mrb, mrb_obj_value(c), ID_RANDOM);
223
0
  if (!mrb_obj_is_kind_of(mrb, d, c)) {
224
0
    mrb_raise(mrb, E_RUNTIME_ERROR, "[BUG] default Random replaced");
225
0
  }
226
0
  return d;
227
0
}
228
229
4.10k
#define random_ptr(v) (rand_state*)mrb_istruct_ptr(v)
230
0
#define random_default_state(mrb) random_ptr(random_default(mrb))
231
232
static mrb_value
233
random_m_init(mrb_state *mrb, mrb_value self)
234
2.05k
{
235
2.05k
  mrb_int seed;
236
2.05k
  rand_state *t = random_ptr(self);
237
238
2.05k
  if (mrb_get_args(mrb, "|i", &seed) == 0) {
239
2.05k
    rand_init(t);
240
2.05k
  }
241
0
  else {
242
0
    rand_seed(t, (uint32_t)seed);
243
0
  }
244
245
2.05k
  return self;
246
2.05k
}
247
248
static mrb_value
249
random_m_rand(mrb_state *mrb, mrb_value self)
250
0
{
251
0
  rand_state *t = random_ptr(self);
252
0
  return random_rand_impl(mrb, t, self);
253
0
}
254
255
static mrb_value
256
random_m_srand(mrb_state *mrb, mrb_value self)
257
0
{
258
0
  uint32_t seed;
259
0
  mrb_int i;
260
0
  rand_state *t = random_ptr(self);
261
262
0
  if (mrb_get_args(mrb, "|i", &i) == 0) {
263
0
    seed = (uint32_t)time(NULL) ^ rand_uint32(t) ^ (uint32_t)(uintptr_t)t;
264
0
  }
265
0
  else {
266
0
    seed = (uint32_t)i;
267
0
  }
268
269
0
  uint32_t old_seed = rand_seed(t, seed);
270
0
  return mrb_int_value(mrb, (mrb_int)old_seed);
271
0
}
272
273
static mrb_value
274
random_m_bytes(mrb_state *mrb, mrb_value self)
275
0
{
276
0
  rand_state *t = random_ptr(self);
277
0
  mrb_int i = mrb_as_int(mrb, mrb_get_arg1(mrb));
278
0
  mrb_value bytes = mrb_str_new(mrb, NULL, i);
279
0
  uint8_t *p = (uint8_t*)RSTRING_PTR(bytes);
280
281
0
  for (; i > 0; i--, p++) {
282
0
    *p = (uint8_t)rand_uint32(t);
283
0
  }
284
285
0
  return bytes;
286
0
}
287
288
static rand_state*
289
check_random_arg(mrb_state *mrb, mrb_value r)
290
0
{
291
0
  struct RClass *c = mrb_class_get_id(mrb, ID_RANDOM);
292
0
  rand_state *random;
293
294
0
  if (mrb_undef_p(r)) {
295
0
    random = random_default_state(mrb);
296
0
  }
297
0
  else if (mrb_istruct_p(r) && mrb_obj_is_kind_of(mrb, r, c)){
298
0
    random = (rand_state*)mrb_istruct_ptr(r);
299
0
  }
300
0
  else {
301
0
    mrb_raise(mrb, E_TYPE_ERROR, "Random object required");
302
0
  }
303
0
  return random;
304
0
}
305
/*
306
 *  call-seq:
307
 *     ary.shuffle!   ->   ary
308
 *
309
 *  Shuffles elements in self in place.
310
 */
311
312
static mrb_value
313
mrb_ary_shuffle_bang(mrb_state *mrb, mrb_value ary)
314
0
{
315
0
  if (RARRAY_LEN(ary) > 1) {
316
0
    mrb_sym kname = MRB_SYM(random);
317
0
    mrb_value r;
318
0
    const mrb_kwargs kw = {1, 0, &kname, &r, NULL};
319
320
0
    mrb_get_args(mrb, ":", &kw);
321
0
    rand_state *random = check_random_arg(mrb, r);
322
0
    mrb_ary_modify(mrb, mrb_ary_ptr(ary));
323
0
    for (mrb_int i = RARRAY_LEN(ary) - 1; i > 0; i--)  {
324
0
      mrb_value *ptr = RARRAY_PTR(ary);
325
0
      mrb_int j = rand_i(random, i + 1);
326
0
      mrb_value tmp = ptr[i];
327
0
      ptr[i] = ptr[j];
328
0
      ptr[j] = tmp;
329
0
    }
330
0
  }
331
332
0
  return ary;
333
0
}
334
335
/*
336
 *  call-seq:
337
 *     ary.shuffle   ->   new_ary
338
 *
339
 *  Returns a new array with elements of self shuffled.
340
 */
341
342
static mrb_value
343
mrb_ary_shuffle(mrb_state *mrb, mrb_value ary)
344
0
{
345
0
  mrb_value new_ary = mrb_ary_new_from_values(mrb, RARRAY_LEN(ary), RARRAY_PTR(ary));
346
0
  mrb_ary_shuffle_bang(mrb, new_ary);
347
348
0
  return new_ary;
349
0
}
350
351
/*
352
 *  call-seq:
353
 *     ary.sample      ->   obj
354
 *     ary.sample(n)   ->   new_ary
355
 *
356
 *  Choose a random element or +n+ random elements from the array.
357
 *
358
 *  The elements are chosen by using random and unique indices into the array
359
 *  in order to ensure that an element doesn't repeat itself unless the array
360
 *  already contained duplicate elements.
361
 *
362
 *  If the array is empty the first form returns +nil+ and the second form
363
 *  returns an empty array.
364
 */
365
366
static mrb_value
367
mrb_ary_sample(mrb_state *mrb, mrb_value ary)
368
0
{
369
0
  mrb_int n = 0;
370
0
  mrb_bool given;
371
0
  mrb_sym kname = MRB_SYM(random);
372
0
  mrb_value r;
373
0
  const mrb_kwargs kw = {1, 0, &kname, &r, NULL};
374
375
0
  mrb_get_args(mrb, "|i?:", &n, &given, &kw);
376
0
  rand_state *random = check_random_arg(mrb, r);
377
0
  mrb_int len = RARRAY_LEN(ary);
378
0
  if (!given) {                 /* pick one element */
379
0
    switch (len) {
380
0
    case 0:
381
0
      return mrb_nil_value();
382
0
    case 1:
383
0
      return RARRAY_PTR(ary)[0];
384
0
    default:
385
0
      return RARRAY_PTR(ary)[rand_i(random, len)];
386
0
    }
387
0
  }
388
0
  else {
389
0
    if (n < 0) mrb_raise(mrb, E_ARGUMENT_ERROR, "negative sample number");
390
0
    if (n > len) n = len;
391
0
    mrb_value result = mrb_ary_new_capa(mrb, n);
392
0
    for (mrb_int i=0; i<n; i++) {
393
0
      mrb_int idx;
394
395
0
      for (;;) {
396
0
      retry:
397
0
        idx = rand_i(random, len);
398
399
0
        for (mrb_int j=0; j<i; j++) {
400
0
          if (mrb_integer(RARRAY_PTR(result)[j]) == idx) {
401
0
            goto retry;         /* retry if duplicate */
402
0
          }
403
0
        }
404
0
        break;
405
0
      }
406
0
      mrb_ary_push(mrb, result, mrb_int_value(mrb, idx));
407
0
    }
408
0
    for (mrb_int i=0; i<n; i++) {
409
0
      mrb_int idx = mrb_integer(RARRAY_PTR(result)[i]);
410
0
      mrb_value elem = RARRAY_PTR(ary)[idx];
411
0
      mrb_ary_set(mrb, result, i, elem);
412
0
    }
413
0
    return result;
414
0
  }
415
0
}
416
417
static mrb_value
418
random_f_rand(mrb_state *mrb, mrb_value self)
419
0
{
420
0
  rand_state *t = random_default_state(mrb);
421
0
  return random_rand_impl(mrb, t, self);
422
0
}
423
424
static mrb_value
425
random_f_srand(mrb_state *mrb, mrb_value self)
426
0
{
427
0
  mrb_value random = random_default(mrb);
428
0
  return random_m_srand(mrb, random);
429
0
}
430
431
static mrb_value
432
random_f_bytes(mrb_state *mrb, mrb_value self)
433
0
{
434
0
  mrb_value random = random_default(mrb);
435
0
  return random_m_bytes(mrb, random);
436
0
}
437
438
439
void mrb_mruby_random_gem_init(mrb_state *mrb)
440
2.05k
{
441
2.05k
  struct RClass *array = mrb->array_class;
442
443
2.05k
  mrb_static_assert(sizeof(rand_state) <= ISTRUCT_DATA_SIZE);
444
445
2.05k
  mrb_define_private_method_id(mrb, mrb->kernel_module, MRB_SYM(rand), random_f_rand, MRB_ARGS_OPT(1));
446
2.05k
  mrb_define_private_method_id(mrb, mrb->kernel_module, MRB_SYM(srand), random_f_srand, MRB_ARGS_OPT(1));
447
448
2.05k
  struct RClass *random = mrb_define_class_id(mrb, MRB_SYM(Random), mrb->object_class);
449
2.05k
  mrb_const_set(mrb, mrb_obj_value(mrb->object_class), ID_RANDOM, mrb_obj_value(random)); // for class check
450
2.05k
  MRB_SET_INSTANCE_TT(random, MRB_TT_ISTRUCT);
451
2.05k
  mrb_define_class_method_id(mrb, random, MRB_SYM(rand), random_f_rand, MRB_ARGS_OPT(1));
452
2.05k
  mrb_define_class_method_id(mrb, random, MRB_SYM(srand), random_f_srand, MRB_ARGS_OPT(1));
453
2.05k
  mrb_define_class_method_id(mrb, random, MRB_SYM(bytes), random_f_bytes, MRB_ARGS_REQ(1));
454
455
2.05k
  mrb_define_method_id(mrb, random, MRB_SYM(initialize), random_m_init, MRB_ARGS_OPT(1));
456
2.05k
  mrb_define_method_id(mrb, random, MRB_SYM(rand), random_m_rand, MRB_ARGS_OPT(1));
457
2.05k
  mrb_define_method_id(mrb, random, MRB_SYM(srand), random_m_srand, MRB_ARGS_OPT(1));
458
2.05k
  mrb_define_method_id(mrb, random, MRB_SYM(bytes), random_m_bytes, MRB_ARGS_REQ(1));
459
460
2.05k
  mrb_define_method_id(mrb, array, MRB_SYM(shuffle), mrb_ary_shuffle, MRB_ARGS_OPT(1));
461
2.05k
  mrb_define_method_id(mrb, array, MRB_SYM_B(shuffle), mrb_ary_shuffle_bang, MRB_ARGS_OPT(1));
462
2.05k
  mrb_define_method_id(mrb, array, MRB_SYM(sample), mrb_ary_sample, MRB_ARGS_OPT(2));
463
464
2.05k
  mrb_value d = mrb_obj_new(mrb, random, 0, NULL);
465
2.05k
  rand_state *t = random_ptr(d);
466
2.05k
  mrb_iv_set(mrb, mrb_obj_value(random), ID_RANDOM, d);
467
468
2.05k
  uint32_t seed = (uint32_t)time(NULL);
469
2.05k
  rand_seed(t, seed ^ (uint32_t)(uintptr_t)t);
470
2.05k
}
471
472
void mrb_mruby_random_gem_final(mrb_state *mrb)
473
2.05k
{
474
2.05k
}