Project

General

Profile

Feature #2673 » enum_len.patch

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

View differences:

array.c (working copy)
{
long i;
RETURN_ENUMERATOR(ary, 0, 0);
RETURN_ENUMERATOR_WITH_LEN(ary, 0, 0, ary);
for (i=0; i<RARRAY_LEN(ary); i++) {
rb_yield(RARRAY_PTR(ary)[i]);
}
......
}
}
static inline long
permu_len(long n, long r)
{
int i;
long nlen = 0;
if (0 <= r && r <= n) {
nlen = 1;
for (i = 0; i < r; ++i)
nlen *= n - i;
}
return nlen;
}
/*
* call-seq:
* ary.permutation { |p| block } -> array
......
long r, n, i;
n = RARRAY_LEN(ary); /* Array length */
RETURN_ENUMERATOR(ary, argc, argv); /* Return enumerator if no block */
rb_scan_args(argc, argv, "01", &num);
r = NIL_P(num) ? n : NUM2LONG(num); /* Permutation size from argument */
RETURN_ENUMERATOR_WITH_LEN(ary, argc, argv, INT2NUM(permu_len(n, r)));
if (r < 0 || n < r) {
/* no permutations: yield nothing */
......
long n, i, len;
n = NUM2LONG(num);
RETURN_ENUMERATOR(ary, 1, &num);
len = RARRAY_LEN(ary);
RETURN_ENUMERATOR_WITH_LEN(ary, 1, &num, INT2NUM(combi_len(len, n)));
if (n < 0 || len < n) {
/* yield nothing */
}
enumerator.c (working copy)
return enumerator_init(enumerator_allocate(rb_cEnumerator), obj, meth, argc, argv);
}
VALUE
rb_enumerator_set_length(VALUE self, VALUE length)
{
rb_ivar_set(self, rb_intern("length"), length);
return self;
}
static VALUE
enumerator_length(VALUE self)
{
VALUE len = rb_attr_get(self, rb_intern("length"));
switch (TYPE(len)) {
case T_ARRAY:
return INT2NUM(RARRAY_LEN(len));
case T_STRING:
return INT2NUM(RSTRING_LEN(len));
}
return len;
}
static VALUE
enumerator_block_call(VALUE obj, rb_block_call_func *func, VALUE arg)
{
......
rb_define_method(rb_cEnumerator, "feed", enumerator_feed, 1);
rb_define_method(rb_cEnumerator, "rewind", enumerator_rewind, 0);
rb_define_method(rb_cEnumerator, "inspect", enumerator_inspect, 0);
rb_define_method(rb_cEnumerator, "length", enumerator_length, 0);
rb_eStopIteration = rb_define_class("StopIteration", rb_eIndexError);
rb_define_method(rb_eStopIteration, "result", stop_result, 0);
include/ruby/intern.h (working copy)
/* enum.c */
/* enumerator.c */
VALUE rb_enumeratorize(VALUE, VALUE, int, VALUE *);
VALUE rb_enumerator_set_length(VALUE, VALUE);
#define RETURN_ENUMERATOR(obj, argc, argv) do { \
if (!rb_block_given_p()) \
return rb_enumeratorize(obj, ID2SYM(rb_frame_this_func()), \
argc, argv); \
} while (0)
#define RETURN_ENUMERATOR_WITH_LEN(obj, argc, argv, len) do { \
if (!rb_block_given_p()) { \
VALUE _e = rb_enumeratorize(obj, ID2SYM(rb_frame_this_func()), \
argc, argv); \
return rb_enumerator_set_length(_e, len); \
} \
} while (0)
/* error.c */
VALUE rb_exc_new(VALUE, const char*, long);
VALUE rb_exc_new2(VALUE, const char*);
test/ruby/test_array.rb (working copy)
assert_equal(@cls[], @cls[1,2,3,4].combination(5).to_a)
end
def test_combination_length
assert_equal(6, @cls[1,2,3,4].combination(2).length)
assert_equal(4, @cls[1,2,3,4].combination(3).length)
end
def test_product
assert_equal(@cls[[1,4],[1,5],[2,4],[2,5],[3,4],[3,5]],
@cls[1,2,3].product([4,5]))
......
assert_equal(@cls[1, 2, 3, 4].permutation.to_a, b)
end
def test_permutation_length
assert_equal(6, @cls[1, 2, 3].permutation.length)
assert_equal(1, @cls[1, 2, 3].permutation(0).length)
assert_equal(3, @cls[1, 2, 3].permutation(1).length)
assert_equal(6, @cls[1, 2, 3].permutation(3).length)
assert_equal(0, @cls[1, 2, 3].permutation(4).length)
assert_equal(24, @cls[1, 2, 3, 4].permutation(3).length)
end
def test_take
assert_equal([1,2,3], [1,2,3,4,5,0].take(3))
assert_raise(ArgumentError, '[ruby-dev:34123]') { [1,2].take(-1) }
(2-2/2)