ruby-changes:4461
From: ko1@a...
Date: Thu, 10 Apr 2008 19:36:25 +0900 (JST)
Subject: [ruby-changes:4461] knu - Ruby:r15952 (ruby_1_8): * array.c (rb_ary_first, rb_ary_last): Return a shared array when
knu 2008-04-10 19:36:10 +0900 (Thu, 10 Apr 2008) New Revision: 15952 Modified files: branches/ruby_1_8/ChangeLog branches/ruby_1_8/NEWS branches/ruby_1_8/array.c Log: * array.c (rb_ary_first, rb_ary_last): Return a shared array when possible. * array.c (rb_ary_pop, rb_ary_pop_m, rb_ary_shift, rb_ary_shift_m): Array#pop and Array#shift can take an optional argument specifying the number of elements to remove and return; backported from 1.9. http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/ChangeLog?r1=15952&r2=15951&diff_format=u http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/array.c?r1=15952&r2=15951&diff_format=u http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/NEWS?r1=15952&r2=15951&diff_format=u Index: ruby_1_8/array.c =================================================================== --- ruby_1_8/array.c (revision 15951) +++ ruby_1_8/array.c (revision 15952) @@ -195,6 +195,27 @@ return ary; } +static VALUE +ary_make_shared(ary) + VALUE ary; +{ + if (!FL_TEST(ary, ELTS_SHARED)) { + NEWOBJ(shared, struct RArray); + OBJSETUP(shared, rb_cArray, T_ARRAY); + + shared->len = RARRAY(ary)->len; + shared->ptr = RARRAY(ary)->ptr; + shared->aux.capa = RARRAY(ary)->aux.capa; + RARRAY(ary)->aux.shared = (VALUE)shared; + FL_SET(ary, ELTS_SHARED); + OBJ_FREEZE(shared); + return (VALUE)shared; + } + else { + return RARRAY(ary)->aux.shared; + } +} + VALUE rb_assoc_new(car, cdr) VALUE car, cdr; @@ -384,6 +405,50 @@ RARRAY(ary)->ptr[idx] = val; } +static VALUE +ary_shared_array(klass, ary) + VALUE klass; + VALUE ary; +{ + VALUE val = ary_alloc(klass); + + ary_make_shared(ary); + RARRAY(val)->ptr = RARRAY(ary)->ptr; + RARRAY(val)->len = RARRAY(ary)->len; + RARRAY(val)->aux.shared = RARRAY(ary)->aux.shared; + FL_SET(val, ELTS_SHARED); + return val; +} + +static VALUE +ary_shared_first(argc, argv, ary, last) + int argc; + VALUE *argv; + VALUE ary; + int last; +{ + VALUE nv, result; + long n; + long offset = 0; + + 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"); + } + if (last) { + offset = RARRAY(ary)->len - n; + } + result = ary_shared_array(rb_cArray, ary); + RARRAY(result)->ptr += offset; + RARRAY(result)->len = n; + + return result; +} + /* * call-seq: * array << obj -> array @@ -431,18 +496,6 @@ return ary; } -/* - * call-seq: - * array.pop -> obj or nil - * - * Removes the last element from <i>self</i> and returns it, or - * <code>nil</code> if the array is empty. - * - * a = [ "a", "m", "z" ] - * a.pop #=> "z" - * a #=> ["a", "m"] - */ - VALUE rb_ary_pop(ary) VALUE ary; @@ -458,62 +511,112 @@ return RARRAY(ary)->ptr[--RARRAY(ary)->len]; } +/* + * call-seq: + * array.pop -> obj or nil + * array.pop(n) -> array + * + * Removes the last element from <i>self</i> and returns it, or + * <code>nil</code> if the array is empty. + * + * If a number _n_ is given, returns an array of the last n elements + * (or less) just like <code>array.slice!(-n, n)</code> does. + * + * a = [ "a", "b", "c", "d" ] + * a.pop #=> "d" + * a.pop(2) #=> ["b", "c"] + * a #=> ["a"] + */ + static VALUE -ary_make_shared(ary) +rb_ary_pop_m(argc, argv, ary) + int argc; + VALUE *argv; VALUE ary; { - if (!FL_TEST(ary, ELTS_SHARED)) { - NEWOBJ(shared, struct RArray); - OBJSETUP(shared, rb_cArray, T_ARRAY); + VALUE result; - shared->len = RARRAY(ary)->len; - shared->ptr = RARRAY(ary)->ptr; - shared->aux.capa = RARRAY(ary)->aux.capa; - RARRAY(ary)->aux.shared = (VALUE)shared; - FL_SET(ary, ELTS_SHARED); - OBJ_FREEZE(shared); - return (VALUE)shared; + if (argc == 0) { + return rb_ary_pop(ary); } - else { - return RARRAY(ary)->aux.shared; + + rb_ary_modify_check(ary); + result = ary_shared_first(argc, argv, ary, Qtrue); + RARRAY(ary)->len -= RARRAY(result)->len; + return result; +} + +VALUE +rb_ary_shift(ary) + VALUE ary; +{ + VALUE top; + + rb_ary_modify_check(ary); + if (RARRAY(ary)->len == 0) return Qnil; + top = RARRAY(ary)->ptr[0]; + if (!FL_TEST(ary, ELTS_SHARED)) { + if (RARRAY(ary)->len < ARY_DEFAULT_SIZE) { + MEMMOVE(RARRAY(ary)->ptr, RARRAY(ary)->ptr+1, VALUE, RARRAY(ary)->len-1); + RARRAY(ary)->len--; + return top; + } + RARRAY(ary)->ptr[0] = Qnil; + ary_make_shared(ary); } + RARRAY(ary)->ptr++; /* shift ptr */ + RARRAY(ary)->len--; + + return top; } /* * call-seq: - * array.shift -> obj or nil + * array.shift -> obj or nil + * array.shift(n) -> array * * Returns the first element of <i>self</i> and removes it (shifting all * other elements down by one). Returns <code>nil</code> if the array * is empty. + * + * If a number _n_ is given, returns an array of the first n elements + * (or less) just like <code>array.slice!(0, n)</code> does. * * args = [ "-m", "-q", "filename" ] - * args.shift #=> "-m" - * args #=> ["-q", "filename"] + * args.shift #=> "-m" + * args #=> ["-q", "filename"] + * + * args = [ "-m", "-q", "filename" ] + * args.shift(2) #=> ["-m", "-q"] + * args #=> ["filename"] */ -VALUE -rb_ary_shift(ary) +static VALUE +rb_ary_shift_m(argc, argv, ary) + int argc; + VALUE *argv; VALUE ary; { - VALUE top; + VALUE result; + long n; + if (argc == 0) { + return rb_ary_shift(ary); + } + rb_ary_modify_check(ary); - if (RARRAY(ary)->len == 0) return Qnil; - top = RARRAY(ary)->ptr[0]; - if (RARRAY_LEN(ary) < ARY_DEFAULT_SIZE && !FL_TEST(ary, ELTS_SHARED)) { - MEMMOVE(RARRAY_PTR(ary), RARRAY_PTR(ary)+1, VALUE, RARRAY_LEN(ary)-1); - } + result = ary_shared_first(argc, argv, ary, Qfalse); + n = RARRAY(result)->len; + if (FL_TEST(ary, ELTS_SHARED)) { + RARRAY(ary)->ptr += n; + RARRAY(ary)->len -= n; + } else { - if (!FL_TEST(ary, ELTS_SHARED)) { - RARRAY(ary)->ptr[0] = Qnil; - } - ary_make_shared(ary); - RARRAY(ary)->ptr++; /* shift ptr */ + MEMMOVE(RARRAY(ary)->ptr, RARRAY(ary)->ptr+n, VALUE, RARRAY(ary)->len-n); + RARRAY(ary)->len -= n; } - RARRAY(ary)->len--; - return top; + return result; } VALUE @@ -748,15 +851,7 @@ return RARRAY(ary)->ptr[0]; } else { - VALUE nv; - long n; - - rb_scan_args(argc, argv, "01", &nv); - n = NUM2LONG(nv); - if (n < 0) { - rb_raise(rb_eArgError, "negative array size"); - } - return rb_ary_subseq(ary, 0, n); + return ary_shared_first(argc, argv, ary, Qfalse); } } @@ -782,17 +877,7 @@ return RARRAY(ary)->ptr[RARRAY(ary)->len-1]; } 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_first(argc, argv, ary, Qtrue); } } @@ -3062,8 +3147,8 @@ rb_define_method(rb_cArray, "concat", rb_ary_concat, 1); 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); rb_define_method(rb_cArray, "each", rb_ary_each, 0); Index: ruby_1_8/NEWS =================================================================== --- ruby_1_8/NEWS (revision 15951) +++ ruby_1_8/NEWS (revision 15952) @@ -35,6 +35,12 @@ Return an enumerator if no block is given. + * Array#pop + * Array#shift + + Take an optional argument specifying the number of elements to + remove. + * Integer#ord implemented. * Integer#odd? implemented. * Integer#even? implemented. Index: ruby_1_8/ChangeLog =================================================================== --- ruby_1_8/ChangeLog (revision 15951) +++ ruby_1_8/ChangeLog (revision 15952) @@ -1,3 +1,13 @@ +Thu Apr 10 19:29:48 2008 Akinori MUSHA <knu@i...> + + * array.c (rb_ary_first, rb_ary_last): Return a shared array when + possible. + + * array.c (rb_ary_pop, rb_ary_pop_m, rb_ary_shift, rb_ary_shift_m): + Array#pop and Array#shift can take an optional argument + specifying the number of elements to remove and return; + backported from 1.9. + Thu Apr 10 14:00:44 2008 Tanaka Akira <akr@f...> * lib/resolv.rb (Resolv::DNS#each_address): backport from 1.9 for -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/