mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	* array.c (rb_ary_shuffle_bang, rb_ary_sample): add optional
argument random.  [ruby-dev:41923] [EXPERIMENTAL]
* random.c (rb_random_{int32,real,bytes}): fallback to normal
  method invocation.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@29083 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
			
			
This commit is contained in:
		
							parent
							
								
									89339af9c1
								
							
						
					
					
						commit
						2f6c0e3be3
					
				
					 5 changed files with 88 additions and 18 deletions
				
			
		| 
						 | 
				
			
			@ -1,3 +1,11 @@
 | 
			
		|||
Tue Aug 24 07:07:28 2010  Nobuyoshi Nakada  <nobu@ruby-lang.org>
 | 
			
		||||
 | 
			
		||||
	* array.c (rb_ary_shuffle_bang, rb_ary_sample): add optional
 | 
			
		||||
	  argument random.  [ruby-dev:41923] [EXPERIMENTAL]
 | 
			
		||||
 | 
			
		||||
	* random.c (rb_random_{int32,real,bytes}): fallback to normal
 | 
			
		||||
	  method invocation.
 | 
			
		||||
 | 
			
		||||
Tue Aug 24 06:08:10 2010  Nobuyoshi Nakada  <nobu@ruby-lang.org>
 | 
			
		||||
 | 
			
		||||
	* include/ruby/version.h (RUBY_API_VERSION_*): renamed and moved
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										45
									
								
								array.c
									
										
									
									
									
								
							
							
						
						
									
										45
									
								
								array.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -3730,22 +3730,30 @@ rb_ary_flatten(int argc, VALUE *argv, VALUE ary)
 | 
			
		|||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define RAND_UPTO(max) (long)(rb_genrand_real()*(max))
 | 
			
		||||
#define OPTHASH_GIVEN_P(opts) \
 | 
			
		||||
    (argc > 0 && !NIL_P(opts = rb_check_hash_type(argv[argc-1])) && (--argc, 1))
 | 
			
		||||
static VALUE sym_random;
 | 
			
		||||
 | 
			
		||||
#define RAND_UPTO(max) (long)(rb_random_real(randgen)*(max))
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  call-seq:
 | 
			
		||||
 *     ary.shuffle!        -> ary
 | 
			
		||||
 *     ary.shuffle!              -> ary
 | 
			
		||||
 *     ary.shuffle!(random: rng) -> ary
 | 
			
		||||
 *
 | 
			
		||||
 *  Shuffles elements in +self+ in place.
 | 
			
		||||
 *  If +rng+ is given, it will be used as the random number generator.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static VALUE
 | 
			
		||||
rb_ary_shuffle_bang(VALUE ary)
 | 
			
		||||
rb_ary_shuffle_bang(int argc, VALUE *argv, VALUE ary)
 | 
			
		||||
{
 | 
			
		||||
    VALUE *ptr;
 | 
			
		||||
    VALUE *ptr, opts, randgen = Qnil;
 | 
			
		||||
    long i = RARRAY_LEN(ary);
 | 
			
		||||
 | 
			
		||||
    if (OPTHASH_GIVEN_P(opts)) {
 | 
			
		||||
	randgen = rb_hash_lookup2(opts, sym_random, randgen);
 | 
			
		||||
    }
 | 
			
		||||
    rb_ary_modify(ary);
 | 
			
		||||
    ptr = RARRAY_PTR(ary);
 | 
			
		||||
    while (i) {
 | 
			
		||||
| 
						 | 
				
			
			@ -3760,27 +3768,34 @@ rb_ary_shuffle_bang(VALUE ary)
 | 
			
		|||
 | 
			
		||||
/*
 | 
			
		||||
 *  call-seq:
 | 
			
		||||
 *     ary.shuffle -> new_ary
 | 
			
		||||
 *     ary.shuffle              -> new_ary
 | 
			
		||||
 *     ary.shuffle(random: rng) -> new_ary
 | 
			
		||||
 *
 | 
			
		||||
 *  Returns a new array with elements of this array shuffled.
 | 
			
		||||
 *
 | 
			
		||||
 *     a = [ 1, 2, 3 ]           #=> [1, 2, 3]
 | 
			
		||||
 *     a.shuffle                 #=> [2, 3, 1]
 | 
			
		||||
 *
 | 
			
		||||
 *  If +rng+ is given, it will be used as the random number generator.
 | 
			
		||||
 *
 | 
			
		||||
 *     a.shuffle(Random.new(1))  #=> [1, 3, 2]
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static VALUE
 | 
			
		||||
rb_ary_shuffle(VALUE ary)
 | 
			
		||||
rb_ary_shuffle(int argc, VALUE *argv, VALUE ary)
 | 
			
		||||
{
 | 
			
		||||
    ary = rb_ary_dup(ary);
 | 
			
		||||
    rb_ary_shuffle_bang(ary);
 | 
			
		||||
    rb_ary_shuffle_bang(argc, argv, ary);
 | 
			
		||||
    return ary;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  call-seq:
 | 
			
		||||
 *     ary.sample        -> obj
 | 
			
		||||
 *     ary.sample(n)     -> new_ary
 | 
			
		||||
 *     ary.sample                  -> obj
 | 
			
		||||
 *     ary.sample(random: rng)     -> obj
 | 
			
		||||
 *     ary.sample(n)               -> new_ary
 | 
			
		||||
 *     ary.sample(n, random: rng)  -> new_ary
 | 
			
		||||
 *
 | 
			
		||||
 *  Choose a random element or +n+ random elements from the array. The elements
 | 
			
		||||
 *  are chosen by using random and unique indices into the array in order to
 | 
			
		||||
| 
						 | 
				
			
			@ -3788,6 +3803,7 @@ rb_ary_shuffle(VALUE ary)
 | 
			
		|||
 *  contained duplicate elements. If the array is empty the first form returns
 | 
			
		||||
 *  <code>nil</code> and the second form returns an empty array.
 | 
			
		||||
 *
 | 
			
		||||
 *  If +rng+ is given, it will be used as the random number generator.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3795,9 +3811,13 @@ static VALUE
 | 
			
		|||
rb_ary_sample(int argc, VALUE *argv, VALUE ary)
 | 
			
		||||
{
 | 
			
		||||
    VALUE nv, result, *ptr;
 | 
			
		||||
    VALUE opts, randgen = Qnil;
 | 
			
		||||
    long n, len, i, j, k, idx[10];
 | 
			
		||||
 | 
			
		||||
    len = RARRAY_LEN(ary);
 | 
			
		||||
    if (OPTHASH_GIVEN_P(opts)) {
 | 
			
		||||
	randgen = rb_hash_lookup2(opts, sym_random, randgen);
 | 
			
		||||
    }
 | 
			
		||||
    if (argc == 0) {
 | 
			
		||||
	if (len == 0) return Qnil;
 | 
			
		||||
	i = len == 1 ? 0 : RAND_UPTO(len);
 | 
			
		||||
| 
						 | 
				
			
			@ -4595,8 +4615,8 @@ Init_Array(void)
 | 
			
		|||
    rb_define_method(rb_cArray, "flatten", rb_ary_flatten, -1);
 | 
			
		||||
    rb_define_method(rb_cArray, "flatten!", rb_ary_flatten_bang, -1);
 | 
			
		||||
    rb_define_method(rb_cArray, "count", rb_ary_count, -1);
 | 
			
		||||
    rb_define_method(rb_cArray, "shuffle!", rb_ary_shuffle_bang, 0);
 | 
			
		||||
    rb_define_method(rb_cArray, "shuffle", rb_ary_shuffle, 0);
 | 
			
		||||
    rb_define_method(rb_cArray, "shuffle!", rb_ary_shuffle_bang, -1);
 | 
			
		||||
    rb_define_method(rb_cArray, "shuffle", rb_ary_shuffle, -1);
 | 
			
		||||
    rb_define_method(rb_cArray, "sample", rb_ary_sample, -1);
 | 
			
		||||
    rb_define_method(rb_cArray, "cycle", rb_ary_cycle, -1);
 | 
			
		||||
    rb_define_method(rb_cArray, "permutation", rb_ary_permutation, -1);
 | 
			
		||||
| 
						 | 
				
			
			@ -4611,4 +4631,5 @@ Init_Array(void)
 | 
			
		|||
    rb_define_method(rb_cArray, "drop_while", rb_ary_drop_while, 0);
 | 
			
		||||
 | 
			
		||||
    id_cmp = rb_intern("<=>");
 | 
			
		||||
    sym_random = ID2SYM(rb_intern("random"));
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										35
									
								
								random.c
									
										
									
									
									
								
							
							
						
						
									
										35
									
								
								random.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -321,6 +321,7 @@ int_pair_to_real_inclusive(unsigned int a, unsigned int b)
 | 
			
		|||
VALUE rb_cRandom;
 | 
			
		||||
#define id_minus '-'
 | 
			
		||||
#define id_plus  '+'
 | 
			
		||||
static ID id_rand, id_bytes;
 | 
			
		||||
 | 
			
		||||
/* :nodoc: */
 | 
			
		||||
static void
 | 
			
		||||
| 
						 | 
				
			
			@ -359,6 +360,13 @@ get_rnd(VALUE obj)
 | 
			
		|||
    return ptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static rb_random_t *
 | 
			
		||||
try_get_rnd(VALUE obj)
 | 
			
		||||
{
 | 
			
		||||
    if (!rb_typeddata_is_kind_of(obj, &random_data_type)) return NULL;
 | 
			
		||||
    return DATA_PTR(obj);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* :nodoc: */
 | 
			
		||||
static VALUE
 | 
			
		||||
random_alloc(VALUE klass)
 | 
			
		||||
| 
						 | 
				
			
			@ -869,14 +877,22 @@ rb_rand_internal(unsigned long i)
 | 
			
		|||
unsigned int
 | 
			
		||||
rb_random_int32(VALUE obj)
 | 
			
		||||
{
 | 
			
		||||
    rb_random_t *rnd = get_rnd(obj);
 | 
			
		||||
    rb_random_t *rnd = try_get_rnd(obj);
 | 
			
		||||
    if (!rnd) {
 | 
			
		||||
	VALUE lim = ULONG2NUM(0xffffffff);
 | 
			
		||||
	return NUM2ULONG(rb_funcall2(obj, id_rand, 1, &lim));
 | 
			
		||||
    }
 | 
			
		||||
    return genrand_int32(&rnd->mt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double
 | 
			
		||||
rb_random_real(VALUE obj)
 | 
			
		||||
{
 | 
			
		||||
    rb_random_t *rnd = get_rnd(obj);
 | 
			
		||||
    rb_random_t *rnd = try_get_rnd(obj);
 | 
			
		||||
    if (!rnd) {
 | 
			
		||||
	VALUE v = rb_funcall2(obj, id_rand, 0, 0);
 | 
			
		||||
	return NUM2DBL(v);
 | 
			
		||||
    }
 | 
			
		||||
    return genrand_real(&rnd->mt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -895,11 +911,17 @@ random_bytes(VALUE obj, VALUE len)
 | 
			
		|||
VALUE
 | 
			
		||||
rb_random_bytes(VALUE obj, long n)
 | 
			
		||||
{
 | 
			
		||||
    rb_random_t *rnd = get_rnd(obj);
 | 
			
		||||
    VALUE bytes = rb_str_new(0, n);
 | 
			
		||||
    char *ptr = RSTRING_PTR(bytes);
 | 
			
		||||
    rb_random_t *rnd = try_get_rnd(obj);
 | 
			
		||||
    VALUE bytes;
 | 
			
		||||
    char *ptr;
 | 
			
		||||
    unsigned int r, i;
 | 
			
		||||
 | 
			
		||||
    if (!rnd) {
 | 
			
		||||
	VALUE len = LONG2NUM(n);
 | 
			
		||||
	return rb_funcall2(obj, id_bytes, 1, &len);
 | 
			
		||||
    }
 | 
			
		||||
    bytes = rb_str_new(0, n);
 | 
			
		||||
    ptr = RSTRING_PTR(bytes);
 | 
			
		||||
    for (; n >= SIZEOF_INT32; n -= SIZEOF_INT32) {
 | 
			
		||||
	r = genrand_int32(&rnd->mt);
 | 
			
		||||
	i = SIZEOF_INT32;
 | 
			
		||||
| 
						 | 
				
			
			@ -1245,4 +1267,7 @@ Init_Random(void)
 | 
			
		|||
    rb_define_singleton_method(rb_cRandom, "new_seed", random_seed, 0);
 | 
			
		||||
    rb_define_private_method(CLASS_OF(rb_cRandom), "state", random_s_state, 0);
 | 
			
		||||
    rb_define_private_method(CLASS_OF(rb_cRandom), "left", random_s_left, 0);
 | 
			
		||||
 | 
			
		||||
    id_rand = rb_intern("rand");
 | 
			
		||||
    id_bytes = rb_intern("bytes");
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1891,6 +1891,12 @@ class TestArray < Test::Unit::TestCase
 | 
			
		|||
    100.times do
 | 
			
		||||
      assert_equal([0, 1, 2], [2, 1, 0].shuffle.sort)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    gen = Random.new(0)
 | 
			
		||||
    srand(0)
 | 
			
		||||
    100.times do
 | 
			
		||||
      assert_equal([0, 1, 2].shuffle, [0, 1, 2].shuffle(random: gen))
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_sample
 | 
			
		||||
| 
						 | 
				
			
			@ -1907,7 +1913,7 @@ class TestArray < Test::Unit::TestCase
 | 
			
		|||
    (0..20).each do |n|
 | 
			
		||||
      100.times do
 | 
			
		||||
        b = a.sample(n)
 | 
			
		||||
        assert_equal([n, 18].min, b.uniq.size)
 | 
			
		||||
        assert_equal([n, 18].min, b.size)
 | 
			
		||||
        assert_equal(a, (a | b).sort)
 | 
			
		||||
        assert_equal(b.sort, (a & b).sort)
 | 
			
		||||
      end
 | 
			
		||||
| 
						 | 
				
			
			@ -1920,6 +1926,15 @@ class TestArray < Test::Unit::TestCase
 | 
			
		|||
    end
 | 
			
		||||
 | 
			
		||||
    assert_raise(ArgumentError, '[ruby-core:23374]') {[1, 2].sample(-1)}
 | 
			
		||||
 | 
			
		||||
    gen = Random.new(0)
 | 
			
		||||
    srand(0)
 | 
			
		||||
    a = (1..18).to_a
 | 
			
		||||
    (0..20).each do |n|
 | 
			
		||||
      100.times do |i|
 | 
			
		||||
        assert_equal(a.sample(n), a.sample(n, random: gen), "#{i}/#{n}")
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_cycle
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -171,6 +171,7 @@ class TestRand < Test::Unit::TestCase
 | 
			
		|||
  def test_shuffle
 | 
			
		||||
    srand(0)
 | 
			
		||||
    assert_equal([1,4,2,5,3], [1,2,3,4,5].shuffle)
 | 
			
		||||
    assert_equal([1,4,2,5,3], [1,2,3,4,5].shuffle(random: Random.new(0)))
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_big_seed
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue