From: nobu.nakada@... Date: 2002-05-23T21:45:00+09:00 Subject: [ruby-dev:17210] Re: [RCR] Array#rotate{,!} なかだです。 At Thu, 23 May 2002 17:05:22 +0900, U.Nakamura wrote: > | RCR(http://www.rubygarden.org/article.php?sid=237)に書いときま > | したが、Array#rotate{,!}というのはどうでしょうか。自明かとは思 > | いますが、 > > 回転寿司シミュレータ(なんじゃそりゃ)に便利かも。 オヤジがまわってる? > | --- Array#rotate!(index) > | self[index]が先頭になるように回転する。変更されたときはself、 > | されなかったときはnilを返す。 > | > | --- Array#rotate(index) > | 回転された新しいArrayを返す。 > > 省略時引数として index = 1 というのを消極的に提案します。 うーむ。indexをmoduloにしたりして消極的なパッチ。 Index: array.c =================================================================== RCS file: /cvs/ruby/src/ruby/array.c,v retrieving revision 1.83 diff -u -2 -p -r1.83 array.c --- array.c 2002/05/22 05:57:08 1.83 +++ array.c 2002/05/23 10:34:08 @@ -1027,4 +1027,15 @@ rb_ary_to_a(ary) } +static void +ary_reverse(p1, p2) + VALUE *p1, *p2; +{ + while (p1 < p2) { + VALUE tmp = *p1; + *p1++ = *p2; + *p2-- = tmp; + } +} + VALUE rb_ary_reverse(ary) @@ -1032,5 +1043,4 @@ rb_ary_reverse(ary) { VALUE *p1, *p2; - VALUE tmp; rb_ary_modify(ary); @@ -1039,11 +1049,6 @@ rb_ary_reverse(ary) p1 = RARRAY(ary)->ptr; p2 = p1 + RARRAY(ary)->len - 1; /* points last item */ + ary_reverse(p1, p2); - while (p1 < p2) { - tmp = *p1; - *p1++ = *p2; - *p2-- = tmp; - } - return ary; } @@ -1064,4 +1069,99 @@ rb_ary_reverse_m(ary) } +static unsigned long +modulo_index(x, y) + long x; + unsigned long y; +{ + /* x must not be LONG_MIN */ + if (x < 0) { + if (x == LONG_MIN) return y - (-(LONG_MIN+1UL) % y + 1) % y; + return y - (unsigned long)-x % y; + } + else { + return (unsigned long)x % y; + } +} + +VALUE +rb_ary_rotate(ary, cnt) + VALUE ary; + long cnt; +{ + rb_ary_modify(ary); + + if (cnt != 0) { + VALUE *ptr = RARRAY(ary)->ptr; + long len = RARRAY(ary)->len; + + cnt = modulo_index(cnt, len); + if (cnt == 0) return Qnil; + + --len; + if (cnt > 1) ary_reverse(ptr, ptr + cnt - 1); + if (cnt < len) ary_reverse(ptr + cnt, ptr + len); + if (len > 0) ary_reverse(ptr, ptr + len); + return ary; + } + + return Qnil; +} + +static long +rotate_arg(argc, argv) + int argc; + VALUE *argv; +{ + long n = 1; + + switch (argc) { + case 1: + n = NUM2LONG(argv[0]); + case 0: + break; + default: + rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc); + } + + return n; +} + +static VALUE +rb_ary_rotate_bang(argc, argv, ary) + int argc; + VALUE *argv; + VALUE ary; +{ + long n = rotate_arg(argc, argv); + + if (RARRAY(ary)->len <= 1) return Qnil; + return rb_ary_rotate(ary, n); +} + +static VALUE +rb_ary_rotate_m(argc, argv, ary) + int argc; + VALUE *argv; + VALUE ary; +{ + VALUE rotated; + VALUE *ptr = RARRAY(ary)->ptr; + long len = RARRAY(ary)->len; + long n = rotate_arg(argc, argv); + + if (len > 1 && n != 0) + n = modulo_index(n, len); + else + n = 0; + + rotated = rb_ary_new2(len); + DUPSETUP(rotated, ary); + RARRAY(rotated)->len = len; + len -= n; + MEMCPY(RARRAY(rotated)->ptr, ptr + n, VALUE, len); + MEMCPY(RARRAY(rotated)->ptr + len, ptr, VALUE, n); + return rotated; +} + int rb_cmpint(cmp) @@ -1879,4 +1979,6 @@ Init_Array() rb_define_method(rb_cArray, "reverse", rb_ary_reverse_m, 0); rb_define_method(rb_cArray, "reverse!", rb_ary_reverse_bang, 0); + rb_define_method(rb_cArray, "rotate", rb_ary_rotate_m, -1); + rb_define_method(rb_cArray, "rotate!", rb_ary_rotate_bang, -1); rb_define_method(rb_cArray, "sort", rb_ary_sort, 0); rb_define_method(rb_cArray, "sort!", rb_ary_sort_bang, 0); -- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦