@@ -4682,6 +4682,25 @@ rb_ary_cycle(int argc, VALUE *argv, VALUE ary)
46824682#define tmpary (n ) rb_ary_tmp_new(n)
46834683#define tmpary_discard (a ) (ary_discard(a), RBASIC_SET_CLASS_RAW(a, rb_cArray))
46844684
4685+ /*
4686+ * Build a ruby array of the corresponding values and yield it to the
4687+ * associated block.
4688+ * Return the class of +values+ for reentry check.
4689+ */
4690+ static int
4691+ yield_indexed_values (const VALUE values , const long r , const long * const p )
4692+ {
4693+ const VALUE result = rb_ary_new2 (r );
4694+ VALUE * const result_array = RARRAY_PTR (result );
4695+ const VALUE * const values_array = RARRAY_CONST_PTR (values );
4696+ long i ;
4697+
4698+ for (i = 0 ; i < r ; i ++ ) result_array [i ] = values_array [p [i ]];
4699+ ARY_SET_LEN (result , r );
4700+ rb_yield (result );
4701+ return !RBASIC (values )-> klass ;
4702+ }
4703+
46854704/*
46864705 * Recursively compute permutations of +r+ elements of the set
46874706 * <code>[0..n-1]</code>.
@@ -4699,7 +4718,7 @@ rb_ary_cycle(int argc, VALUE *argv, VALUE ary)
46994718static void
47004719permute0 (long n , long r , long * p , long index , char * used , VALUE values )
47014720{
4702- long i , j ;
4721+ long i ;
47034722 for (i = 0 ; i < n ; i ++ ) {
47044723 if (used [i ] == 0 ) {
47054724 p [index ] = i ;
@@ -4710,17 +4729,7 @@ permute0(long n, long r, long *p, long index, char *used, VALUE values)
47104729 used [i ] = 0 ; /* index unused */
47114730 }
47124731 else {
4713- /* We have a complete permutation of array indexes */
4714- /* Build a ruby array of the corresponding values */
4715- /* And yield it to the associated block */
4716- VALUE result = rb_ary_new2 (r );
4717- VALUE * result_array = RARRAY_PTR (result );
4718- const VALUE * values_array = RARRAY_PTR (values );
4719-
4720- for (j = 0 ; j < r ; j ++ ) result_array [j ] = values_array [p [j ]];
4721- ARY_SET_LEN (result , r );
4722- rb_yield (result );
4723- if (RBASIC (values )-> klass ) {
4732+ if (!yield_indexed_values (values , r , p )) {
47244733 rb_raise (rb_eRuntimeError , "permute reentered" );
47254734 }
47264735 }
@@ -4889,21 +4898,19 @@ rb_ary_combination(VALUE ary, VALUE num)
48894898 }
48904899 }
48914900 else {
4892- volatile VALUE t0 = tmpbuf (n + 1 , sizeof (long ));
4893- long * stack = (long * )RSTRING_PTR (t0 );
4894- volatile VALUE cc = tmpary (n );
4895- VALUE * chosen = RARRAY_PTR (cc );
4901+ VALUE ary0 = ary_make_shared_copy (ary ); /* private defensive copy of ary */
4902+ volatile VALUE t0 ;
4903+ long * stack = ALLOCV_N (long , t0 , n + 1 );
48964904 long lev = 0 ;
48974905
4898- MEMZERO (stack , long , n );
4906+ RBASIC_CLEAR_CLASS (ary0 );
4907+ MEMZERO (stack + 1 , long , n );
48994908 stack [0 ] = -1 ;
49004909 for (;;) {
4901- chosen [lev ] = RARRAY_AREF (ary , stack [lev + 1 ]);
49024910 for (lev ++ ; lev < n ; lev ++ ) {
4903- chosen [ lev ] = RARRAY_AREF ( ary , stack [lev + 1 ] = stack [lev ]+ 1 ) ;
4911+ stack [lev + 1 ] = stack [lev ]+ 1 ;
49044912 }
4905- rb_yield (rb_ary_new4 (n , chosen ));
4906- if (RBASIC (t0 )-> klass ) {
4913+ if (!yield_indexed_values (ary0 , n , stack + 1 )) {
49074914 rb_raise (rb_eRuntimeError , "combination reentered" );
49084915 }
49094916 do {
@@ -4912,8 +4919,8 @@ rb_ary_combination(VALUE ary, VALUE num)
49124919 } while (stack [lev + 1 ]+ n == len + lev + 1 );
49134920 }
49144921 done :
4915- tmpbuf_discard (t0 );
4916- tmpary_discard ( cc );
4922+ ALLOCV_END (t0 );
4923+ RBASIC_SET_CLASS_RAW ( ary0 , rb_cArray );
49174924 }
49184925 return ary ;
49194926}
@@ -4934,24 +4941,14 @@ rb_ary_combination(VALUE ary, VALUE num)
49344941static void
49354942rpermute0 (long n , long r , long * p , long index , VALUE values )
49364943{
4937- long i , j ;
4944+ long i ;
49384945 for (i = 0 ; i < n ; i ++ ) {
49394946 p [index ] = i ;
49404947 if (index < r - 1 ) { /* if not done yet */
49414948 rpermute0 (n , r , p , index + 1 , values ); /* recurse */
49424949 }
49434950 else {
4944- /* We have a complete permutation of array indexes */
4945- /* Build a ruby array of the corresponding values */
4946- /* And yield it to the associated block */
4947- VALUE result = rb_ary_new2 (r );
4948- VALUE * result_array = RARRAY_PTR (result );
4949- const VALUE * values_array = RARRAY_PTR (values );
4950-
4951- for (j = 0 ; j < r ; j ++ ) result_array [j ] = values_array [p [j ]];
4952- ARY_SET_LEN (result , r );
4953- rb_yield (result );
4954- if (RBASIC (values )-> klass ) {
4951+ if (!yield_indexed_values (values , r , p )) {
49554952 rb_raise (rb_eRuntimeError , "repeated permute reentered" );
49564953 }
49574954 }
@@ -5032,22 +5029,14 @@ rb_ary_repeated_permutation(VALUE ary, VALUE num)
50325029static void
50335030rcombinate0 (long n , long r , long * p , long index , long rest , VALUE values )
50345031{
5035- long j ;
50365032 if (rest > 0 ) {
50375033 for (; index < n ; ++ index ) {
50385034 p [r - rest ] = index ;
50395035 rcombinate0 (n , r , p , index , rest - 1 , values );
50405036 }
50415037 }
50425038 else {
5043- VALUE result = rb_ary_new2 (r );
5044- VALUE * result_array = RARRAY_PTR (result );
5045- const VALUE * values_array = RARRAY_PTR (values );
5046-
5047- for (j = 0 ; j < r ; ++ j ) result_array [j ] = values_array [p [j ]];
5048- ARY_SET_LEN (result , r );
5049- rb_yield (result );
5050- if (RBASIC (values )-> klass ) {
5039+ if (!yield_indexed_values (values , r , p )) {
50515040 rb_raise (rb_eRuntimeError , "repeated combination reentered" );
50525041 }
50535042 }
0 commit comments