From: Nobuyoshi Nakada Date: 2011-01-01T11:08:52+09:00 Subject: [ruby-dev:42917] Re: cut off an array at C level なかだです。 At Fri, 31 Dec 2010 18:55:19 +0900, Tanaka Akira wrote in [ruby-dev:42912]: > ふと、sort_by でテンポラリオブジェクトを減らす方法を思いついて、 > やってみたら (r30439) 高速化してよかったのですが、 > その中で配列の最後のほうを切り落とす関数が見当たらなくて、 > 配列の中身 (RARRAY_EMBED_FLAG) にアクセスする必要がありました。 > > 長さを変えるのは配列に対する基本的な操作な気がするんですが、 > なんでないんでしたっけ? 見落としてる? あったような気がしたんですがないですねぇ。 Index: include/ruby/intern.h =================================================================== --- include/ruby/intern.h (revision 30444) +++ include/ruby/intern.h (working copy) @@ -83,6 +83,7 @@ VALUE rb_ary_cmp(VALUE, VALUE); VALUE rb_ary_replace(VALUE copy, VALUE orig); VALUE rb_get_values_at(VALUE, long, int, VALUE*, VALUE(*)(VALUE,long)); +VALUE rb_ary_resize(VALUE ary, long len); /* bignum.c */ VALUE rb_big_new(long, int); int rb_bigzero_p(VALUE x); Index: array.c =================================================================== --- array.c (revision 30444) +++ array.c (working copy) @@ -1308,6 +1308,43 @@ } } +VALUE +rb_ary_resize(VALUE ary, long len) +{ + long olen; + VALUE *ptr; + rb_ary_modify(ary); + olen = RARRAY_LEN(ary); + if (len == olen) return ary; + if (len > ARY_MAX_SIZE) { + rb_raise(rb_eIndexError, "index %ld too big", len); + } + if (len > olen) { + if (len >= ARY_CAPA(ary)) { + ary_double_capa(ary, len); + } + rb_mem_clear(RARRAY_PTR(ary) + olen, len - olen); + ARY_SET_HEAP_LEN(ary, len); + } + else if (ARY_EMBED_P(ary)) { + ARY_SET_EMBED_LEN(ary, len); + } + else if (len <= RARRAY_EMBED_LEN_MAX) { + VALUE tmp[RARRAY_EMBED_LEN_MAX]; + memcpy(tmp, ARY_HEAP_PTR(ary), ARY_HEAP_LEN(ary)); + ary_discard(ary); + memcpy(ARY_EMBED_PTR(ary), tmp, len); + ARY_SET_EMBED_LEN(ary, len); + } + else { + if (olen > len + ARY_DEFAULT_SIZE) { + REALLOC_N(RARRAY(ary)->as.heap.ptr, VALUE, len); + } + ARY_SET_HEAP_LEN(ary, len); + } + return ary; +} + /* * call-seq: * ary[index] = obj -> obj -- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦