Skip to content

Instantly share code, notes, and snippets.

@matthewd
Created April 14, 2010 17:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save matthewd/366111 to your computer and use it in GitHub Desktop.
Save matthewd/366111 to your computer and use it in GitHub Desktop.
From 64424b2d80a45d8ac9d90fd3766b63c8f5f47b12 Mon Sep 17 00:00:00 2001
From: Matthew Draper <matthew@trebex.net>
Date: Thu, 15 Apr 2010 03:23:27 +0930
Subject: [PATCH] C++ Kernel.{rand,srand} implementation
---
benchmark/rubinius/bm_random.rb | 50 ++++++
kernel/common/kernel.rb | 58 ++-----
kernel/common/load_order.txt | 1 +
kernel/common/random.rb | 47 +++++
rakelib/vm.rake | 1 +
vm/builtin/bignum.cpp | 56 ++++++
vm/builtin/bignum.hpp | 5 +
vm/builtin/randomizer.cpp | 358 +++++++++++++++++++++++++++++++++++++++
vm/builtin/randomizer.hpp | 65 +++++++
vm/globals.hpp | 2 +
10 files changed, 600 insertions(+), 43 deletions(-)
create mode 100644 benchmark/rubinius/bm_random.rb
create mode 100644 kernel/common/random.rb
create mode 100644 vm/builtin/randomizer.cpp
create mode 100644 vm/builtin/randomizer.hpp
diff --git a/benchmark/rubinius/bm_random.rb b/benchmark/rubinius/bm_random.rb
new file mode 100644
index 0000000..18646ea
--- /dev/null
+++ b/benchmark/rubinius/bm_random.rb
@@ -0,0 +1,50 @@
+require 'benchmark'
+
+total = (ENV['TOTAL'] || 10_000).to_i
+
+Benchmark.bmbm do |x|
+ x.report("Kernel#rand()") do
+ total.times do
+ rand
+ end
+ end
+
+ x.report("Kernel#rand(10)") do
+ total.times do
+ rand(10)
+ end
+ end
+
+ x.report("Kernel#rand(0x12345678901234567890)") do
+ total.times do
+ rand(0x12345678901234567890)
+ end
+ end
+
+ x.report("Kernel#srand()") do
+ total.times do
+ srand
+ end
+ end
+
+ x.report("Kernel#srand(0)") do
+ total.times do
+ srand(0)
+ end
+ end
+
+ x.report("Kernel#srand(0x12345678901234567890)") do
+ total.times do
+ srand(0x12345678901234567890)
+ end
+ end
+
+ x.report("Kernel#srand(10); Kernel#rand") do
+ (total / 20).times do
+ srand(10)
+ 50.times do
+ rand
+ end
+ end
+ end
+end
diff --git a/kernel/common/kernel.rb b/kernel/common/kernel.rb
index 17aa87f..ec107b5 100644
--- a/kernel/common/kernel.rb
+++ b/kernel/common/kernel.rb
@@ -222,57 +222,29 @@ module Kernel
end
module_function :open
- #--
- # NOTE: This isn't quite MRI compatible.
- # We don't seed the RNG by default with a combination of time, pid and
- # sequence number
- #++
- #
-
- @current_seed = 0
-
- def self.srand(seed=undefined)
- cur = @current_srand
-
+ def srand(seed=undefined)
if seed.equal? undefined
- begin
- File.open("/dev/urandom", "r") do |f|
- seed = f.read(10).unpack("I*")[0]
- end
- rescue Errno::ENOENT, Errno::EPERM, Errno::EACCES
- seed = Time.now.to_i
- end
- else
- seed = Type.coerce_to(seed, Integer, :to_int)
+ seed = Rubinius::Randomizer.instance.generate_seed
end
- FFI::Platform::POSIX.srand(seed)
- @current_srand = seed
-
- cur
- end
+ unless seed.respond_to?(:to_int)
+ raise TypeError, "can't convert #{seed.class} into Integer"
+ end
- # Redispatch to Kernel so we can store @current_srand as an ivar
- # on Kernel without an accessor.
- def srand(seed=undefined)
- Kernel.srand(seed)
+ Rubinius::Randomizer.instance.swap_seed seed.to_int
end
+ module_function :srand
- private :srand
-
- def rand(max=0)
- max = max.to_i.abs
- x = FFI::Platform::POSIX.rand
+ def rand(limit=0)
+ limit = Integer(limit).abs
- # scale result of rand to a domain between 0 and max
- if max == 0
- x.to_f / 2147483647.0
- elsif max == 1
- 0
- elsif x < max
- x
+ case limit
+ when 0
+ Rubinius::Randomizer.instance.random_float
+ when Integer
+ Rubinius::Randomizer.instance.random_integer(limit - 1)
else
- x % max
+ raise TypeError, "Integer() returned a non-integer"
end
end
module_function :rand
diff --git a/kernel/common/load_order.txt b/kernel/common/load_order.txt
index 13e55b2..00fa0e8 100644
--- a/kernel/common/load_order.txt
+++ b/kernel/common/load_order.txt
@@ -64,6 +64,7 @@ rubinius.rbc
pack.rbc
struct.rbc
process.rbc
+random.rbc
regexp.rbc
selector.rbc
signal.rbc
diff --git a/kernel/common/random.rb b/kernel/common/random.rb
new file mode 100644
index 0000000..fffb1de
--- /dev/null
+++ b/kernel/common/random.rb
@@ -0,0 +1,47 @@
+class Rubinius::Randomizer
+ def self.allocate
+ Ruby.primitive :randomizer_allocate
+ raise PrimitiveFailure, "Randomizer.allocate primitive failed"
+ end
+
+ def self.instance
+ @instance || (@instance = new)
+ end
+
+ def initialize
+ self.seed = generate_seed
+ end
+
+ attr_reader :seed
+ def seed=(new_seed)
+ set_seed new_seed
+ @seed = new_seed
+ end
+
+ def set_seed(new_seed)
+ Ruby.primitive :randomizer_seed
+ raise PrimitiveFailure, "Randomizer#seed primitive failed"
+ end
+
+ def swap_seed(new_seed)
+ old_seed, self.seed = self.seed, new_seed
+ old_seed
+ end
+
+ # Generate a random Float, in the range 0...1.0
+ def random_float
+ Ruby.primitive :randomizer_rand_float
+ raise PrimitiveFailure, "Randomizer#rand_float primitive failed"
+ end
+
+ # Generate a random Integer, in the range 0...limit
+ def random_integer(limit)
+ Ruby.primitive :randomizer_rand_int
+ raise PrimitiveFailure, "Randomizer#rand_int primitive failed"
+ end
+
+ def generate_seed
+ Ruby.primitive :randomizer_gen_seed
+ raise PrimitiveFailure, "Randomizer#gen_seed primitive failed"
+ end
+end
diff --git a/rakelib/vm.rake b/rakelib/vm.rake
index c4bb0e5..c16c66a 100644
--- a/rakelib/vm.rake
+++ b/rakelib/vm.rake
@@ -109,6 +109,7 @@ field_extract_headers = %w[
vm/builtin/methodtable.hpp
vm/builtin/nativefunction.hpp
vm/builtin/packed_object.hpp
+ vm/builtin/randomizer.hpp
vm/builtin/regexp.hpp
vm/builtin/staticscope.hpp
vm/builtin/string.hpp
diff --git a/vm/builtin/bignum.cpp b/vm/builtin/bignum.cpp
index e0f5e24..fdc5136 100644
--- a/vm/builtin/bignum.cpp
+++ b/vm/builtin/bignum.cpp
@@ -405,6 +405,14 @@ namespace rubinius {
return b;
}
+ Integer* Bignum::abs(STATE) {
+ if (mp_val()->sign == MP_NEG) {
+ return Bignum::from(state, 0)->sub(state, this);
+ } else {
+ return this;
+ }
+ }
+
Integer* Bignum::add(STATE, Fixnum* b) {
NMP;
native_int bi = b->to_native();
@@ -1041,6 +1049,54 @@ namespace rubinius {
mp_toradix_nd(XST, mp_val(), buf, radix, sz, &k);
}
+ Integer* Bignum::from_array(STATE, uint32_t *ary, size_t sz) {
+ /*
+ * Read the values from the given array to populate a bignum.
+ *
+ * ary[0] contains the least significant sizeof(ary[0]) * 8 bits;
+ * ary[1] the next least significant, etc.
+ *
+ * See also Bignum::into_array()
+ */
+
+ Bignum* big = Bignum::create(state);
+
+ for (unsigned int i = 0; i < sz; i++) {
+ Integer* tmp = big->left_shift(state, Fixnum::from(32));
+ big = tmp->fixnum_p() ? Bignum::from(state, tmp->to_native()) : as<Bignum>(tmp);
+ tmp = big->bit_or(state, Bignum::from(state, ary[i]));
+ big = tmp->fixnum_p() ? Bignum::from(state, tmp->to_native()) : as<Bignum>(tmp);
+ }
+
+ return Bignum::normalize(state, big);
+ }
+
+ size_t Bignum::into_array(STATE, uint32_t *ary, size_t sz) {
+ /*
+ * Split the bignum's value into an array of unsigned integers.
+ *
+ * After execution, ary[0] contains the least significant
+ * sizeof(ary[0]) * 8 bits; ary[1] the next least significant, etc.
+ *
+ * See also Bignum::from_array()
+ */
+
+ if (ary) ary[0] = 0;
+
+ uint32_t n = 0;
+ Bignum* zero = Bignum::from(state, 0);
+ Integer* rest_i = this->abs(state);
+ Bignum* rest = rest_i->fixnum_p() ? Bignum::from(state, rest_i->to_native()) : as<Bignum>(rest_i);
+ while (rest->gt(state, zero) == Qtrue) {
+ if (ary && n < sz) ary[n] = rest->to_ulong() & 0xffffffff;
+ n++;
+ rest_i = rest->right_shift(state, Fixnum::from(32));
+ rest = rest_i->fixnum_p() ? Bignum::from(state, rest_i->to_native()) : as<Bignum>(rest_i);
+ }
+
+ return n;
+ }
+
double Bignum::to_double(STATE) {
mp_int *a = mp_val();
diff --git a/vm/builtin/bignum.hpp b/vm/builtin/bignum.hpp
index 9732661..6120ff3 100644
--- a/vm/builtin/bignum.hpp
+++ b/vm/builtin/bignum.hpp
@@ -43,6 +43,9 @@ namespace rubinius {
static Integer* from_string_detect(STATE, const char* str);
static Integer* from_string(STATE, const char* str, size_t radix);
static Integer* from_double(STATE, double d);
+ static Integer* from_array(STATE, uint32_t *ary, size_t sz);
+
+ Integer* abs(STATE);
// Ruby.primitive :bignum_new
static Bignum* create(STATE, Fixnum* f);
@@ -185,6 +188,8 @@ namespace rubinius {
// in +buf+ of size +sz+. This will always NUL-terminate +buf+.
void into_string(STATE, size_t radix, char* buf, size_t sz);
+ size_t into_array(STATE, uint32_t *ary, size_t sz);
+
double to_double(STATE);
// Ruby.primitive :bignum_size
diff --git a/vm/builtin/randomizer.cpp b/vm/builtin/randomizer.cpp
new file mode 100644
index 0000000..afd0336
--- /dev/null
+++ b/vm/builtin/randomizer.cpp
@@ -0,0 +1,358 @@
+#include "builtin/randomizer.hpp"
+#include "ffi.hpp"
+#include "vm.hpp"
+#include "objectmemory.hpp"
+#include "builtin/array.hpp"
+#include "builtin/bignum.hpp"
+#include "builtin/class.hpp"
+#include "builtin/exception.hpp"
+#include "builtin/fixnum.hpp"
+#include "builtin/float.hpp"
+#include "builtin/integer.hpp"
+#include "builtin/memorypointer.hpp"
+#include "builtin/string.hpp"
+#include "builtin/tuple.hpp"
+
+#include "object_utils.hpp"
+
+#include <time.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+/*
+
+This is based on random.c from Ruby 1.8.7, which carries the following notice:
+
+This is based on trimmed version of MT19937. To get the original version,
+contact <http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html>.
+
+The original copyright notice follows.
+
+ A C-program for MT19937, with initialization improved 2002/2/10.
+ Coded by Takuji Nishimura and Makoto Matsumoto.
+ This is a faster version by taking Shawn Cokus's optimization,
+ Matthe Bellew's simplification, Isaku Wada's real version.
+
+ Before using, initialize the rng_state by using init_genrand(seed)
+ or init_by_array(init_key, key_length).
+
+ Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. The names of its contributors may not be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+ Any feedback is very welcome.
+ http://www.math.keio.ac.jp/matumoto/emt.html
+ email: matumoto@math.keio.ac.jp
+*/
+
+/* Period parameters */
+#define N 624
+#define M 397
+#define MATRIX_A 0x9908b0dfUL /* constant vector a */
+#define UMASK 0x80000000UL /* most significant w-r bits */
+#define LMASK 0x7fffffffUL /* least significant r bits */
+#define MIXBITS(u,v) ( ((u) & UMASK) | ((v) & LMASK) )
+#define TWIST(u,v) ((MIXBITS(u,v) >> 1) ^ ((v)&1UL ? MATRIX_A : 0UL))
+
+
+template <typename T>
+static T make_mask(T x) {
+ for (unsigned int i = 1; i < sizeof(T) * 8; i *= 2)
+ x = x | x >> i;
+ return x;
+}
+
+namespace rubinius {
+ uint32_t *Randomizer::rng_data() {
+ return (uint32_t*)rng_state()->raw_bytes();
+ }
+
+ /* initializes rng_state[N] with a seed */
+ void Randomizer::init_genrand(uint32_t s) {
+ uint32_t *rng_state = rng_data();
+
+ int j;
+ rng_state[0] = s;
+ for (j=1; j<N; j++) {
+ rng_state[j] = (1812433253UL * (rng_state[j-1] ^ (rng_state[j-1] >> 30)) + j);
+ /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
+ /* In the previous versions, MSBs of the seed affect */
+ /* only MSBs of the array rng_state[]. */
+ /* 2002/01/09 modified by Makoto Matsumoto */
+ }
+ left = 1;
+ }
+
+ /* initialize by an array with array-length */
+ /* init_key is the array for initializing keys */
+ /* key_length is its length */
+ /* slight change for C++, 2004/2/26 */
+ void Randomizer::init_by_array(uint32_t init_key[], int key_length) {
+ init_genrand(19650218UL);
+
+ uint32_t *rng_state = rng_data();
+
+ int i, j, k;
+ i=1; j=0;
+ k = (N>key_length ? N : key_length);
+ for (; k; k--) {
+ rng_state[i] = (rng_state[i] ^ ((rng_state[i-1] ^ (rng_state[i-1] >> 30)) * 1664525UL))
+ + init_key[j] + j; /* non linear */
+ i++; j++;
+ if (i>=N) { rng_state[0] = rng_state[N-1]; i=1; }
+ if (j>=key_length) j=0;
+ }
+ for (k=N-1; k; k--) {
+ rng_state[i] = (rng_state[i] ^ ((rng_state[i-1] ^ (rng_state[i-1] >> 30)) * 1566083941UL))
+ - i; /* non linear */
+ i++;
+ if (i>=N) { rng_state[0] = rng_state[N-1]; i=1; }
+ }
+
+ rng_state[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */
+ left = 1;
+ }
+
+ void Randomizer::next_state() {
+ uint32_t *rng_state = rng_data();
+
+ left = N;
+ next = 0;
+
+ uint32_t *p=rng_state;
+
+ int j;
+ for (j=N-M+1; --j; p++)
+ *p = p[M] ^ TWIST(p[0], p[1]);
+
+ for (j=M; --j; p++)
+ *p = p[M-N] ^ TWIST(p[0], p[1]);
+
+ *p = p[M-N] ^ TWIST(p[0], rng_state[0]);
+ }
+
+ /* generates a random number on [0,0xffffffff]-interval */
+ uint32_t Randomizer::rb_genrand_int32() {
+ if (--left == 0) next_state();
+ uint32_t *rng_state = rng_data();
+
+ uint32_t y;
+ y = rng_state[next++];
+
+ /* Tempering */
+ y ^= (y >> 11);
+ y ^= (y << 7) & 0x9d2c5680UL;
+ y ^= (y << 15) & 0xefc60000UL;
+ y ^= (y >> 18);
+
+ return y;
+ }
+
+ uintptr_t Randomizer::limited_rand(uintptr_t limit) {
+ uintptr_t mask = make_mask(limit);
+ int i;
+ uintptr_t val;
+
+ retry:
+ val = 0;
+ for (i = sizeof(uintptr_t)/4-1; 0 <= i; i--) {
+ if (mask >> (i * 32)) {
+ val |= rb_genrand_int32() << (i * 32);
+ val &= mask;
+ if (limit < val)
+ goto retry;
+ }
+ }
+ return val;
+ }
+
+ /* generates a random number on [0,1) with 53-bit resolution*/
+ double Randomizer::rb_genrand_real() {
+ uint32_t a=rb_genrand_int32()>>5, b=rb_genrand_int32()>>6;
+ return(a*67108864.0+b)*(1.0/9007199254740992.0);
+ }
+ /* These real versions are due to Isaku Wada, 2002/01/09 added */
+
+
+
+
+ void Randomizer::init(STATE) {
+ GO(randomizer).set(state->new_class("Randomizer", G(object)));
+ G(randomizer)->set_object_type(state, RandomizerType);
+ }
+
+ Randomizer* Randomizer::create(STATE) {
+ Randomizer* r = state->new_object<Randomizer>(G(randomizer));
+ r->rng_state(state, ByteArray::create(state, N * sizeof(uint32_t)));
+
+ return r;
+ }
+
+ Randomizer* Randomizer::allocate(STATE, Object* self) {
+ Randomizer* randomizer = create(state);
+
+ if(Class* cls = try_as<Class>(self)) {
+ randomizer->klass(state, cls);
+ }
+
+ randomizer->init_genrand(5489UL);
+
+ return randomizer;
+ }
+
+ Integer* Randomizer::gen_seed(STATE) {
+ static int n = 0;
+
+ uint32_t seed[] = { 0, 0, 0, 0 };
+
+#ifdef S_ISCHR
+ int fd;
+ if ((fd = open("/dev/urandom", O_RDONLY
+#ifdef O_NONBLOCK
+ |O_NONBLOCK
+#endif
+#ifdef O_NOCTTY
+ |O_NOCTTY
+#endif
+#ifdef O_NOFOLLOW
+ |O_NOFOLLOW
+#endif
+ )) >= 0) {
+ struct stat statbuf;
+ if (fstat(fd, &statbuf) == 0 && S_ISCHR(statbuf.st_mode)) {
+ /* If this fails, we're no worse off than if it hadn't opened to
+ * begin with */
+ int ignored;
+ ignored = read(fd, seed, 4 * sizeof(uint32_t));
+ }
+ close(fd);
+ }
+#endif
+
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+ seed[0] ^= tv.tv_usec;
+ seed[1] ^= tv.tv_sec;
+ seed[2] ^= getpid() ^ (n++ << 16);
+ seed[3] ^= (uint32_t)&seed;
+
+ return Bignum::from_array(state, seed, 4);
+ }
+
+ Object* Randomizer::seed(STATE, Integer* seed) {
+ Bignum* big;
+
+ size_t longs;
+ uint32_t* data;
+
+ if (!seed->fixnum_p())
+ seed = as<Bignum>(seed)->abs(state);
+
+ if (seed->fixnum_p()) {
+ uintptr_t s = seed->to_native();
+
+ // Remove the sign bit, for no good reason... but that's what MRI
+ // does.
+ s &= ~(1 << (sizeof(uintptr_t) * 8 - 1));
+
+ if (s <= 0xffffffffUL) {
+ init_genrand((uint32_t)s);
+ return Qnil;
+ }
+
+ longs = sizeof(uintptr_t) / 4;
+ data = (uint32_t*)alloca(longs * 4);
+ for (unsigned int i = 0; i < longs; i++)
+ data[i] = (uint32_t)(s >> (i * 32));
+ } else {
+ big = as<Bignum>(seed);
+
+ longs = big->into_array(state, NULL, 0);
+
+ data = (uint32_t*)alloca(longs * 4);
+ size_t output_count = big->into_array(state, data, longs);
+ assert(longs >= output_count);
+ }
+
+ init_by_array(data, longs);
+
+ return Qnil;
+ }
+
+ Integer* Randomizer::rand_int(STATE, Integer* max) {
+ if (max->fixnum_p()) {
+ native_int max_i = max->to_native();
+ uintptr_t result = limited_rand((uintptr_t)(max_i));
+ return Integer::from(state, result);
+ }
+
+ Bignum* max_big = as<Bignum>(max);
+ size_t longs = max_big->into_array(state, NULL, 0);
+
+ uint32_t* max_data = (uint32_t*)alloca(longs * 4);
+ size_t output_count = max_big->into_array(state, max_data, longs);
+ assert(longs >= output_count);
+
+ uint32_t* result_data = (uint32_t*)alloca(longs * 4);
+
+ retry:
+ uint32_t mask = 0;
+ int i, boundary = 1;
+
+ for (i = longs - 1; i >= 0; i--) {
+ uint32_t rnd;
+ uint32_t lim = max_data[i];
+ mask = mask ? 0xffffffff : make_mask(lim);
+ if (mask) {
+ rnd = rb_genrand_int32() & mask;
+ if (boundary) {
+ if (lim < rnd)
+ goto retry;
+ if (rnd < lim)
+ boundary = 0;
+ }
+ } else {
+ rnd = 0;
+ }
+ result_data[i] = rnd;
+ }
+
+ Integer* result = Bignum::from_array(state, result_data, longs);
+
+ return result;
+ }
+
+ Float* Randomizer::rand_float(STATE) {
+ return Float::create(state, rb_genrand_real());
+ }
+}
+
diff --git a/vm/builtin/randomizer.hpp b/vm/builtin/randomizer.hpp
new file mode 100644
index 0000000..0aa2dae
--- /dev/null
+++ b/vm/builtin/randomizer.hpp
@@ -0,0 +1,65 @@
+#ifndef RBX_BUILTIN_RANDOMIZER_HPP
+#define RBX_BUILTIN_RANDOMIZER_HPP
+
+#include "builtin/object.hpp"
+#include "builtin/bignum.hpp"
+#include "builtin/bytearray.hpp"
+#include "builtin/integer.hpp"
+#include "type_info.hpp"
+
+namespace rubinius {
+ class ByteArray;
+ class Integer;
+
+ class Randomizer : public Object {
+ public:
+ const static object_type type = RandomizerType;
+
+ private:
+ int next;
+ int left;
+ ByteArray *rng_state_; // slot
+
+ uint32_t* rng_data();
+
+ void init_genrand(uint32_t s);
+ void init_by_array(uint32_t init_key[], int key_length);
+ void next_state();
+ uint32_t rb_genrand_int32();
+ uintptr_t limited_rand(uintptr_t limit);
+ double rb_genrand_real();
+
+ public:
+
+ attr_accessor(rng_state, ByteArray);
+
+ /* interface */
+
+ static void init(STATE);
+
+
+ static Randomizer* create(STATE);
+
+ // Ruby.primitive :randomizer_allocate
+ static Randomizer* allocate(STATE, Object* self);
+
+ // Ruby.primitive :randomizer_gen_seed
+ Integer* gen_seed(STATE);
+
+ // Ruby.primitive :randomizer_seed
+ Object* seed(STATE, Integer* seed);
+
+ // Ruby.primitive :randomizer_rand_int
+ Integer* rand_int(STATE, Integer* max);
+
+ // Ruby.primitive :randomizer_rand_float
+ Float* rand_float(STATE);
+
+ class Info : public TypeInfo {
+ public:
+ BASIC_TYPEINFO(TypeInfo)
+ };
+ };
+};
+
+#endif
diff --git a/vm/globals.hpp b/vm/globals.hpp
index 6b6eb47..ba87176 100644
--- a/vm/globals.hpp
+++ b/vm/globals.hpp
@@ -93,6 +93,7 @@ namespace rubinius {
TypedRoot<Class*> numeric;
TypedRoot<Class*> memory_pointer;
TypedRoot<Class*> taskprobe;
+ TypedRoot<Class*> randomizer;
TypedRoot<Class*> nmethod; /**< NativeMethod */
@@ -209,6 +210,7 @@ namespace rubinius {
numeric(&roots),
memory_pointer(&roots),
taskprobe(&roots),
+ randomizer(&roots),
nmethod(&roots),
data(&roots),
--
1.7.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment