Commit 756c3fbf authored by Yukihiro "Matz" Matsumoto's avatar Yukihiro "Matz" Matsumoto

Merge branch 'master' of github.com:mruby/mruby

parents 8af26752 e1f4e891
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "mruby.h" #include "mruby.h"
#include "mruby/variable.h" #include "mruby/variable.h"
#include "mruby/class.h"
#include "mruby/data.h" #include "mruby/data.h"
#include "mruby/array.h" #include "mruby/array.h"
#include "mt19937ar.h" #include "mt19937ar.h"
...@@ -19,23 +20,11 @@ ...@@ -19,23 +20,11 @@
#define INSTANCE_RAND_SEED_KEY_CSTR_LEN 16 #define INSTANCE_RAND_SEED_KEY_CSTR_LEN 16
#define MT_STATE_KEY "$mrb_i_mt_state" #define MT_STATE_KEY "$mrb_i_mt_state"
#define MT_STATE_KEY_CSTR_LEN 15
static const struct mrb_data_type mt_state_type = { static const struct mrb_data_type mt_state_type = {
MT_STATE_KEY, mrb_free, MT_STATE_KEY, mrb_free,
}; };
static mt_state *mrb_mt_get_context(mrb_state *mrb, mrb_value self)
{
mt_state *t;
mrb_value context;
context = mrb_iv_get(mrb, self, mrb_intern2(mrb, MT_STATE_KEY, MT_STATE_KEY_CSTR_LEN));
t = DATA_GET_PTR(mrb, context, &mt_state_type, mt_state);
return t;
}
static void mt_g_srand(unsigned long seed) static void mt_g_srand(unsigned long seed)
{ {
init_genrand(seed); init_genrand(seed);
...@@ -51,7 +40,8 @@ static double mt_g_rand_real() ...@@ -51,7 +40,8 @@ static double mt_g_rand_real()
return genrand_real1(); return genrand_real1();
} }
static mrb_value mrb_random_mt_g_srand(mrb_state *mrb, mrb_value seed) static mrb_value
mrb_random_mt_g_srand(mrb_state *mrb, mrb_value seed)
{ {
if (mrb_nil_p(seed)) { if (mrb_nil_p(seed)) {
seed = mrb_fixnum_value(time(NULL) + mt_g_rand()); seed = mrb_fixnum_value(time(NULL) + mt_g_rand());
...@@ -65,7 +55,8 @@ static mrb_value mrb_random_mt_g_srand(mrb_state *mrb, mrb_value seed) ...@@ -65,7 +55,8 @@ static mrb_value mrb_random_mt_g_srand(mrb_state *mrb, mrb_value seed)
return seed; return seed;
} }
static mrb_value mrb_random_mt_g_rand(mrb_state *mrb, mrb_value max) static mrb_value
mrb_random_mt_g_rand(mrb_state *mrb, mrb_value max)
{ {
mrb_value value; mrb_value value;
...@@ -78,22 +69,26 @@ static mrb_value mrb_random_mt_g_rand(mrb_state *mrb, mrb_value max) ...@@ -78,22 +69,26 @@ static mrb_value mrb_random_mt_g_rand(mrb_state *mrb, mrb_value max)
return value; return value;
} }
static void mt_srand(mt_state *t, unsigned long seed) static void
mt_srand(mt_state *t, unsigned long seed)
{ {
mrb_random_init_genrand(t, seed); mrb_random_init_genrand(t, seed);
} }
static unsigned long mt_rand(mt_state *t) static unsigned long
mt_rand(mt_state *t)
{ {
return mrb_random_genrand_int32(t); return mrb_random_genrand_int32(t);
} }
static double mt_rand_real(mt_state *t) static double
mt_rand_real(mt_state *t)
{ {
return mrb_random_genrand_real1(t); return mrb_random_genrand_real1(t);
} }
static mrb_value mrb_random_mt_srand(mrb_state *mrb, mt_state *t, mrb_value seed) static mrb_value
mrb_random_mt_srand(mrb_state *mrb, mt_state *t, mrb_value seed)
{ {
if (mrb_nil_p(seed)) { if (mrb_nil_p(seed)) {
seed = mrb_fixnum_value(time(NULL) + mt_rand(t)); seed = mrb_fixnum_value(time(NULL) + mt_rand(t));
...@@ -107,7 +102,8 @@ static mrb_value mrb_random_mt_srand(mrb_state *mrb, mt_state *t, mrb_value seed ...@@ -107,7 +102,8 @@ static mrb_value mrb_random_mt_srand(mrb_state *mrb, mt_state *t, mrb_value seed
return seed; return seed;
} }
static mrb_value mrb_random_mt_rand(mrb_state *mrb, mt_state *t, mrb_value max) static mrb_value
mrb_random_mt_rand(mrb_state *mrb, mt_state *t, mrb_value max)
{ {
mrb_value value; mrb_value value;
...@@ -120,7 +116,8 @@ static mrb_value mrb_random_mt_rand(mrb_state *mrb, mt_state *t, mrb_value max) ...@@ -120,7 +116,8 @@ static mrb_value mrb_random_mt_rand(mrb_state *mrb, mt_state *t, mrb_value max)
return value; return value;
} }
static mrb_value get_opt(mrb_state* mrb) static mrb_value
get_opt(mrb_state* mrb)
{ {
mrb_value arg; mrb_value arg;
...@@ -139,20 +136,29 @@ static mrb_value get_opt(mrb_state* mrb) ...@@ -139,20 +136,29 @@ static mrb_value get_opt(mrb_state* mrb)
return arg; return arg;
} }
static mrb_value mrb_random_g_rand(mrb_state *mrb, mrb_value self) static void
mrb_random_g_rand_seed(mrb_state *mrb)
{ {
mrb_value max;
mrb_value seed; mrb_value seed;
max = get_opt(mrb);
seed = mrb_gv_get(mrb, mrb_intern2(mrb, GLOBAL_RAND_SEED_KEY, GLOBAL_RAND_SEED_KEY_CSTR_LEN)); seed = mrb_gv_get(mrb, mrb_intern2(mrb, GLOBAL_RAND_SEED_KEY, GLOBAL_RAND_SEED_KEY_CSTR_LEN));
if (mrb_nil_p(seed)) { if (mrb_nil_p(seed)) {
mrb_random_mt_g_srand(mrb, mrb_nil_value()); mrb_random_mt_g_srand(mrb, mrb_nil_value());
} }
}
static mrb_value
mrb_random_g_rand(mrb_state *mrb, mrb_value self)
{
mrb_value max;
max = get_opt(mrb);
mrb_random_g_rand_seed(mrb);
return mrb_random_mt_g_rand(mrb, max); return mrb_random_mt_g_rand(mrb, max);
} }
static mrb_value mrb_random_g_srand(mrb_state *mrb, mrb_value self) static mrb_value
mrb_random_g_srand(mrb_state *mrb, mrb_value self)
{ {
mrb_value seed; mrb_value seed;
mrb_value old_seed; mrb_value old_seed;
...@@ -164,41 +170,62 @@ static mrb_value mrb_random_g_srand(mrb_state *mrb, mrb_value self) ...@@ -164,41 +170,62 @@ static mrb_value mrb_random_g_srand(mrb_state *mrb, mrb_value self)
return old_seed; return old_seed;
} }
static mrb_value mrb_random_init(mrb_state *mrb, mrb_value self) static mrb_value
mrb_random_init(mrb_state *mrb, mrb_value self)
{ {
mrb_value seed; mrb_value seed;
mt_state *t;
DATA_TYPE(self) = &mt_state_type;
DATA_PTR(self) = NULL;
/* avoid memory leaks */
t = (mt_state*)DATA_PTR(self);
if (t) {
mrb_free(mrb, t);
}
mt_state *t = (mt_state *)mrb_malloc(mrb, sizeof(mt_state)); t = (mt_state *)mrb_malloc(mrb, sizeof(mt_state));
t->mti = N + 1; t->mti = N + 1;
seed = get_opt(mrb); seed = get_opt(mrb);
seed = mrb_random_mt_srand(mrb, t, seed); seed = mrb_random_mt_srand(mrb, t, seed);
mrb_iv_set(mrb, self, mrb_intern2(mrb, INSTANCE_RAND_SEED_KEY, INSTANCE_RAND_SEED_KEY_CSTR_LEN), seed); mrb_iv_set(mrb, self, mrb_intern2(mrb, INSTANCE_RAND_SEED_KEY, INSTANCE_RAND_SEED_KEY_CSTR_LEN), seed);
mrb_iv_set(mrb, self, mrb_intern2(mrb, MT_STATE_KEY, MT_STATE_KEY_CSTR_LEN),
mrb_obj_value(Data_Wrap_Struct(mrb, mrb->object_class, &mt_state_type, (void*) t))); DATA_PTR(self) = t;
return self; return self;
} }
static mrb_value mrb_random_rand(mrb_state *mrb, mrb_value self) static void
mrb_random_rand_seed(mrb_state *mrb, mrb_value self)
{ {
mrb_value max;
mrb_value seed; mrb_value seed;
mt_state *t = mrb_mt_get_context(mrb, self); mt_state *t = DATA_PTR(self);
max = get_opt(mrb);
seed = mrb_iv_get(mrb, self, mrb_intern2(mrb, INSTANCE_RAND_SEED_KEY, INSTANCE_RAND_SEED_KEY_CSTR_LEN)); seed = mrb_iv_get(mrb, self, mrb_intern2(mrb, INSTANCE_RAND_SEED_KEY, INSTANCE_RAND_SEED_KEY_CSTR_LEN));
if (mrb_nil_p(seed)) { if (mrb_nil_p(seed)) {
mrb_random_mt_srand(mrb, t, mrb_nil_value()); mrb_random_mt_srand(mrb, t, mrb_nil_value());
} }
}
static mrb_value
mrb_random_rand(mrb_state *mrb, mrb_value self)
{
mrb_value max;
mt_state *t = DATA_PTR(self);
max = get_opt(mrb);
mrb_random_rand_seed(mrb, self);
return mrb_random_mt_rand(mrb, t, max); return mrb_random_mt_rand(mrb, t, max);
} }
static mrb_value mrb_random_srand(mrb_state *mrb, mrb_value self) static mrb_value
mrb_random_srand(mrb_state *mrb, mrb_value self)
{ {
mrb_value seed; mrb_value seed;
mrb_value old_seed; mrb_value old_seed;
mt_state *t = mrb_mt_get_context(mrb, self); mt_state *t = DATA_PTR(self);
seed = get_opt(mrb); seed = get_opt(mrb);
seed = mrb_random_mt_srand(mrb, t, seed); seed = mrb_random_mt_srand(mrb, t, seed);
...@@ -219,17 +246,29 @@ static mrb_value ...@@ -219,17 +246,29 @@ static mrb_value
mrb_ary_shuffle_bang(mrb_state *mrb, mrb_value ary) mrb_ary_shuffle_bang(mrb_state *mrb, mrb_value ary)
{ {
mrb_int i; mrb_int i;
mrb_value seed; mrb_value random = mrb_nil_value();
seed = mrb_gv_get(mrb, mrb_intern2(mrb, GLOBAL_RAND_SEED_KEY, GLOBAL_RAND_SEED_KEY_CSTR_LEN)); if (RARRAY_LEN(ary) > 1) {
if (mrb_nil_p(seed)) { mrb_get_args(mrb, "|o", &random);
mrb_random_mt_g_srand(mrb, mrb_nil_value());
if( mrb_nil_p(random) ) {
mrb_random_g_rand_seed(mrb);
} else {
mrb_data_check_type(mrb, random, &mt_state_type);
mrb_random_rand_seed(mrb, random);
} }
if (RARRAY_LEN(ary) > 1) {
mrb_ary_modify(mrb, mrb_ary_ptr(ary)); mrb_ary_modify(mrb, mrb_ary_ptr(ary));
for (i = RARRAY_LEN(ary) - 1; i > 0; i--) { for (i = RARRAY_LEN(ary) - 1; i > 0; i--) {
mrb_int j = mrb_fixnum(mrb_random_mt_g_rand(mrb, mrb_fixnum_value(RARRAY_LEN(ary)))); mrb_int j;
if( mrb_nil_p(random) ) {
j = mrb_fixnum(mrb_random_mt_g_rand(mrb, mrb_fixnum_value(RARRAY_LEN(ary))));
} else {
j = mrb_fixnum(mrb_random_mt_rand(mrb, DATA_PTR(random), mrb_fixnum_value(RARRAY_LEN(ary))));
}
mrb_value t = RARRAY_PTR(ary)[i]; mrb_value t = RARRAY_PTR(ary)[i];
RARRAY_PTR(ary)[i] = RARRAY_PTR(ary)[j]; RARRAY_PTR(ary)[i] = RARRAY_PTR(ary)[j];
RARRAY_PTR(ary)[j] = t; RARRAY_PTR(ary)[j] = t;
...@@ -264,6 +303,7 @@ void mrb_mruby_random_gem_init(mrb_state *mrb) ...@@ -264,6 +303,7 @@ void mrb_mruby_random_gem_init(mrb_state *mrb)
mrb_define_method(mrb, mrb->kernel_module, "srand", mrb_random_g_srand, MRB_ARGS_OPT(1)); mrb_define_method(mrb, mrb->kernel_module, "srand", mrb_random_g_srand, MRB_ARGS_OPT(1));
random = mrb_define_class(mrb, "Random", mrb->object_class); random = mrb_define_class(mrb, "Random", mrb->object_class);
MRB_SET_INSTANCE_TT(random, MRB_TT_DATA);
mrb_define_class_method(mrb, random, "rand", mrb_random_g_rand, MRB_ARGS_OPT(1)); mrb_define_class_method(mrb, random, "rand", mrb_random_g_rand, MRB_ARGS_OPT(1));
mrb_define_class_method(mrb, random, "srand", mrb_random_g_srand, MRB_ARGS_OPT(1)); mrb_define_class_method(mrb, random, "srand", mrb_random_g_srand, MRB_ARGS_OPT(1));
...@@ -271,8 +311,8 @@ void mrb_mruby_random_gem_init(mrb_state *mrb) ...@@ -271,8 +311,8 @@ void mrb_mruby_random_gem_init(mrb_state *mrb)
mrb_define_method(mrb, random, "rand", mrb_random_rand, MRB_ARGS_OPT(1)); mrb_define_method(mrb, random, "rand", mrb_random_rand, MRB_ARGS_OPT(1));
mrb_define_method(mrb, random, "srand", mrb_random_srand, MRB_ARGS_OPT(1)); mrb_define_method(mrb, random, "srand", mrb_random_srand, MRB_ARGS_OPT(1));
mrb_define_method(mrb, array, "shuffle", mrb_ary_shuffle, MRB_ARGS_NONE()); mrb_define_method(mrb, array, "shuffle", mrb_ary_shuffle, MRB_ARGS_OPT(1));
mrb_define_method(mrb, array, "shuffle!", mrb_ary_shuffle_bang, MRB_ARGS_NONE()); mrb_define_method(mrb, array, "shuffle!", mrb_ary_shuffle_bang, MRB_ARGS_OPT(1));
} }
void mrb_mruby_random_gem_final(mrb_state *mrb) void mrb_mruby_random_gem_final(mrb_state *mrb)
......
...@@ -44,3 +44,33 @@ assert('Array#shuffle!') do ...@@ -44,3 +44,33 @@ assert('Array#shuffle!') do
ary != [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] and 10.times { |x| ary.include? x } ary != [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] and 10.times { |x| ary.include? x }
end end
assert("Array#shuffle(random)") do
assert_raise(TypeError) do
# this will cause an exception due to the wrong argument
[1, 2].shuffle "Not a Random instance"
end
# verify that the same seed causes the same results
ary1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
shuffle1 = ary1.shuffle Random.new 345
ary2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
shuffle2 = ary2.shuffle Random.new 345
ary1 != shuffle1 and 10.times { |x| shuffle1.include? x } and shuffle1 == shuffle2
end
assert('Array#shuffle!(random)') do
assert_raise(TypeError) do
# this will cause an exception due to the wrong argument
[1, 2].shuffle! "Not a Random instance"
end
# verify that the same seed causes the same results
ary1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
ary1.shuffle! Random.new 345
ary2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
ary2.shuffle! Random.new 345
ary1 != [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] and 10.times { |x| ary1.include? x } and ary1 == ary2
end
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment