enum_len.patch
| 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) }
|