diff options
author | usa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2014-08-31 06:56:43 +0000 |
---|---|---|
committer | usa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2014-08-31 06:56:43 +0000 |
commit | bea02d1b35a389cd70f349183776cc96be29abc2 (patch) | |
tree | 2fa90f5fe46677be6549c27882c4dbee4de8a354 /array.c | |
parent | 1abe5c8d41f66ddc2419b361200d06c8b0d7a31e (diff) |
merge revision(s) 46417,46418: [Backport #9939]
* array.c (yield_indexed_values): extract from permute0(),
rpermute0(), and rcombinate0().
* array.c (rb_ary_combination): iterate on a shared copy, and use
array of indexes instead of array of chosen objects.
[ruby-core:63149] [Bug #9939]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_0_0@47332 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'array.c')
-rw-r--r-- | array.c | 77 |
1 files changed, 33 insertions, 44 deletions
@@ -4529,6 +4529,25 @@ rb_ary_cycle(int argc, VALUE *argv, VALUE ary) #define tmpary_discard(a) (ary_discard(a), RBASIC(a)->klass = rb_cArray) /* + * Build a ruby array of the corresponding values and yield it to the + * associated block. + * Return the class of +values+ for reentry check. + */ +static int +yield_indexed_values(const VALUE values, const long r, const long *const p) +{ + const VALUE result = rb_ary_new2(r); + VALUE *const result_array = RARRAY_PTR(result); + const VALUE *const values_array = RARRAY_PTR(values); + long i; + + for (i = 0; i < r; i++) result_array[i] = values_array[p[i]]; + ARY_SET_LEN(result, r); + rb_yield(result); + return !RBASIC(values)->klass; +} + +/* * Recursively compute permutations of +r+ elements of the set * <code>[0..n-1]</code>. * @@ -4545,7 +4564,7 @@ rb_ary_cycle(int argc, VALUE *argv, VALUE ary) static void permute0(long n, long r, long *p, long index, char *used, VALUE values) { - long i,j; + long i; for (i = 0; i < n; i++) { if (used[i] == 0) { p[index] = i; @@ -4556,17 +4575,7 @@ permute0(long n, long r, long *p, long index, char *used, VALUE values) used[i] = 0; /* index unused */ } else { - /* We have a complete permutation of array indexes */ - /* Build a ruby array of the corresponding values */ - /* And yield it to the associated block */ - VALUE result = rb_ary_new2(r); - VALUE *result_array = RARRAY_PTR(result); - const VALUE *values_array = RARRAY_PTR(values); - - for (j = 0; j < r; j++) result_array[j] = values_array[p[j]]; - ARY_SET_LEN(result, r); - rb_yield(result); - if (RBASIC(values)->klass) { + if (!yield_indexed_values(values, r, p)) { rb_raise(rb_eRuntimeError, "permute reentered"); } } @@ -4731,21 +4740,19 @@ rb_ary_combination(VALUE ary, VALUE num) } } else { - volatile VALUE t0 = tmpbuf(n+1, sizeof(long)); - long *stack = (long*)RSTRING_PTR(t0); - volatile VALUE cc = tmpary(n); - VALUE *chosen = RARRAY_PTR(cc); + VALUE ary0 = ary_make_shared_copy(ary); /* private defensive copy of ary */ + volatile VALUE t0; + long *stack = ALLOCV_N(long, t0, n+1); long lev = 0; - MEMZERO(stack, long, n); + RBASIC(ary0)->klass = 0; + MEMZERO(stack+1, long, n); stack[0] = -1; for (;;) { - chosen[lev] = RARRAY_PTR(ary)[stack[lev+1]]; for (lev++; lev < n; lev++) { - chosen[lev] = RARRAY_PTR(ary)[stack[lev+1] = stack[lev]+1]; + stack[lev+1] = stack[lev]+1; } - rb_yield(rb_ary_new4(n, chosen)); - if (RBASIC(t0)->klass) { + if (!yield_indexed_values(ary0, n, stack+1)) { rb_raise(rb_eRuntimeError, "combination reentered"); } do { @@ -4754,8 +4761,8 @@ rb_ary_combination(VALUE ary, VALUE num) } while (stack[lev+1]+n == len+lev+1); } done: - tmpbuf_discard(t0); - tmpary_discard(cc); + ALLOCV_END(t0); + RBASIC(ary0)->klass = rb_cArray; } return ary; } @@ -4776,24 +4783,14 @@ rb_ary_combination(VALUE ary, VALUE num) static void rpermute0(long n, long r, long *p, long index, VALUE values) { - long i, j; + long i; for (i = 0; i < n; i++) { p[index] = i; if (index < r-1) { /* if not done yet */ rpermute0(n, r, p, index+1, values); /* recurse */ } else { - /* We have a complete permutation of array indexes */ - /* Build a ruby array of the corresponding values */ - /* And yield it to the associated block */ - VALUE result = rb_ary_new2(r); - VALUE *result_array = RARRAY_PTR(result); - const VALUE *values_array = RARRAY_PTR(values); - - for (j = 0; j < r; j++) result_array[j] = values_array[p[j]]; - ARY_SET_LEN(result, r); - rb_yield(result); - if (RBASIC(values)->klass) { + if (!yield_indexed_values(values, r, p)) { rb_raise(rb_eRuntimeError, "repeated permute reentered"); } } @@ -4872,7 +4869,6 @@ rb_ary_repeated_permutation(VALUE ary, VALUE num) static void rcombinate0(long n, long r, long *p, long index, long rest, VALUE values) { - long j; if (rest > 0) { for (; index < n; ++index) { p[r-rest] = index; @@ -4880,14 +4876,7 @@ rcombinate0(long n, long r, long *p, long index, long rest, VALUE values) } } else { - VALUE result = rb_ary_new2(r); - VALUE *result_array = RARRAY_PTR(result); - const VALUE *values_array = RARRAY_PTR(values); - - for (j = 0; j < r; ++j) result_array[j] = values_array[p[j]]; - ARY_SET_LEN(result, r); - rb_yield(result); - if (RBASIC(values)->klass) { + if (!yield_indexed_values(values, r, p)) { rb_raise(rb_eRuntimeError, "repeated combination reentered"); } } |