From c8aaf31fdd06df05c8c58df3d312280c5a02fc09 Mon Sep 17 00:00:00 2001 From: nobu Date: Wed, 5 Jan 2011 20:10:59 +0000 Subject: * array.c (rb_ary_resize): new utility function. [ruby-dev:42912] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@30465 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- array.c | 45 ++++++++++++++++++++++++++++++++++++++ ext/-test-/array/resize/extconf.rb | 1 + ext/-test-/array/resize/resize.c | 14 ++++++++++++ include/ruby/intern.h | 1 + test/-ext-/array/test_resize.rb | 29 ++++++++++++++++++++++++ 5 files changed, 90 insertions(+) create mode 100644 ext/-test-/array/resize/extconf.rb create mode 100644 ext/-test-/array/resize/resize.c create mode 100644 test/-ext-/array/test_resize.rb diff --git a/array.c b/array.c index b7c913d40d..54213449dd 100644 --- a/array.c +++ b/array.c @@ -1308,6 +1308,51 @@ rb_ary_splice(VALUE ary, long beg, long len, VALUE rpl) } } +/*! + * expands or shrinks \a ary to \a len elements. + * expanded region will be filled with Qnil. + * \param ary an arrray + * \param len new size + * \return \a ary + * \post the size of \a ary is \a len. + */ +VALUE +rb_ary_resize(VALUE ary, long len) +{ + long olen; + + 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), VALUE, len); + ary_discard(ary); + MEMCPY(ARY_EMBED_PTR(ary), tmp, VALUE, 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 diff --git a/ext/-test-/array/resize/extconf.rb b/ext/-test-/array/resize/extconf.rb new file mode 100644 index 0000000000..6500a878fc --- /dev/null +++ b/ext/-test-/array/resize/extconf.rb @@ -0,0 +1 @@ +create_makefile("-test-/array/resize") diff --git a/ext/-test-/array/resize/resize.c b/ext/-test-/array/resize/resize.c new file mode 100644 index 0000000000..b3e6c751ba --- /dev/null +++ b/ext/-test-/array/resize/resize.c @@ -0,0 +1,14 @@ +#include "ruby/ruby.h" + +static VALUE +ary_resize(VALUE ary, VALUE len) +{ + rb_ary_resize(ary, NUM2LONG(len)); + return ary; +} + +void +Init_resize(void) +{ + rb_define_method(rb_cArray, "resize", ary_resize, 1); +} diff --git a/include/ruby/intern.h b/include/ruby/intern.h index 578587109d..7f194a9dd2 100644 --- a/include/ruby/intern.h +++ b/include/ruby/intern.h @@ -83,6 +83,7 @@ VALUE rb_ary_includes(VALUE, VALUE); 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); diff --git a/test/-ext-/array/test_resize.rb b/test/-ext-/array/test_resize.rb new file mode 100644 index 0000000000..d9084b652d --- /dev/null +++ b/test/-ext-/array/test_resize.rb @@ -0,0 +1,29 @@ +require 'test/unit' +require '-test-/array/resize' + +class TestArray < Test::Unit::TestCase + class TestResize < Test::Unit::TestCase + def test_expand + feature = '[ruby-dev:42912]' + ary = [*1..10] + ary.resize(10) + assert_equal(10, ary.size, feature) + assert_equal([*1..10], ary, feature) + ary.resize(100) + assert_equal(100, ary.size, feature) + assert_equal([*1..10]+[nil]*90, ary, feature) + ary.resize(20) + assert_equal(20, ary.size, feature) + assert_equal([*1..10]+[nil]*10, ary, feature) + ary.resize(2) + assert_equal(2, ary.size, feature) + assert_equal([1,2], ary, feature) + ary.resize(3) + assert_equal(3, ary.size, feature) + assert_equal([1,2,nil], ary, feature) + ary.resize(10) + assert_equal(10, ary.size, feature) + assert_equal([1,2]+[nil]*8, ary, feature) + end + end +end -- cgit v1.2.3