なかだです。

RCR(http://www.rubygarden.org/article.php?sid=237)に書いときま
したが、Array#rotate{,!}というのはどうでしょうか。自明かとは思
いますが、

--- Array#rotate!(index)
    self[index]が先頭になるように回転する。変更されたときはself、
    されなかったときはnilを返す。

--- Array#rotate(index)
    回転された新しいArrayを返す。

ということでパッチ。


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 03:54:57 @@ -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,10 +1049,5 @@ rb_ary_reverse(ary) p1 = RARRAY(ary)->ptr; p2 = p1 + RARRAY(ary)->len - 1; /* points last item */ - - while (p1 < p2) { - tmp = *p1; - *p1++ = *p2; - *p2-- = tmp; - } + ary_reverse(p1, p2); return ary; @@ -1064,4 +1069,76 @@ rb_ary_reverse_m(ary) } +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; + + if (cnt < 0) { + cnt += len; + if (cnt < 0) { + rb_raise(rb_eIndexError, "index %ld out of array", cnt - len); + } + if (cnt == 0) return Qnil; + } + else { + if (cnt >= len) { + rb_raise(rb_eIndexError, "index %ld out of array", cnt); + } + } + + --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 VALUE +rb_ary_rotate_bang(ary, cnt) + VALUE ary, cnt; +{ + long n = NUM2LONG(cnt); + + if (RARRAY(ary)->len <= 1) return Qnil; + return rb_ary_rotate(ary, n); +} + +static VALUE +rb_ary_rotate_m(ary, cnt) + VALUE ary, cnt; +{ + long n = NUM2LONG(cnt), len = RARRAY(ary)->len; + VALUE rotated, *ptr = RARRAY(ary)->ptr; + + if (n < 0) { + n += len; + if (n < 0) { + rb_raise(rb_eIndexError, "index %ld out of array", n - len); + } + } + else { + if (n >= len) { + rb_raise(rb_eIndexError, "index %ld out of array", n); + } + } + + 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 +1956,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はできる。 中田 伸悦