[#5737] returning strings from methods/instance_methods — TRANS <transfire@...>

I was just wondering why with #methods and #instance_methods, it was

11 messages 2005/09/08

[#5796] proposed attr writer patch — Daniel Berger <Daniel.Berger@...>

Hi all,

18 messages 2005/09/16

[#5798] Makefile error in OpenSLL extension (on Windows) — noreply@...

Bugs item #2472, was opened at 2005-09-16 18:56

11 messages 2005/09/17
[#5800] Re: [ ruby-Bugs-2472 ] Makefile error in OpenSLL extension (on Windows) — nobu.nokada@... 2005/09/17

Hi,

[#5851] Re: RubyGems in Ruby HEAD — Paul van Tilburg <paul@...>

Hi all,

34 messages 2005/09/21
[#5867] Re: RubyGems in Ruby HEAD — mathew <meta@...> 2005/09/21

Paul van Tilburg wrote:

[#5870] Re: RubyGems in Ruby HEAD — Marc Dequènes (Duck) <Duck@...> 2005/09/21

[#5920] Re: RubyGems in Ruby HEAD — mathew <meta@...> 2005/09/22

Marc Dequ竪nes (Duck) wrote:

[#5926] Re: RubyGems in Ruby HEAD — Pascal Terjan <pterjan@...> 2005/09/23

On 9/22/05, mathew <meta@pobox.com> wrote:

[#5931] Re: RubyGems in Ruby HEAD — Austin Ziegler <halostatue@...> 2005/09/23

On 9/23/05, Pascal Terjan <pterjan@gmail.com> wrote:

[#5898] Delegate and Forwardable Documentation — James Edward Gray II <james@...>

I've tried to send these files through a couple of times now with

17 messages 2005/09/22
[#5911] Re: Delegate and Forwardable Documentation — James Edward Gray II <james@...> 2005/09/22

On Sep 22, 2005, at 9:02 AM, James Edward Gray II wrote:

[#5924] Re: Delegate and Forwardable Documentation — James Edward Gray II <james@...> 2005/09/23

On Sep 22, 2005, at 11:53 AM, James Edward Gray II wrote:

[#5941] Re: Delegate and Forwardable Documentation — Yukihiro Matsumoto <matz@...> 2005/09/23

Hi,

[#5942] Re: Delegate and Forwardable Documentation — James Edward Gray II <james@...> 2005/09/23

On Sep 23, 2005, at 10:54 AM, Yukihiro Matsumoto wrote:

[#5947] Re: Delegate and Forwardable Documentation — Yukihiro Matsumoto <matz@...> 2005/09/23

Hi,

[#5921] Mutually dependent libs double loading. — TRANS <transfire@...>

I'm on Ruby 1.8.2.

14 messages 2005/09/23
[#5923] Re: Mutually dependent libs double loading. — Florian Gro<florgro@...> 2005/09/23

TRANS wrote:

[#5985] Finally an answer to my RubyGems question and some small suggestions — TRANS <transfire@...>

I appreciate those that attempted to offer me some info on this issue.

9 messages 2005/09/26

[#6001] Require Namepaces and RubyGems' effect on LoadPath problem — TRANS <transfire@...>

I've added namespaces to require. Works like this:

94 messages 2005/09/26
[#6002] Re: Require Namepaces and RubyGems' effect on LoadPath problem — Austin Ziegler <halostatue@...> 2005/09/26

On 9/26/05, TRANS <transfire@gmail.com> wrote:

[#6003] Re: Require Namepaces and RubyGems' effect on LoadPath problem — TRANS <transfire@...> 2005/09/26

On 9/26/05, Austin Ziegler <halostatue@gmail.com> wrote:

[#6005] Re: Require Namepaces and RubyGems' effect on LoadPath problem — Austin Ziegler <halostatue@...> 2005/09/26

On 9/26/05, TRANS <transfire@gmail.com> wrote:

[#6007] gems is a language change, not a pkging system (Re: Require Namepaces and RubyGems' effect on LoadPath problem) — Sam Roberts <sroberts@...> 2005/09/26

Quoting halostatue@gmail.com, on Tue, Sep 27, 2005 at 06:02:07AM +0900:

[#6013] Re: gems is a language change, not a pkging system (Re: Require Namepaces and RubyGems' effect on LoadPath problem) — Austin Ziegler <halostatue@...> 2005/09/27

On 9/26/05, Sam Roberts <sroberts@uniserve.com> wrote:

[#6014] Re: gems is a language change, not a pkging system — Sam Roberts <sroberts@...> 2005/09/27

Quoting halostatue@gmail.com, on Tue, Sep 27, 2005 at 10:29:17AM +0900:

[#6015] Re: gems is a language change, not a pkging system — James Edward Gray II <james@...> 2005/09/27

On Sep 26, 2005, at 8:54 PM, Sam Roberts wrote:

[#6016] Re: gems is a language change, not a pkging system — Sam Roberts <sroberts@...> 2005/09/27

Quoting james@grayproductions.net, on Tue, Sep 27, 2005 at 11:06:01AM +0900:

[#6018] Re: gems is a language change, not a pkging system — Austin Ziegler <halostatue@...> 2005/09/27

On 9/26/05, Sam Roberts <sroberts@uniserve.com> wrote:

[#6019] Re: gems is a language change, not a pkging system — Sam Roberts <sroberts@...> 2005/09/27

Quoting halostatue@gmail.com, on Tue, Sep 27, 2005 at 11:49:14AM +0900:

[#6024] Re: gems is a language change, not a pkging system — Austin Ziegler <halostatue@...> 2005/09/27

On 9/27/05, Sam Roberts <sroberts@uniserve.com> wrote:

[#6025] Re: gems is a language change, not a pkging system — Ralph Amissah <ralph.amissah@...> 2005/09/27

> Right now, they're watching people who have pretty much sat on the side

[#6026] Re: gems is a language change, not a pkging system — Austin Ziegler <halostatue@...> 2005/09/27

On 9/27/05, Ralph Amissah <ralph.amissah@gmail.com> wrote:

[#6043] Re: gems is a language change, not a pkging system — Ralph Amissah <ralph.amissah@...> 2005/09/28

I'll greatly weaken my post, and give everyone the opportunity to head me

[#6044] Re: gems is a language change, not a pkging system — Hugh Sasse <hgs@...> 2005/09/28

On Wed, 28 Sep 2005, Ralph Amissah wrote:

[#6073] Re: gems is a language change, not a pkging system — Mauricio Fern疣dez <mfp@...> 2005/09/28

Hello,

[#6074] Re: gems is a language change, not a pkging system — Jim Weirich <jim@...> 2005/09/29

On Wednesday 28 September 2005 07:35 pm, Mauricio Fern疣dez wrote:

[#6017] Re: gems is a language change, not a pkging system — Austin Ziegler <halostatue@...> 2005/09/27

On 9/26/05, Sam Roberts <sroberts@uniserve.com> wrote:

[#6046] Re: gems is a language change, not a pkging system — "Sean E. Russell" <ser@...> 2005/09/28

On Monday 26 September 2005 22:41, Austin Ziegler wrote:

[#6050] Re: gems is a language change, not a pkging system — Hugh Sasse <hgs@...> 2005/09/28

On Wed, 28 Sep 2005, Sean E. Russell wrote:

[#6207] Re: gems is a language change, not a pkging system — "Sean E. Russell" <ser@...> 2005/10/10

On Wednesday 28 September 2005 08:54, Hugh Sasse wrote:

[#6045] Re: gems is a language change, not a pkging system (Re: Require Namepaces and RubyGems' effect on LoadPath problem) — "Sean E. Russell" <ser@...> 2005/09/28

On Monday 26 September 2005 21:29, Austin Ziegler wrote:

[#6048] Re: gems is a language change, not a pkging system (Re: Require Namepaces and RubyGems' effect on LoadPath problem) — Austin Ziegler <halostatue@...> 2005/09/28

On 9/28/05, Sean E. Russell <ser@germane-software.com> wrote:

[#6059] Re: gems is a language change, not a pkging system (Re: Require Namepaces and RubyGems' effect on LoadPath problem) — Dominique Brezinski <dominique.brezinski@...> 2005/09/28

On 9/28/05, Austin Ziegler <halostatue@gmail.com> wrote:

[#6061] Re: gems is a language change, not a pkging system (Re: Require Namepaces and RubyGems' effect on LoadPath problem) — Austin Ziegler <halostatue@...> 2005/09/28

On 9/28/05, Dominique Brezinski <dominique.brezinski@gmail.com> wrote:

[#6062] Re: gems is a language change, not a pkging system (Re: Require Namepaces and RubyGems' effect on LoadPath problem) — Dominique Brezinski <dominique.brezinski@...> 2005/09/28

For what it is worth, I live life behind an authenticated proxy, so I

[#6099] Re: gems is a language change, not a pkging system (Re: Require Namepaces and RubyGems' effect on LoadPath problem) — "Sean E. Russell" <ser@...> 2005/09/30

On Wednesday 28 September 2005 08:43, Austin Ziegler wrote:

[#6009] Re: ruby 1.8.3 (2005-09-21) [i486-linux] sisu segfault — Ralph Amissah <ralph.amissah@...>

(i) correction, segfault is with official ruby 1.8.3 (2005-09-21), not

21 messages 2005/09/27
[#6010] Fwd: ruby 1.8.3 (2005-09-21) [i486-linux] sisu segfault — Ralph Amissah <ralph.amissah@...> 2005/09/27

[sorry for duplicate post]

[#6079] Re: Fwd: ruby 1.8.3 (2005-09-21) [i486-linux] sisu segfault — ts <decoux@...> 2005/09/29

>>>>> "R" == Ralph Amissah <ralph.amissah@gmail.com> writes:

[#6081] Re: Fwd: ruby 1.8.3 (2005-09-21) [i486-linux] sisu segfault — ts <decoux@...> 2005/09/29

>>>>> "t" == ts <decoux@moulon.inra.fr> writes:

[#6082] Re: Fwd: ruby 1.8.3 (2005-09-21) [i486-linux] sisu segfault — Tanaka Akira <akr@...17n.org> 2005/09/29

In article <200509291419.j8TEJYid015419@moulon.inra.fr>,

patch for O(1) performance for Array#unshift and Array#shift

From: Eric Mahurin <eric_mahurin@...>
Date: 2005-09-18 19:10:34 UTC
List: ruby-core #5820
Before giving that patch, here are some performance numbers for
n=65536 (the benchmark code is attached):

old (v1.9 from CVS):

                    user     system      total        real
shift           0.020000   0.000000   0.020000 (  0.025219)
pop             0.020000   0.000000   0.020000 (  0.024189)
unshift         3.970000   0.000000   3.970000 (  5.810518)
push            0.040000   0.000000   0.040000 (  0.035977)
shift/unshift   9.900000   5.400000  15.300000 ( 15.900842)
pop/push        0.010000   0.000000   0.010000 (  0.025130)
shift/push      7.760000   5.570000  13.330000 ( 13.995335)
pop/unshift     1.960000   0.000000   1.960000 (  2.056620)
shift/pop       0.010000   0.000000   0.010000 (  0.018803)
ushift/push     2.010000   0.000000   2.010000 (  2.243158)
shift2          0.020000   0.000000   0.020000 (  0.018887)
pop2            0.010000   0.000000   0.010000 (  0.018966)
unshift2        2.000000   0.000000   2.000000 (  2.128590)
push2           0.020000   0.000000   0.020000 (  0.070644)
shift2/pop2     0.020000   0.000000   0.020000 (  0.016413)
ushift2/push2   1.000000   0.000000   1.000000 (  1.007503)

new:

                    user     system      total        real
shift           0.020000   0.000000   0.020000 (  0.040953)
pop             0.030000   0.000000   0.030000 (  0.040594)
unshift         0.030000   0.000000   0.030000 (  0.052172)
push            0.030000   0.000000   0.030000 (  0.053591)
shift/unshift   0.020000   0.000000   0.020000 (  0.035353)
pop/push        0.020000   0.000000   0.020000 (  0.035218)
shift/push      0.020000   0.000000   0.020000 (  0.035056)
pop/unshift     0.020000   0.000000   0.020000 (  0.034636)
shift/pop       0.020000   0.000000   0.020000 (  0.032797)
ushift/push     0.020000   0.000000   0.020000 (  0.040963)
shift2          0.020000   0.000000   0.020000 (  0.032121)
pop2            0.020000   0.000000   0.020000 (  0.033111)
unshift2        0.020000   0.000000   0.020000 (  0.033722)
push2           0.020000   0.000000   0.020000 (  0.033936)
shift2/pop2     0.010000   0.000000   0.010000 (  0.029171)
ushift2/push2   0.010000   0.000000   0.010000 (  0.029569)

I didn't solve these (n=8192) where element sharing causes
O(n**2) memory usage (memory blows up with larger n):

shift2/unshift2   0.690000   0.090000   0.780000 (  0.799305)
pop2/push2        1.090000   0.070000   1.160000 (  1.179294)
shift2/push2      1.160000   0.080000   1.240000 (  1.265385)
pop2/unshift2     0.820000   0.090000   0.910000 (  0.937219)


I accomplished this by using a flag bit (ELTS_LFREE=FL_USER3)
to designate that there is free space to the left of ptr and
ptr[-1] will hold how many elements are free.  Just like push
will allocate space with excess space for the array to grow by
50% to the right, unshift now does something similar for growth
to the left of the array (actually preserves some space on both
sides if there was space to the right already).

I just used cvs diff -u to generate the patch attached
(unshift.diff).  Not sure if this is the right way.

Matz, is this acceptable?  I don't see any downsides and it
gives huge performance increases for Array#shift and
Array#unshift.

Other things that could be done along these same lines include:

- make random all inserts/deletes do the operation toward the
closest end of the array.  On average this will double the
random insert/delete performance.

- redo element sharing to not copy the parent array when it is
modified and one or more slices are sharing data with it. 
Instead cause the slices to get copies.  This would result in
something no worse in terms of memory usage than if sharing
wasn't employed - not something that can be said now.

- when the array needs to be stretched and data needs to be
moved, don't realloc/move.  This results in 2 moves typically
because realloc typically has to do a move.  Instead alloc
new/move old->new/free old.

- do the same things for string

Eric



		
__________________________________ 
Yahoo! Mail - PC Magazine Editors' Choice 2005 
http://mail.yahoo.com

Attachments (2)

end_test.rb (1.68 KB, text/x-ruby)
require 'benchmark'

[1 << 13, 1 << 16].each { |n|
    puts
    puts("n = #{n}")
    n2 = n/2;
    n4 = n/4;
    a0 = []
    an2 = Array.new(n2) { |i| i }
    an = Array.new(n) { |i| i }
    Benchmark.bmbm { |b|
        b.report("shift") {a=an.dup;n.times{a.shift}}
        b.report("pop") {a=an.dup;n.times{a.pop}}
        b.report("unshift") {a=a0.dup;n.times{|i|a.unshift(i)}}
        b.report("push") {a=a0.dup;n.times{|i|a.push(i)}}
        b.report("shift/unshift") {a=an2.dup;n2.times{a.unshift(a.shift)}}
        b.report("pop/push") {a=an2.dup;n2.times{a.push(a.pop)}}
        b.report("shift/push") {a=an2.dup;n2.times{a.push(a.shift)}}
        b.report("pop/unshift") {a=an2.dup;n2.times{a.unshift(a.pop)}}
        b.report("shift/pop") {a=an.dup;n2.times{a.shift;a.pop}}
        b.report("ushift/push") {a=a0.dup;n2.times{|i|a.unshift(i);a.push(i)}}
        b.report("shift2") {a=an.dup;n2.times{a.shift(2)}}
        b.report("pop2") {a=an.dup;n2.times{a.pop(2)}}
        b.report("unshift2") {a=a0.dup;n2.times{|i|a.unshift(i,i)}}
        b.report("push2") {a=a0.dup;n2.times{|i|a.push(i,i)}}
        b.report("shift2/pop2") {a=an.dup;n4.times{a.shift(2);a.pop(2)}}
        b.report("ushift2/push2") {a=a0.dup;n4.times{|i|a.unshift(i,i);a.push(i,i)}}
        if n <= (1 << 13)
            # these will run out of memory because of element sharing - O(n**2)
            b.report("shift2/unshift2") {a=an.dup;n4.times{a.unshift(x=a.shift(2),x)}}
            b.report("pop2/push2") {a=an.dup;n4.times{a.push(x=a.pop(2),x)}}
            b.report("shift2/push2") {a=an.dup;n4.times{a.push(x=a.shift(2),x)}}
            b.report("pop2/unshift2") {a=an.dup;n4.times{a.unshift(x=a.pop(2),x)}}
        end
    }
}


unshift.diff (9.16 KB, text/x-diff)
Index: array.c
===================================================================
RCS file: /src/ruby/array.c,v
retrieving revision 1.179
diff -u -r1.179 array.c
--- array.c	12 Sep 2005 15:23:54 -0000	1.179
+++ array.c	18 Sep 2005 18:50:58 -0000
@@ -211,6 +211,10 @@
 	shared->len = RARRAY(ary)->len;
 	shared->ptr = RARRAY(ary)->ptr;
 	shared->aux.capa = RARRAY(ary)->aux.capa;
+        if (FL_TEST(ary,ELTS_LFREE)) {
+            FL_SET(shared,ELTS_LFREE);
+            FL_UNSET(ary,ELTS_LFREE);
+        }
 	RARRAY(ary)->aux.shared = (VALUE)shared;
 	FL_SET(ary, ELTS_SHARED);
 	OBJ_FREEZE(shared);
@@ -341,7 +345,10 @@
     }
     rb_ary_modify(ary);
     if (len > RARRAY(ary)->aux.capa) {
-	REALLOC_N(RARRAY(ary)->ptr, VALUE, len);
+        long lfree = FL_TEST(ary,ELTS_LFREE) ? RARRAY(ary)->ptr[-1] : 0;
+        RARRAY(ary)->ptr -= lfree;
+	REALLOC_N(RARRAY(ary)->ptr, VALUE, len + lfree);
+        RARRAY(ary)->ptr += lfree;
 	RARRAY(ary)->aux.capa = len;
     }
     if (rb_block_given_p()) {
@@ -400,6 +407,7 @@
     rb_ary_modify(ary);
     if (idx >= RARRAY(ary)->aux.capa) {
 	long new_capa = RARRAY(ary)->aux.capa / 2;
+        long lfree = FL_TEST(ary,ELTS_LFREE) ? RARRAY(ary)->ptr[-1] : 0;
 
 	if (new_capa < ARY_DEFAULT_SIZE) {
 	    new_capa = ARY_DEFAULT_SIZE;
@@ -408,7 +416,9 @@
 	if (new_capa * (long)sizeof(VALUE) <= new_capa) {
 	    rb_raise(rb_eArgError, "index too big");
 	}
-	REALLOC_N(RARRAY(ary)->ptr, VALUE, new_capa);
+        RARRAY(ary)->ptr -= lfree;
+	REALLOC_N(RARRAY(ary)->ptr, VALUE, new_capa + lfree);
+        RARRAY(ary)->ptr += lfree;
 	RARRAY(ary)->aux.capa = new_capa;
     }
     if (idx > RARRAY(ary)->len) {
@@ -500,8 +510,11 @@
     if (!FL_TEST(ary, ELTS_SHARED) &&
 	    RARRAY(ary)->len * 2 < RARRAY(ary)->aux.capa &&
 	    RARRAY(ary)->aux.capa > ARY_DEFAULT_SIZE) {
+        long lfree = FL_TEST(ary,ELTS_LFREE) ? RARRAY(ary)->ptr[-1] : 0;
 	RARRAY(ary)->aux.capa = RARRAY(ary)->len * 2;
-	REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->aux.capa);
+        RARRAY(ary)->ptr -= lfree;
+	REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->aux.capa + lfree);
+        RARRAY(ary)->ptr += lfree;
     }
     return RARRAY(ary)->ptr[--RARRAY(ary)->len];
 }
@@ -543,7 +556,15 @@
     rb_ary_modify_check(ary);
     if (RARRAY(ary)->len == 0) return Qnil;
     top = RARRAY(ary)->ptr[0];
-    ary_make_shared(ary);
+    if (!FL_TEST(ary,ELTS_SHARED)) {
+        if (FL_TEST(ary,ELTS_LFREE)) {
+            RARRAY(ary)->ptr[0] = RARRAY(ary)->ptr[-1]+1;
+        } else {
+            FL_SET(ary, ELTS_LFREE);
+            RARRAY(ary)->ptr[0] = 1;
+        }
+        RARRAY(ary)->aux.capa--;
+    }
     RARRAY(ary)->ptr++;		/* shift ptr */
     RARRAY(ary)->len--;
 
@@ -587,28 +608,6 @@
     return result;
 }
 
-VALUE
-rb_ary_unshift(VALUE ary, VALUE item)
-{
-    rb_ary_modify(ary);
-    if (RARRAY(ary)->len == RARRAY(ary)->aux.capa) {
-	long capa_inc = RARRAY(ary)->aux.capa / 2;
-	if (capa_inc < ARY_DEFAULT_SIZE) {
-	    capa_inc = ARY_DEFAULT_SIZE;
-	}
-	RARRAY(ary)->aux.capa += capa_inc;
-	REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->aux.capa);
-    }
-
-    /* sliding items */
-    MEMMOVE(RARRAY(ary)->ptr + 1, RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len);
-
-    RARRAY(ary)->len++;
-    RARRAY(ary)->ptr[0] = item;
-
-    return ary;
-}
-
 /*
  *  call-seq:
  *     array.unshift(obj, ...)  -> array
@@ -624,20 +623,52 @@
 static VALUE
 rb_ary_unshift_m(int argc, VALUE *argv, VALUE ary)
 {
-    long len = RARRAY(ary)->len;
-
-    if (argc == 0) return ary;
-
-    /* make rooms by setting the last item */
-    rb_ary_store(ary, len + argc - 1, Qnil);
+    long lfree = FL_TEST(ary,ELTS_LFREE) ? RARRAY(ary)->ptr[-1] : 0;
+    
+    rb_ary_modify_check(ary);
 
-    /* sliding items */
-    MEMMOVE(RARRAY(ary)->ptr + argc, RARRAY(ary)->ptr, VALUE, len);
+    if (lfree<argc) {
+        int elts_shared = FL_TEST(ary, ELTS_SHARED); 
+        long len = RARRAY(ary)->len;
+        long rfree = elts_shared ? 0 : (RARRAY(ary)->aux.capa-len)/2;
+	long free2 = argc+(RARRAY(ary)->len+argc)/2;
+        VALUE *ptr;
+	if (free2 < ARY_DEFAULT_SIZE) {
+	    free2 = ARY_DEFAULT_SIZE;
+	}
+        ptr = ALLOC_N(VALUE,len+free2)+(free2-rfree);
+        MEMMOVE(ptr, RARRAY(ary)->ptr, VALUE, len);
+        if (elts_shared) {
+            FL_UNSET(ary, ELTS_SHARED);
+        } else {
+            free(RARRAY(ary)->ptr-lfree);
+        }
+        RARRAY(ary)->ptr = ptr;
+        RARRAY(ary)->aux.capa = len+rfree;
+        lfree = free2-rfree;
+        FL_SET(ary, ELTS_LFREE);
+    }
+
+    RARRAY(ary)->ptr -= argc;
+    RARRAY(ary)->len += argc;
+    RARRAY(ary)->aux.capa += argc;
+    lfree -= argc;
+    if (lfree) {
+        RARRAY(ary)->ptr[-1] = lfree;
+    } else {
+        FL_UNSET(ary, ELTS_LFREE);
+    }
     MEMCPY(RARRAY(ary)->ptr, argv, VALUE, argc);
-    
+
     return ary;
 }
 
+VALUE
+rb_ary_unshift(VALUE ary, VALUE item)
+{
+    return rb_ary_unshift_m(1,&item,ary);
+}
+
 /* faster version - use this if you don't need to treat negative offset */
 static inline VALUE
 rb_ary_elt(VALUE ary, long offset)
@@ -993,7 +1024,10 @@
     if (beg >= RARRAY(ary)->len) {
 	len = beg + rlen;
 	if (len >= RARRAY(ary)->aux.capa) {
-	    REALLOC_N(RARRAY(ary)->ptr, VALUE, len);
+            long lfree = FL_TEST(ary,ELTS_LFREE) ? RARRAY(ary)->ptr[-1] : 0;
+            RARRAY(ary)->ptr -= lfree;
+	    REALLOC_N(RARRAY(ary)->ptr, VALUE, len + lfree);
+            RARRAY(ary)->ptr += lfree;
 	    RARRAY(ary)->aux.capa = len;
 	}
 	rb_mem_clear(RARRAY(ary)->ptr + RARRAY(ary)->len, beg - RARRAY(ary)->len);
@@ -1011,7 +1045,10 @@
 
 	alen = RARRAY(ary)->len + rlen - len;
 	if (alen >= RARRAY(ary)->aux.capa) {
-	    REALLOC_N(RARRAY(ary)->ptr, VALUE, alen);
+            long lfree = FL_TEST(ary,ELTS_LFREE) ? RARRAY(ary)->ptr[-1] : 0;
+            RARRAY(ary)->ptr -= lfree;
+	    REALLOC_N(RARRAY(ary)->ptr, VALUE, alen + lfree);
+            RARRAY(ary)->ptr += lfree;
 	    RARRAY(ary)->aux.capa = alen;
 	}
 
@@ -1752,7 +1789,10 @@
 	RARRAY(ary)->len = i2;
 	if (i2 * 2 < RARRAY(ary)->aux.capa &&
 	    RARRAY(ary)->aux.capa > ARY_DEFAULT_SIZE) {
-	    REALLOC_N(RARRAY(ary)->ptr, VALUE, i2 * 2);
+            long lfree = FL_TEST(ary,ELTS_LFREE) ? RARRAY(ary)->ptr[-1] : 0;
+            RARRAY(ary)->ptr -= lfree;
+	    REALLOC_N(RARRAY(ary)->ptr, VALUE, i2 * 2 + lfree);
+            RARRAY(ary)->ptr += lfree;
 	    RARRAY(ary)->aux.capa = i2 * 2;
 	}
     }
@@ -2037,8 +2077,10 @@
     orig = to_ary(orig);
     if (copy == orig) return copy;
     shared = ary_make_shared(orig);
-    if (RARRAY(copy)->ptr && !FL_TEST(copy, ELTS_SHARED))
-	free(RARRAY(copy)->ptr);
+    if (RARRAY(copy)->ptr && !FL_TEST(copy, ELTS_SHARED)) {
+        long lfree = FL_TEST(copy,ELTS_LFREE) ? RARRAY(copy)->ptr[-1] : 0;
+	free(RARRAY(copy)->ptr-lfree);
+    }
     RARRAY(copy)->ptr = RARRAY(orig)->ptr;
     RARRAY(copy)->len = RARRAY(orig)->len;
     RARRAY(copy)->aux.shared = shared;
@@ -2063,7 +2105,10 @@
     rb_ary_modify(ary);
     RARRAY(ary)->len = 0;
     if (ARY_DEFAULT_SIZE * 2 < RARRAY(ary)->aux.capa) {
-	REALLOC_N(RARRAY(ary)->ptr, VALUE, ARY_DEFAULT_SIZE * 2);
+        long lfree = FL_TEST(ary,ELTS_LFREE) ? RARRAY(ary)->ptr[-1] : 0;
+        RARRAY(ary)->ptr -= lfree;
+	REALLOC_N(RARRAY(ary)->ptr, VALUE, ARY_DEFAULT_SIZE * 2 + lfree);
+        RARRAY(ary)->ptr += lfree;
 	RARRAY(ary)->aux.capa = ARY_DEFAULT_SIZE * 2;
     }
     return ary;
@@ -2132,7 +2177,10 @@
     end = beg + len;
     if (end > RARRAY(ary)->len) {
 	if (end >= RARRAY(ary)->aux.capa) {
-	    REALLOC_N(RARRAY(ary)->ptr, VALUE, end);
+            long lfree = FL_TEST(ary,ELTS_LFREE) ? RARRAY(ary)->ptr[-1] : 0;
+            RARRAY(ary)->ptr -= lfree;
+	    REALLOC_N(RARRAY(ary)->ptr, VALUE, end + lfree);
+            RARRAY(ary)->ptr += lfree;
 	    RARRAY(ary)->aux.capa = end;
 	}
 	if (beg > RARRAY(ary)->len) {
@@ -2661,6 +2709,7 @@
 rb_ary_compact_bang(VALUE ary)
 {
     VALUE *p, *t, *end;
+    long lfree;
 
     rb_ary_modify(ary);
     p = t = RARRAY(ary)->ptr;
@@ -2674,7 +2723,10 @@
 	return Qnil;
     }
     RARRAY(ary)->len = RARRAY(ary)->aux.capa = (p - RARRAY(ary)->ptr);
-    REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len);
+    lfree = FL_TEST(ary,ELTS_LFREE) ? RARRAY(ary)->ptr[-1] : 0;
+    RARRAY(ary)->ptr -= lfree;
+    REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len + lfree);
+    RARRAY(ary)->ptr += lfree;
 
     return ary;
 }
Index: gc.c
===================================================================
RCS file: /src/ruby/gc.c,v
retrieving revision 1.209
diff -u -r1.209 gc.c
--- gc.c	14 Sep 2005 08:30:15 -0000	1.209
+++ gc.c	18 Sep 2005 18:50:59 -0000
@@ -1111,7 +1111,8 @@
 	break;
       case T_ARRAY:
 	if (RANY(obj)->as.array.ptr && !FL_TEST(obj, ELTS_SHARED)) {
-	    RUBY_CRITICAL(free(RANY(obj)->as.array.ptr));
+        long lfree = FL_TEST(obj,ELTS_LFREE) ? RANY(obj)->as.array.ptr[-1] : 0;
+	    RUBY_CRITICAL(free(RANY(obj)->as.array.ptr-lfree));
 	}
 	break;
       case T_HASH:
Index: ruby.h
===================================================================
RCS file: /src/ruby/ruby.h,v
retrieving revision 1.122
diff -u -r1.122 ruby.h
--- ruby.h	14 Sep 2005 13:40:43 -0000	1.122
+++ ruby.h	18 Sep 2005 18:50:59 -0000
@@ -347,6 +347,7 @@
 };
 
 #define ELTS_SHARED FL_USER2
+#define ELTS_LFREE FL_USER3
 
 struct RString {
     struct RBasic basic;

In This Thread

Prev Next