Project

General

Profile

Feature #2673 ยป enum_len.patch

wanabe (_ wanabe), 03/14/2010 01:05 PM

View differences:

array.c (working copy)
1408 1408
{
1409 1409
    long i;
1410 1410

  
1411
    RETURN_ENUMERATOR(ary, 0, 0);
1411
    RETURN_ENUMERATOR_WITH_LEN(ary, 0, 0, ary);
1412 1412
    for (i=0; i<RARRAY_LEN(ary); i++) {
1413 1413
	rb_yield(RARRAY_PTR(ary)[i]);
1414 1414
    }
......
3888 3888
    }
3889 3889
}
3890 3890

  
3891
static inline long
3892
permu_len(long n, long r)
3893
{
3894
    int i;
3895
    long nlen = 0;
3896
    if (0 <= r && r <= n) {
3897
	nlen = 1;
3898
	for (i = 0; i < r; ++i)
3899
	  nlen *= n - i;
3900
    }
3901
    return nlen;
3902
}
3903

  
3891 3904
/*
3892 3905
 *  call-seq:
3893 3906
 *     ary.permutation { |p| block }          -> array
......
3921 3934
    long r, n, i;
3922 3935

  
3923 3936
    n = RARRAY_LEN(ary);                  /* Array length */
3924
    RETURN_ENUMERATOR(ary, argc, argv);   /* Return enumerator if no block */
3925 3937
    rb_scan_args(argc, argv, "01", &num);
3926 3938
    r = NIL_P(num) ? n : NUM2LONG(num);   /* Permutation size from argument */
3939
    RETURN_ENUMERATOR_WITH_LEN(ary, argc, argv, INT2NUM(permu_len(n, r)));
3927 3940

  
3928 3941
    if (r < 0 || n < r) {
3929 3942
	/* no permutations: yield nothing */
......
4004 4017
    long n, i, len;
4005 4018

  
4006 4019
    n = NUM2LONG(num);
4007
    RETURN_ENUMERATOR(ary, 1, &num);
4008 4020
    len = RARRAY_LEN(ary);
4021
    RETURN_ENUMERATOR_WITH_LEN(ary, 1, &num, INT2NUM(combi_len(len, n)));
4009 4022
    if (n < 0 || len < n) {
4010 4023
	/* yield nothing */
4011 4024
    }
enumerator.c (working copy)
302 302
    return enumerator_init(enumerator_allocate(rb_cEnumerator), obj, meth, argc, argv);
303 303
}
304 304

  
305
VALUE
306
rb_enumerator_set_length(VALUE self, VALUE length)
307
{
308
    rb_ivar_set(self, rb_intern("length"), length);
309
    return self;
310
}
311

  
312
static VALUE
313
enumerator_length(VALUE self)
314
{
315
    VALUE len = rb_attr_get(self, rb_intern("length"));
316
    switch (TYPE(len)) {
317
      case T_ARRAY:
318
        return INT2NUM(RARRAY_LEN(len));
319
      case T_STRING:
320
        return INT2NUM(RSTRING_LEN(len));
321
    }
322
    return len;
323
}
324

  
305 325
static VALUE
306 326
enumerator_block_call(VALUE obj, rb_block_call_func *func, VALUE arg)
307 327
{
......
1070 1090
    rb_define_method(rb_cEnumerator, "feed", enumerator_feed, 1);
1071 1091
    rb_define_method(rb_cEnumerator, "rewind", enumerator_rewind, 0);
1072 1092
    rb_define_method(rb_cEnumerator, "inspect", enumerator_inspect, 0);
1093
    rb_define_method(rb_cEnumerator, "length", enumerator_length, 0);
1073 1094

  
1074 1095
    rb_eStopIteration = rb_define_class("StopIteration", rb_eIndexError);
1075 1096
    rb_define_method(rb_eStopIteration, "result", stop_result, 0);
include/ruby/intern.h (working copy)
185 185
/* enum.c */
186 186
/* enumerator.c */
187 187
VALUE rb_enumeratorize(VALUE, VALUE, int, VALUE *);
188
VALUE rb_enumerator_set_length(VALUE, VALUE);
188 189
#define RETURN_ENUMERATOR(obj, argc, argv) do {				\
189 190
	if (!rb_block_given_p())					\
190 191
	    return rb_enumeratorize(obj, ID2SYM(rb_frame_this_func()),	\
191 192
				    argc, argv);			\
192 193
    } while (0)
194
#define RETURN_ENUMERATOR_WITH_LEN(obj, argc, argv, len) do {		\
195
    if (!rb_block_given_p()) {						\
196
	VALUE _e = rb_enumeratorize(obj, ID2SYM(rb_frame_this_func()),	\
197
				    argc, argv);			\
198
	return rb_enumerator_set_length(_e, len);			\
199
    }									\
200
} while (0)
193 201
/* error.c */
194 202
VALUE rb_exc_new(VALUE, const char*, long);
195 203
VALUE rb_exc_new2(VALUE, const char*);
test/ruby/test_array.rb (working copy)
1370 1370
    assert_equal(@cls[], @cls[1,2,3,4].combination(5).to_a)
1371 1371
  end
1372 1372

  
1373
  def test_combination_length
1374
    assert_equal(6, @cls[1,2,3,4].combination(2).length)
1375
    assert_equal(4, @cls[1,2,3,4].combination(3).length)
1376
  end
1377

  
1373 1378
  def test_product
1374 1379
    assert_equal(@cls[[1,4],[1,5],[2,4],[2,5],[3,4],[3,5]],
1375 1380
                 @cls[1,2,3].product([4,5]))
......
1403 1408
    assert_equal(@cls[1, 2, 3, 4].permutation.to_a, b)
1404 1409
  end
1405 1410

  
1411
  def test_permutation_length
1412
    assert_equal(6, @cls[1, 2, 3].permutation.length)
1413
    assert_equal(1, @cls[1, 2, 3].permutation(0).length)
1414
    assert_equal(3, @cls[1, 2, 3].permutation(1).length)
1415
    assert_equal(6, @cls[1, 2, 3].permutation(3).length)
1416
    assert_equal(0, @cls[1, 2, 3].permutation(4).length)
1417
    assert_equal(24, @cls[1, 2, 3, 4].permutation(3).length)
1418
  end
1419

  
1406 1420
  def test_take
1407 1421
    assert_equal([1,2,3], [1,2,3,4,5,0].take(3))
1408 1422
    assert_raise(ArgumentError, '[ruby-dev:34123]') { [1,2].take(-1) }