From: Mauricio Fernandez Date: 2005-12-16T19:33:16+09:00 Subject: Re: Question of reference and (sub)strings. On Fri, Dec 16, 2005 at 08:17:40AM +0900, Ron Jeffries wrote: > On Thu, 15 Dec 2005 14:50:59 +0900, "Daniel Sheppard" > wrote: > > >I might be wrong - but I'm pretty sure that substrings in ruby are > >created with copy-on-write. That is, when you take a substring, a new > >block of memory isn't allocated to the new String, it references the > >same block of memory as the original string - the allocation of a new > >block of memory only occurs when one of the strings is modified. > > I asked about this a week or two ago, as part of my Extended Set Theory thing, > and the impression I got from the answers then was that sub /arrays/ are copy on > write but that sub /strings/ were not. > > I wonder how one might confirm this, other than by asking matz or reading the > compiler and libraries ... Just the following should do: ----------------------------------------------------------------------------- VALUE rb_str_substr(str, beg, len) VALUE str; long beg, len; { VALUE str2; if (len < 0) return Qnil; if (beg > RSTRING(str)->len) return Qnil; if (beg < 0) { beg += RSTRING(str)->len; if (beg < 0) return Qnil; } if (beg + len > RSTRING(str)->len) { len = RSTRING(str)->len - beg; } if (len < 0) { len = 0; } if (len == 0) { str2 = rb_str_new5(str,0,0); } else if (len > sizeof(struct RString)/2 && beg + len == RSTRING(str)->len && !FL_TEST(str, STR_ASSOC)) { /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */ str2 = rb_str_new3(rb_str_new4(str)); RSTRING(str2)->ptr += RSTRING(str2)->len - len; RSTRING(str2)->len = len; } else { str2 = rb_str_new5(str, RSTRING(str)->ptr+beg, len); } OBJ_INFECT(str2, str); return str2; } ----------------------------------------------------------------------------- ... (optionally) ... ----------------------------------------------------------------------------- static VALUE str_new3(klass, str) VALUE klass, str; { VALUE str2 = str_alloc(klass); RSTRING(str2)->len = RSTRING(str)->len; RSTRING(str2)->ptr = RSTRING(str)->ptr; RSTRING(str2)->aux.shared = str; FL_SET(str2, ELTS_SHARED); OBJ_INFECT(str2, str); return str2; } VALUE rb_str_new3(str) VALUE str; { return str_new3(rb_obj_class(str), str); } static VALUE str_new4(klass, str) VALUE klass, str; { VALUE str2 = str_alloc(klass); RSTRING(str2)->len = RSTRING(str)->len; RSTRING(str2)->ptr = RSTRING(str)->ptr; if (FL_TEST(str, ELTS_SHARED)) { FL_SET(str2, ELTS_SHARED); RSTRING(str2)->aux.shared = RSTRING(str)->aux.shared; } else { FL_SET(str, ELTS_SHARED); RSTRING(str)->aux.shared = str2; } return str2; } VALUE rb_str_new4(orig) VALUE orig; { VALUE klass, str; if (OBJ_FROZEN(orig)) return orig; klass = rb_obj_class(orig); if (FL_TEST(orig, ELTS_SHARED) && (str = RSTRING(orig)->aux.shared) && klass == RBASIC(str)->klass) { long ofs; ofs = RSTRING(str)->len - RSTRING(orig)->len; if (ofs > 0) { str = str_new3(klass, str); RSTRING(str)->ptr += ofs; RSTRING(str)->len -= ofs; } } else if (FL_TEST(orig, STR_ASSOC)) { str = str_new(klass, RSTRING(orig)->ptr, RSTRING(orig)->len); } else { str = str_new4(klass, orig); } OBJ_INFECT(str, orig); OBJ_FREEZE(str); return str; } VALUE rb_str_new5(obj, ptr, len) VALUE obj; const char *ptr; long len; { return str_new(rb_obj_class(obj), ptr, len); } ----------------------------------------------------------------------------- -- Mauricio Fernandez