From: nobu.nokada@... Date: 2004-06-15T22:16:48+09:00 Subject: Re: [Patch] Array#shift(n) Hi, At Tue, 15 Jun 2004 17:09:33 +0900, Yukihiro Matsumoto wrote in [ruby-core:03000]: > |Or: Is there any reason to downgrade it back to 'Array'? > > It depends on how you define the behavior: > > if first(2) means "gives first two values (packed in array) from the > original array", it should be Array. > > if first(2) means "returns subarray from the original array with > first two values", it should be A. > > I vote for the former. Along the former. And, Michal, do you have the test cases? Index: array.c =================================================================== RCS file: /var/cvs/src/ruby/array.c,v retrieving revision 1.148 diff -u -2 -p -w -r1.148 array.c --- array.c 11 Jun 2004 13:33:47 -0000 1.148 +++ array.c 15 Jun 2004 13:11:56 -0000 @@ -34,5 +34,5 @@ rb_mem_clear(mem, size) } -static void +static inline void memfill(mem, size, val) register VALUE *mem; @@ -73,4 +73,5 @@ rb_ary_modify(ary) } } + VALUE rb_ary_freeze(ary) @@ -117,5 +118,5 @@ ary_new(klass, len) long len; { - VALUE ary = ary_alloc(klass); + VALUE ary; if (len < 0) { @@ -126,4 +127,6 @@ ary_new(klass, len) } if (len == 0) len++; + + ary = ary_alloc(klass); RARRAY(ary)->ptr = ALLOC_N(VALUE, len); RARRAY(ary)->aux.capa = len; @@ -471,4 +474,38 @@ rb_ary_store(ary, idx, val) } +static VALUE +ary_shared_first(argc, argv, ary) + int argc; + VALUE *argv; + VALUE ary; +{ + VALUE nv, result; + long n; + + rb_scan_args(argc, argv, "1", &nv); + n = NUM2LONG(nv); + if (n > RARRAY(ary)->len) { + n = RARRAY(ary)->len; + } + else if (n < 0) { + rb_raise(rb_eArgError, "negative array size"); + } + result = ary_shared_array(rb_cArray, ary); + RARRAY(result)->len = n; + return result; +} + +static VALUE +ary_shared_last(argc, argv, ary) + int argc; + VALUE *argv; + VALUE ary; +{ + VALUE result = ary_shared_first(argc, argv, ary); + + RARRAY(result)->ptr += RARRAY(ary)->len - RARRAY(result)->len; + return result; +} + /* * call-seq: @@ -518,16 +555,4 @@ rb_ary_push_m(argc, argv, ary) } -/* - * call-seq: - * array.pop => obj or nil - * - * Removes the last element from self and returns it, or - * nil if the array is empty. - * - * a = [ "a", "m", "z" ] - * a.pop #=> "z" - * a #=> ["a", "m"] - */ - VALUE rb_ary_pop(ary) @@ -547,15 +572,33 @@ rb_ary_pop(ary) /* * call-seq: - * array.shift => obj or nil + * array.pop => obj or nil * - * Returns the first element of self and removes it (shifting all - * other elements down by one). Returns nil if the array - * is empty. + * Removes the last element from self and returns it, or + * nil if the array is empty. * - * args = [ "-m", "-q", "filename" ] - * args.shift #=> "-m" - * args #=> ["-q", "filename"] + * a = [ "a", "m", "z" ] + * a.pop #=> "z" + * a #=> ["a", "m"] */ +static VALUE +rb_ary_pop_m(argc, argv, ary) + int argc; + VALUE *argv; + VALUE ary; +{ + VALUE result; + + if (argc == 0) { + return rb_ary_pop(ary); + } + + rb_ary_modify_check(ary); + + result = ary_shared_last(argc, argv, ary); + RARRAY(ary)->len -= RARRAY(result)->len; + return result; +} + VALUE rb_ary_shift(ary) @@ -574,4 +617,44 @@ rb_ary_shift(ary) } +/* + * call-seq: + * array.shift => obj or nil + * + * Returns the first element of self and removes it (shifting all + * other elements down by one). Returns nil if the array + * is empty. + * + * args = [ "-m", "-q", "filename" ] + * args.shift #=> "-m" + * args #=> ["-q", "filename"] + * + * args = [ "-m", "-q", "filename" ] + * args.shift(2) #=> ["-m", "-q"] + * args #=> ["filename"] + */ + +static VALUE +rb_ary_shift_m(argc, argv, ary) + int argc; + VALUE *argv; + VALUE ary; +{ + VALUE result; + long n; + + if (argc == 0) { + return rb_ary_shift(ary); + } + + rb_ary_modify_check(ary); + + result = ary_shared_first(argc, argv, ary); + n = RARRAY(result)->len; + RARRAY(ary)->ptr += n; + RARRAY(ary)->len -= n; + + return result; +} + VALUE rb_ary_unshift(ary, item) @@ -778,5 +861,6 @@ rb_ary_at(ary, pos) /* * call-seq: - * array.first => obj or nil + * array.first => obj or nil + * array.first(n) => an_array * * Returns the first element of the array. If the array is empty, @@ -784,5 +868,6 @@ rb_ary_at(ary, pos) * * a = [ "q", "r", "s", "t" ] - * a.first #=> "q" + * a.first #=> "q" + * a.first(2) #=> ["q", "r"] */ @@ -798,15 +883,5 @@ rb_ary_first(argc, argv, ary) } else { - VALUE nv, result; - long n, i; - - rb_scan_args(argc, argv, "01", &nv); - n = NUM2LONG(nv); - if (n > RARRAY(ary)->len) n = RARRAY(ary)->len; - result = rb_ary_new2(n); - for (i=0; iptr[i]); - } - return result; + return ary_shared_first(argc, argv, ary); } } @@ -820,5 +895,7 @@ rb_ary_first(argc, argv, ary) * the first form returns nil. * - * [ "w", "x", "y", "z" ].last #=> "z" + * a = [ "w", "x", "y", "z" ] + * a.last #=> "z" + * a.last(2) #=> ["y", "z"] */ @@ -834,15 +911,5 @@ rb_ary_last(argc, argv, ary) } else { - VALUE nv, result; - long n, i; - - rb_scan_args(argc, argv, "01", &nv); - n = NUM2LONG(nv); - if (n > RARRAY(ary)->len) n = RARRAY(ary)->len; - result = rb_ary_new2(n); - for (i=RARRAY(ary)->len-n; n--; i++) { - rb_ary_push(result, RARRAY(ary)->ptr[i]); - } - return result; + return ary_shared_last(argc, argv, ary); } } @@ -1803,7 +1870,5 @@ rb_ary_values_at(argc, argv, ary) static VALUE -rb_ary_select(argc, argv, ary) - int argc; - VALUE *argv; +rb_ary_select(ary) VALUE ary; { @@ -1811,7 +1876,4 @@ rb_ary_select(argc, argv, ary) long i; - if (argc > 0) { - rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc); - } result = rb_ary_new2(RARRAY(ary)->len); for (i = 0; i < RARRAY(ary)->len; i++) { @@ -2993,6 +3055,6 @@ Init_Array() rb_define_method(rb_cArray, "<<", rb_ary_push, 1); rb_define_method(rb_cArray, "push", rb_ary_push_m, -1); - rb_define_method(rb_cArray, "pop", rb_ary_pop, 0); - rb_define_method(rb_cArray, "shift", rb_ary_shift, 0); + rb_define_method(rb_cArray, "pop", rb_ary_pop_m, -1); + rb_define_method(rb_cArray, "shift", rb_ary_shift_m, -1); rb_define_method(rb_cArray, "unshift", rb_ary_unshift_m, -1); rb_define_method(rb_cArray, "insert", rb_ary_insert, -1); @@ -3014,5 +3076,5 @@ Init_Array() rb_define_method(rb_cArray, "map", rb_ary_collect, 0); rb_define_method(rb_cArray, "map!", rb_ary_collect_bang, 0); - rb_define_method(rb_cArray, "select", rb_ary_select, -1); + rb_define_method(rb_cArray, "select", rb_ary_select, 0); rb_define_method(rb_cArray, "values_at", rb_ary_values_at, -1); rb_define_method(rb_cArray, "delete", rb_ary_delete, 1); -- Nobu Nakada