Hi all,
Windows XP
VC++ 8
I noticed that the Array#delete method in array.c is basically copying
the existing array element by element into a new array object. I
suspected it could be improved so I tried this.
Using an approach similar to Array#delete_at, I came up with this:
VALUE rb_ary_delete(VALUE self, VALUE v_object){
long i, n, length;
int modified = 0;
VALUE v_return = Qnil;
length = RARRAY(self)->len;
for(i = 0; i < RARRAY(self)->len; i++){
if(rb_equal(v_object, RARRAY(self)->ptr[i])){
if(!modified){
rb_ary_modify(self);
modified = 1;
}
for(n = 0; n < length; n++)
RARRAY(self)->ptr[n-1] = RARRAY(self)->ptr[n];
length -= 1;
RARRAY(self)->len = length;
i -= 1;
}
}
/* If there was no match found and block was provided,
* return the value of the yielded block. Otherwise, return
* the deleted value.
*/
if((!modified) && (rb_block_given_p())){
v_return = rb_yield(rb_block_proc());
}
else{
if(modified)
v_return = v_object;
}
return v_return;
}
Then I ran this benchmark:
require 'benchmark'
MAX = 30000
array = ['daniel'] * 1000
array << ['charles'] * 1000
array << ['matz'] * 1000
array << ['larry'] * 1000
array << ['guido'] * 1000
array.flatten!
Benchmark.bm(10) do |x|
x.report("delete"){
MAX.times{ array.delete('larry') }
}
end
Old Array#delete:
user system total real
delete 13.125000 0.000000 13.125000 ( 13.468000)
New Array#delete:
user system total real
delete 3.704000 0.000000 3.704000 ( 3.781000)
So, about a 3x speed increase in my tests, where I compiled both
versions with MS VC++ 8 on Windows XP.
I thought I would see a substantial memory usage decrease, but my
(limited) testing didn't show more than an 8k decrease for the Ruby process.
The only test I could break was an unrelated Array#collect! test:
# With the change, it returns [3,3]
def test_collect_bang_removes_elements_before_they_are_reached
a = [1,2,3]
assert_equal([2, 3], a.collect!{ |e| a.delete(a[1]) })
end
However, I believe the semantics for modifying an array in-place in the
middle of a collect block are undefined, so I'm not sure the test I came
up with is actually valid.
Thoughts? Suggestions? Comments?
Thanks,
Dan