Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
random.c
Go to the documentation of this file.
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/data.h"
10 #include "mt19937ar.h"
11 
12 #include <time.h>
13 
14 #define GLOBAL_RAND_SEED_KEY "$mrb_g_rand_seed"
15 #define GLOBAL_RAND_SEED_KEY_CSTR_LEN 16
16 
17 #define INSTANCE_RAND_SEED_KEY "$mrb_i_rand_seed"
18 #define INSTANCE_RAND_SEED_KEY_CSTR_LEN 16
19 
20 #define MT_STATE_KEY "$mrb_i_mt_state"
21 #define MT_STATE_KEY_CSTR_LEN 15
22 
23 static const struct mrb_data_type mt_state_type = {
25 };
26 
27 static mt_state *mrb_mt_get_context(mrb_state *mrb, mrb_value self)
28 {
29  mt_state *t;
31 
32  context = mrb_iv_get(mrb, self, mrb_intern2(mrb, MT_STATE_KEY, MT_STATE_KEY_CSTR_LEN));
33  t = DATA_GET_PTR(mrb, context, &mt_state_type, mt_state);
34 
35  return t;
36 }
37 
38 static void mt_g_srand(unsigned long seed)
39 {
40  init_genrand(seed);
41 }
42 
43 static unsigned long mt_g_rand()
44 {
45  return genrand_int32();
46 }
47 
48 static double mt_g_rand_real()
49 {
50  return genrand_real1();
51 }
52 
53 static mrb_value mrb_random_mt_g_srand(mrb_state *mrb, mrb_value seed)
54 {
55  if (mrb_nil_p(seed)) {
56  seed = mrb_fixnum_value(time(NULL) + mt_g_rand());
57  if (mrb_fixnum(seed) < 0) {
58  seed = mrb_fixnum_value( 0 - mrb_fixnum(seed));
59  }
60  }
61 
62  mt_g_srand((unsigned) mrb_fixnum(seed));
63 
64  return seed;
65 }
66 
67 static mrb_value mrb_random_mt_g_rand(mrb_state *mrb, mrb_value max)
68 {
69  mrb_value value;
70 
71  if (mrb_fixnum(max) == 0) {
72  value = mrb_float_value(mrb, mt_g_rand_real());
73  } else {
74  value = mrb_fixnum_value(mt_g_rand() % mrb_fixnum(max));
75  }
76 
77  return value;
78 }
79 
80 static void mt_srand(mt_state *t, unsigned long seed)
81 {
82  mrb_random_init_genrand(t, seed);
83 }
84 
85 static unsigned long mt_rand(mt_state *t)
86 {
87  return mrb_random_genrand_int32(t);
88 }
89 
90 static double mt_rand_real(mt_state *t)
91 {
92  return mrb_random_genrand_real1(t);
93 }
94 
95 static mrb_value mrb_random_mt_srand(mrb_state *mrb, mt_state *t, mrb_value seed)
96 {
97  if (mrb_nil_p(seed)) {
98  seed = mrb_fixnum_value(time(NULL) + mt_rand(t));
99  if (mrb_fixnum(seed) < 0) {
100  seed = mrb_fixnum_value( 0 - mrb_fixnum(seed));
101  }
102  }
103 
104  mt_srand(t, (unsigned) mrb_fixnum(seed));
105 
106  return seed;
107 }
108 
109 static mrb_value mrb_random_mt_rand(mrb_state *mrb, mt_state *t, mrb_value max)
110 {
111  mrb_value value;
112 
113  if (mrb_fixnum(max) == 0) {
114  value = mrb_float_value(mrb, mt_rand_real(t));
115  } else {
116  value = mrb_fixnum_value(mt_rand(t) % mrb_fixnum(max));
117  }
118 
119  return value;
120 }
121 
122 static mrb_value get_opt(mrb_state* mrb)
123 {
124  mrb_value arg;
125 
126  arg = mrb_fixnum_value(0);
127  mrb_get_args(mrb, "|o", &arg);
128 
129  if (!mrb_nil_p(arg)) {
130  if (!mrb_fixnum_p(arg)) {
131  mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid argument type");
132  }
133  arg = mrb_check_convert_type(mrb, arg, MRB_TT_FIXNUM, "Fixnum", "to_int");
134  if (mrb_fixnum(arg) < 0) {
135  arg = mrb_fixnum_value(0 - mrb_fixnum(arg));
136  }
137  }
138  return arg;
139 }
140 
141 static mrb_value mrb_random_g_rand(mrb_state *mrb, mrb_value self)
142 {
143  mrb_value max;
144  mrb_value seed;
145 
146  max = get_opt(mrb);
148  if (mrb_nil_p(seed)) {
149  mrb_random_mt_g_srand(mrb, mrb_nil_value());
150  }
151  return mrb_random_mt_g_rand(mrb, max);
152 }
153 
154 static mrb_value mrb_random_g_srand(mrb_state *mrb, mrb_value self)
155 {
156  mrb_value seed;
157  mrb_value old_seed;
158 
159  seed = get_opt(mrb);
160  seed = mrb_random_mt_g_srand(mrb, seed);
163  return old_seed;
164 }
165 
166 static mrb_value mrb_random_init(mrb_state *mrb, mrb_value self)
167 {
168  mrb_value seed;
169 
170 
171  mt_state *t = (mt_state *)mrb_malloc(mrb, sizeof(mt_state));
172  t->mti = N + 1;
173 
174  seed = get_opt(mrb);
175  seed = mrb_random_mt_srand(mrb, t, seed);
178  mrb_obj_value(Data_Wrap_Struct(mrb, mrb->object_class, &mt_state_type, (void*) t)));
179  return self;
180 }
181 
182 static mrb_value mrb_random_rand(mrb_state *mrb, mrb_value self)
183 {
184  mrb_value max;
185  mrb_value seed;
186  mt_state *t = mrb_mt_get_context(mrb, self);
187 
188  max = get_opt(mrb);
190  if (mrb_nil_p(seed)) {
191  mrb_random_mt_srand(mrb, t, mrb_nil_value());
192  }
193  return mrb_random_mt_rand(mrb, t, max);
194 }
195 
196 static mrb_value mrb_random_srand(mrb_state *mrb, mrb_value self)
197 {
198  mrb_value seed;
199  mrb_value old_seed;
200  mt_state *t = mrb_mt_get_context(mrb, self);
201 
202  seed = get_opt(mrb);
203  seed = mrb_random_mt_srand(mrb, t, seed);
206 
207  return old_seed;
208 }
209 
211 {
212  struct RClass *random;
213 
214  mrb_define_method(mrb, mrb->kernel_module, "rand", mrb_random_g_rand, MRB_ARGS_OPT(1));
215  mrb_define_method(mrb, mrb->kernel_module, "srand", mrb_random_g_srand, MRB_ARGS_OPT(1));
216 
217  random = mrb_define_class(mrb, "Random", mrb->object_class);
218  mrb_define_class_method(mrb, random, "rand", mrb_random_g_rand, MRB_ARGS_OPT(1));
219  mrb_define_class_method(mrb, random, "srand", mrb_random_g_srand, MRB_ARGS_OPT(1));
220 
221  mrb_define_method(mrb, random, "initialize", mrb_random_init, MRB_ARGS_OPT(1));
222  mrb_define_method(mrb, random, "rand", mrb_random_rand, MRB_ARGS_OPT(1));
223  mrb_define_method(mrb, random, "srand", mrb_random_srand, MRB_ARGS_OPT(1));
224 }
225 
227 {
228 }