diff options
-rw-r--r-- | ChangeLog | 128 | ||||
-rw-r--r-- | ToDo | 10 | ||||
-rw-r--r-- | array.c | 209 | ||||
-rw-r--r-- | class.c | 3 | ||||
-rw-r--r-- | enum.c | 47 | ||||
-rw-r--r-- | error.c | 4 | ||||
-rw-r--r-- | ext/curses/curses.c | 60 | ||||
-rw-r--r-- | gc.c | 12 | ||||
-rw-r--r-- | hash.c | 41 | ||||
-rw-r--r-- | io.c | 31 | ||||
-rw-r--r-- | object.c | 3 | ||||
-rw-r--r-- | parse.y | 22 | ||||
-rw-r--r-- | regex.c | 2 | ||||
-rw-r--r-- | ruby.h | 17 | ||||
-rw-r--r-- | sample/test.rb | 57 | ||||
-rw-r--r-- | string.c | 225 | ||||
-rw-r--r-- | time.c | 55 | ||||
-rw-r--r-- | util.c | 59 | ||||
-rw-r--r-- | version.h | 4 |
19 files changed, 653 insertions, 336 deletions
@@ -1,15 +1,53 @@ -Sun Dec 9 23:00:54 2001 Keiju Ishitsuka <keiju@ishitsuka.com> - * matrix.rb: Vector#* bug. reported from Massimiliano Mirra - <info@chromatic-harp.com>. - -Sun Dec 9 22:15:59 2001 Nobuyoshi Nakada <nobu.nakada@nifty.ne.jp> +Mon Dec 10 02:09:28 2001 Yukihiro Matsumoto <matz@ruby-lang.org> - * enum.c (enum_sort_by): should replace with last elements. + * array.c (rb_ary_modify): should copy the internal buffer if the + modifying buffer is shared. + + * array.c (ary_make_shared): make an internal buffer of an array + to be shared. + + * array.c (rb_ary_shift): avoid sliding an internal buffer by + using shared buffer. + + * array.c (rb_ary_subseq): avoid copying the buffer. + +Mon Dec 10 01:06:56 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * parse.y (gettable): should freeze __LINE__ string. Sun Dec 9 18:06:26 2001 Minero Aoki <aamine@loveruby.net> * lib/net/protocol.rb: calls on_connect before conn_command +Sat Dec 8 23:27:44 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * io.c (rb_io_puts): old behavoir restored. rationale: a) if you + want to call to_s for arrays, you can just call print a, "\n". + b) to_s wastes memory if array (and sum of its contents) is + huge. c) now any object that has to_ary is treated as an array, + using rb_check_convert_type(). + +Sat Dec 8 22:40:38 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * hash.c (rb_hash_initialize): now accepts a block to calculate + the default value. [new] + + * hash.c (rb_hash_aref): call "default" method to get the value + corrensponding to the non existing key. + + * hash.c (rb_hash_default): get the default value based on the + block given to 'new'. Now it takes an optinal "key" argument. + "default" became the method to get the value for non existing + key. Users may override "default" method to change the hash + behavior. + + * hash.c (rb_hash_set_default): clear the flag if a block is given + to 'new' + +Sat Dec 8 02:29:54 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * object.c (Init_Object): undef Data.allocate, left Data.new. + Fri Dec 7 19:12:14 2001 Minero Aoki <aamine@loveruby.net> * lib/net/smtp.rb: SMTP.new requires at least one arg. @@ -27,12 +65,83 @@ Fri Dec 7 15:49:39 2001 Usaku Nakamura <usa@ruby-lang.org> * ext/extmk.rb.in: ignore adding -Wl,-R to DLDFLAGS when the directory is $topdir. +Fri Dec 7 13:58:58 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * ext/curses/curses.c (window_scrollok): use RTEST(). + + * ext/curses/curses.c (window_idlok): ditto. + + * ext/curses/curses.c (window_keypad): ditto. + + * ext/curses/curses.c (window_idlok): idlok() may return void on + some platforms; so don't use return value. + + * ext/curses/curses.c (window_scrollok): ditto for consistency. + + * ext/curses/curses.c: replace FIX2INT() by typechecking NUM2INT(). + +Fri Dec 7 09:51:00 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * parse.y (str_extend): should not process immature #$x and + #@x interpolation, e.g #@#@ etc. + +Fri Dec 7 03:21:18 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * enum.c (enum_sort_by): sort_by does not have to be stable always. + + * enum.c (enum_sort_by): call qsort directly to gain performance. + Thu Dec 6 18:52:28 2001 Usaku Nakamura <usa@ruby-lang.org> * ext/extmk.rb.in: add -Wl,-R flags to DLDFLAGS on netbsdelf. * lib/mkmf.rb: ditto. +Thu Dec 6 09:15:14 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * util.c (ruby_qsort): ruby_qsort(qs6) is now native thread safe. + + * error.c (rb_sys_fail): it must be a bug if it's called when + errno == 0. + +Wed Dec 5 23:36:56 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * regex.c (WC2MBC1ST): should not pass through > 0x80 number in UTF-8. + +Tue Dec 4 17:43:10 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * ruby.h (DUPSETUP): new SETUP macro for duplication. + + * time.c (time_dup): implement in Time class using DUPSETUP. + + * time.c (time_getlocaltime): new method; probably requires + better name than getlocaltime. [new,experimental] + + * time.c (time_getgmtime): ditto. + + * array.c (rb_ary_dup): uses DUPSETUP. + + * string.c (rb_str_dup): uses DUPSETUP. now properly copies + instance variables too. + +Tue Dec 4 03:49:06 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * io.c (io_fread): EAGAIN/EWOULDBLOCK should not terminate and + throw away the input. + + * time.c (time_new_internal): underflow adjustment must not use + negative div/mod. + + * time.c (time_cmp): should consider tv_usec on non Fixnum number + comparison. +Sun Dec 9 23:00:54 2001 Keiju Ishitsuka <keiju@ishitsuka.com> + * matrix.rb: Vector#* bug. reported from Massimiliano Mirra + <info@chromatic-harp.com>. + +Sun Dec 9 22:15:59 2001 Nobuyoshi Nakada <nobu.nakada@nifty.ne.jp> + + * enum.c (enum_sort_by): should replace with last elements. + Mon Dec 3 16:06:57 2001 WATANABE Hirofumi <eban@ruby-lang.org> * ext/socket/extconf.rb: remove -L/usr/local/lib. @@ -43,6 +152,13 @@ Mon Dec 3 16:04:16 2001 Usaku Nakamura <usa@ruby-lang.org> * configure.in: not use X11BASE, since it's not always set. +Mon Dec 3 13:53:49 2001 Tanaka Akira <akr@m17n.org> + + * time.c (rb_strftime): buffer length condition was wrong. + + * time.c (time_strftime): should backup buf to the original + buffer. + Mon Dec 3 09:59:08 2001 Yukihiro Matsumoto <matz@ruby-lang.org> * time.c (time_plus): must detect result overflow. @@ -71,9 +71,11 @@ Standard Libraries - fork_and_kill_other_threads. - signal list (Signal::trap, Signal::list). - move NameError under StandardError. +- Integer#to_s(base) +- Hash::new{default} +- hash etc. should handle self referenceing array/hash * String#scanf(?) * Object#fmt(?) -* Integer#{bin,oct,hex,heX} * Time::strptime * Integer[num], Float[num]; Fixnum[num]? * method to retrieve non-number trailer for to_i/to_f. @@ -86,16 +88,16 @@ Standard Libraries * Array#&, Array#| to allow duplication. ??? * way to specify immortal (fork endurance) thread; * or raise ForkException to every thread but fork caller. -* Hash::new{default} or recommend Hash#fetch? * new user-defined marshal scheme. _dump(dumper), _load(restorer) -* hash etc. should handle self referenceing array/hash * library to load per-user profile seeking .ruby_profile or ruby.ini file. * warning framework (warn, warning for Ruby level) -* marshal should not depend on sprintf/strtod (works bad for locale). +* marshal should not depend on sprintf/strtod (works bad with locale). * ternary arg pow: a.pow(b,c) == a**b%c * new caller(), e.g. call_stack; needs better name. * remove dependency on MAXPATHLEN. * pointer share mechanism similar to one in String for Array. +* Array#select(n1,n2...) works like Array#indexes(n1,n2...) +* deprecate Array#indexes, and Array#indices. Extension Libraries @@ -17,7 +17,7 @@ #include "st.h" VALUE rb_cArray; -static ID cmp; +static ID id_cmp; #define ARY_DEFAULT_SIZE 16 @@ -45,7 +45,7 @@ memfill(mem, size, val) #define ARY_TMPLOCK FL_USER1 static void -rb_ary_modify(ary) +rb_ary_modify_check(ary) VALUE ary; { if (OBJ_FROZEN(ary)) rb_error_frozen("array"); @@ -55,6 +55,21 @@ rb_ary_modify(ary) rb_raise(rb_eSecurityError, "Insecure: can't modify array"); } +static void +rb_ary_modify(ary) + VALUE ary; +{ + VALUE *ptr; + + rb_ary_modify_check(ary); + if (!FL_TEST(ary, ELTS_SHARED)) return; + ptr = ALLOC_N(VALUE, RARRAY(ary)->len); + FL_UNSET(ary, ELTS_SHARED); + RARRAY(ary)->aux.capa = RARRAY(ary)->len; + MEMCPY(ptr, RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len); + RARRAY(ary)->ptr = ptr; +} + VALUE rb_ary_freeze(ary) VALUE ary; @@ -79,14 +94,14 @@ rb_ary_s_alloc(klass) OBJSETUP(ary, klass, T_ARRAY); ary->len = 0; - ary->capa = 0; ary->ptr = 0; + ary->aux.capa = 0; return (VALUE)ary; } -VALUE -rb_ary_new0(klass, len) +static VALUE +ary_new(klass, len) VALUE klass; long len; { @@ -100,7 +115,7 @@ rb_ary_new0(klass, len) } if (len == 0) len++; RARRAY(ary)->ptr = ALLOC_N(VALUE, len); - RARRAY(ary)->capa = len; + RARRAY(ary)->aux.capa = len; return ary; } @@ -109,7 +124,7 @@ VALUE rb_ary_new2(len) long len; { - return rb_ary_new0(rb_cArray, len); + return ary_new(rb_cArray, len); } @@ -228,9 +243,9 @@ rb_ary_initialize(argc, argv, ary) if (len > 0 && len*sizeof(VALUE) <= 0) { rb_raise(rb_eArgError, "array size too big"); } - if (len > RARRAY(ary)->capa) { - RARRAY(ary)->capa = len; - REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->capa); + if (len > RARRAY(ary)->aux.capa) { + RARRAY(ary)->aux.capa = len; + REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->aux.capa); } memfill(RARRAY(ary)->ptr, len, val); RARRAY(ary)->len = len; @@ -250,7 +265,7 @@ rb_ary_s_create(argc, argv, klass) RARRAY(ary)->ptr = ALLOC_N(VALUE, argc); MEMCPY(RARRAY(ary)->ptr, argv, VALUE, argc); } - RARRAY(ary)->len = RARRAY(ary)->capa = argc; + RARRAY(ary)->len = RARRAY(ary)->aux.capa = argc; return ary; } @@ -270,13 +285,13 @@ rb_ary_store(ary, idx, val) } } - if (idx >= RARRAY(ary)->capa) { - long capa_inc = RARRAY(ary)->capa / 2; + if (idx >= 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)->capa = idx + capa_inc; - REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->capa); + RARRAY(ary)->aux.capa = idx + capa_inc; + REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->aux.capa); } if (idx > RARRAY(ary)->len) { rb_mem_clear(RARRAY(ary)->ptr+RARRAY(ary)->len, @@ -319,34 +334,45 @@ VALUE rb_ary_pop(ary) VALUE ary; { - rb_ary_modify(ary); + rb_ary_modify_check(ary); if (RARRAY(ary)->len == 0) return Qnil; - if (RARRAY(ary)->len * 10 < RARRAY(ary)->capa && RARRAY(ary)->capa > ARY_DEFAULT_SIZE) { - RARRAY(ary)->capa = RARRAY(ary)->len * 2; - REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->capa); + if (RARRAY(ary)->len * 10 < RARRAY(ary)->aux.capa && RARRAY(ary)->aux.capa > ARY_DEFAULT_SIZE) { + RARRAY(ary)->aux.capa = RARRAY(ary)->len * 2; + REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->aux.capa); } return RARRAY(ary)->ptr[--RARRAY(ary)->len]; } +static void +ary_make_shared(ary) + VALUE ary; +{ + if (FL_TEST(ary, ELTS_SHARED)) return; + else { + NEWOBJ(shared, struct RArray); + OBJSETUP(shared, rb_cArray, T_ARRAY); + + shared->len = RARRAY(ary)->len; + shared->ptr = RARRAY(ary)->ptr; + shared->aux.capa = RARRAY(ary)->aux.capa; + RARRAY(ary)->aux.shared = (VALUE)shared; + FL_SET(ary, ELTS_SHARED); + } +} + VALUE rb_ary_shift(ary) VALUE ary; { VALUE top; - rb_ary_modify(ary); + rb_ary_modify_check(ary); if (RARRAY(ary)->len == 0) return Qnil; - top = RARRAY(ary)->ptr[0]; + ary_make_shared(ary); + RARRAY(ary)->ptr++; /* shift ptr */ RARRAY(ary)->len--; - /* sliding items */ - MEMMOVE(RARRAY(ary)->ptr, RARRAY(ary)->ptr+1, VALUE, RARRAY(ary)->len); - if (RARRAY(ary)->len * 10 < RARRAY(ary)->capa && RARRAY(ary)->capa > ARY_DEFAULT_SIZE) { - RARRAY(ary)->capa = RARRAY(ary)->len * 2; - REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->capa); - } - return top; } @@ -355,13 +381,13 @@ rb_ary_unshift(ary, item) VALUE ary, item; { rb_ary_modify(ary); - if (RARRAY(ary)->len >= RARRAY(ary)->capa) { - long capa_inc = RARRAY(ary)->capa / 2; + 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)->capa+=capa_inc; - REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->capa); + RARRAY(ary)->aux.capa+=capa_inc; + REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->aux.capa); } /* sliding items */ @@ -429,11 +455,14 @@ rb_ary_subseq(ary, beg, len) len = 0; } klass = rb_obj_class(ary); - if (len == 0) return rb_ary_new0(klass,0); + if (len == 0) return ary_new(klass,0); - ary2 = rb_ary_new0(klass, len); - MEMCPY(RARRAY(ary2)->ptr, RARRAY(ary)->ptr+beg, VALUE, len); + ary_make_shared(ary); + ary2 = rb_obj_alloc(klass); + RARRAY(ary2)->ptr = RARRAY(ary)->ptr+beg; RARRAY(ary2)->len = len; + RARRAY(ary2)->aux.shared = RARRAY(ary)->aux.shared; + FL_SET(ary2, ELTS_SHARED); return ary2; } @@ -609,9 +638,9 @@ rb_ary_update(ary, beg, len, rpl) rb_ary_modify(ary); if (beg >= RARRAY(ary)->len) { len = beg + rlen; - if (len >= RARRAY(ary)->capa) { - RARRAY(ary)->capa=len; - REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->capa); + if (len >= RARRAY(ary)->aux.capa) { + RARRAY(ary)->aux.capa=len; + REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->aux.capa); } rb_mem_clear(RARRAY(ary)->ptr+RARRAY(ary)->len, beg-RARRAY(ary)->len); MEMCPY(RARRAY(ary)->ptr+beg, RARRAY(rpl)->ptr, VALUE, rlen); @@ -625,9 +654,9 @@ rb_ary_update(ary, beg, len, rpl) } alen = RARRAY(ary)->len + rlen - len; - if (alen >= RARRAY(ary)->capa) { - RARRAY(ary)->capa = alen; - REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->capa); + if (alen >= RARRAY(ary)->aux.capa) { + RARRAY(ary)->aux.capa = alen; + REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->aux.capa); } if (len != rlen) { @@ -749,32 +778,51 @@ rb_ary_empty_p(ary) } static VALUE -rb_ary_clone(ary) +ary_copy(ary, clone) VALUE ary; + int clone; { - VALUE clone = rb_ary_new2(RARRAY(ary)->len); + VALUE copy; + + ary_make_shared(ary); + copy = rb_obj_alloc(rb_cArray); + if (clone) CLONESETUP(copy, ary); + else DUPSETUP(copy, ary); + RARRAY(copy)->ptr = RARRAY(ary)->ptr; + RARRAY(copy)->len = RARRAY(ary)->len; + RARRAY(copy)->aux.shared = RARRAY(ary)->aux.shared; + FL_SET(copy, ELTS_SHARED); + + return copy; +} - CLONESETUP(clone, ary); - MEMCPY(RARRAY(clone)->ptr, RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len); - RARRAY(clone)->len = RARRAY(ary)->len; - return clone; +static VALUE +rb_ary_clone(ary) + VALUE ary; +{ + return ary_copy(ary, Qtrue); } VALUE rb_ary_dup(ary) VALUE ary; { + return ary_copy(ary, Qfalse); +} + +static VALUE +ary_dup(ary) + VALUE ary; +{ VALUE dup = rb_ary_new2(RARRAY(ary)->len); - OBJSETUP(dup, rb_obj_class(ary), T_ARRAY); + DUPSETUP(dup, ary); MEMCPY(RARRAY(dup)->ptr, RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len); RARRAY(dup)->len = RARRAY(ary)->len; - OBJ_INFECT(dup, ary); return dup; } extern VALUE rb_output_fs; -extern VALUE rb_default_rs; static VALUE inspect_join(ary, arg) @@ -861,9 +909,6 @@ rb_ary_to_s(ary) if (RARRAY(ary)->len == 0) return rb_str_new(0, 0); sep = rb_output_fs; -#if 1 - if (NIL_P(rb_output_fs)) sep = rb_default_rs; /* newline */ -#endif str = rb_ary_join(ary, sep); return str; } @@ -1006,7 +1051,7 @@ static VALUE rb_ary_reverse_m(ary) VALUE ary; { - return rb_ary_reverse(rb_ary_dup(ary)); + return rb_ary_reverse(ary_dup(ary)); } int @@ -1018,8 +1063,8 @@ rb_cmpint(cmp) if (RBIGNUM(cmp)->sign) return 1; return -1; } - if (rb_funcall(cmp, '>', 1, INT2FIX(0))) return 1; - if (rb_funcall(cmp, '<', 1, INT2FIX(0))) return -1; + if (rb_funcall(id_cmp, '>', 1, INT2FIX(0))) return 1; + if (rb_funcall(id_cmp, '<', 1, INT2FIX(0))) return -1; return 0; } @@ -1044,7 +1089,7 @@ sort_2(a, b) return rb_str_cmp(*a, *b); } - retval = rb_funcall(*a, cmp, 1, *b); + retval = rb_funcall(*a, id_cmp, 1, *b); return rb_cmpint(retval); } @@ -1081,32 +1126,12 @@ VALUE rb_ary_sort(ary) VALUE ary; { - ary = rb_ary_dup(ary); + ary = ary_dup(ary); rb_ary_sort_bang(ary); return ary; } static VALUE -sort_inplace(ary) - VALUE ary; -{ - qsort(RARRAY(ary)->ptr, RARRAY(ary)->len, sizeof(VALUE),sort_2); - return ary; -} - -VALUE -rb_ary_sort_inplace(ary) - VALUE ary; -{ - rb_ary_modify(ary); - if (RARRAY(ary)->len <= 1) return ary; - - FL_SET(ary, ARY_TMPLOCK); /* prohibit modification during sort */ - rb_ensure(sort_inplace, ary, sort_unlock, ary); - return ary; -} - -static VALUE rb_ary_collect(ary) VALUE ary; { @@ -1269,7 +1294,7 @@ static VALUE rb_ary_reject(ary) VALUE ary; { - ary = rb_ary_dup(ary); + ary = ary_dup(ary); rb_ary_reject_bang(ary); return ary; } @@ -1297,9 +1322,9 @@ rb_ary_clear(ary) { rb_ary_modify(ary); RARRAY(ary)->len = 0; - if (ARY_DEFAULT_SIZE*3 < RARRAY(ary)->capa) { - RARRAY(ary)->capa = ARY_DEFAULT_SIZE * 2; - REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->capa); + if (ARY_DEFAULT_SIZE*3 < RARRAY(ary)->aux.capa) { + RARRAY(ary)->aux.capa = ARY_DEFAULT_SIZE * 2; + REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->aux.capa); } return ary; } @@ -1337,9 +1362,9 @@ rb_ary_fill(argc, argv, ary) rb_ary_modify(ary); end = beg + len; if (end > RARRAY(ary)->len) { - if (end >= RARRAY(ary)->capa) { - RARRAY(ary)->capa = end; - REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->capa); + if (end >= RARRAY(ary)->aux.capa) { + RARRAY(ary)->aux.capa = end; + REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->aux.capa); } if (beg > RARRAY(ary)->len) { rb_mem_clear(RARRAY(ary)->ptr+RARRAY(ary)->len,end-RARRAY(ary)->len); @@ -1397,7 +1422,7 @@ rb_ary_times(ary, times) } len *= RARRAY(ary)->len; - ary2 = rb_ary_new0(rb_obj_class(ary), len); + ary2 = ary_new(rb_obj_class(ary), len); RARRAY(ary2)->len = len; for (i=0; i<len; i+=RARRAY(ary)->len) { @@ -1521,7 +1546,7 @@ rb_ary_cmp(ary, ary2) len = RARRAY(ary2)->len; } for (i=0; i<len; i++) { - VALUE v = rb_funcall(RARRAY(ary)->ptr[i],cmp,1,RARRAY(ary2)->ptr[i]); + VALUE v = rb_funcall(RARRAY(ary)->ptr[i],id_cmp,1,RARRAY(ary2)->ptr[i]); if (v != INT2FIX(0)) { return v; } @@ -1646,7 +1671,7 @@ static VALUE rb_ary_uniq(ary) VALUE ary; { - ary = rb_ary_dup(ary); + ary = ary_dup(ary); rb_ary_uniq_bang(ary); return ary; } @@ -1667,7 +1692,7 @@ rb_ary_compact_bang(ary) if (RARRAY(ary)->len == (p - RARRAY(ary)->ptr)) { return Qnil; } - RARRAY(ary)->len = RARRAY(ary)->capa = (p - RARRAY(ary)->ptr); + RARRAY(ary)->len = RARRAY(ary)->aux.capa = (p - RARRAY(ary)->ptr); REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len); return ary; @@ -1677,7 +1702,7 @@ static VALUE rb_ary_compact(ary) VALUE ary; { - ary = rb_ary_dup(ary); + ary = ary_dup(ary); rb_ary_compact_bang(ary); return ary; } @@ -1755,7 +1780,7 @@ static VALUE rb_ary_flatten(ary) VALUE ary; { - ary = rb_ary_dup(ary); + ary = ary_dup(ary); rb_ary_flatten_bang(ary); return ary; } @@ -1847,5 +1872,5 @@ Init_Array() rb_define_method(rb_cArray, "flatten!", rb_ary_flatten_bang, 0); rb_define_method(rb_cArray, "nitems", rb_ary_nitems, 0); - cmp = rb_intern("<=>"); + id_cmp = rb_intern("<=>"); } @@ -87,7 +87,8 @@ rb_mod_dup(mod) VALUE mod; { VALUE dup = rb_mod_clone(mod); - OBJSETUP(dup, RBASIC(mod)->klass, BUILTIN_TYPE(mod)); + + DUPSETUP(dup, mod); if (FL_TEST(mod, FL_SINGLETON)) { FL_SET(dup, FL_SINGLETON); } @@ -12,6 +12,7 @@ #include "ruby.h" #include "node.h" +#include "util.h" VALUE rb_mEnumerable; static ID id_each, id_eqq, id_cmp; @@ -204,53 +205,41 @@ enum_sort(obj) } static VALUE -sort_by_i(i, memo) - VALUE i; - NODE *memo; +sort_by_i(i, ary) + VALUE i, ary; { VALUE v, e; v = rb_yield(i); - if (TYPE(v) == T_ARRAY) { - int j, len = RARRAY(v)->len; - - e = rb_ary_new2(len+2); - for (j=0; j<len; j++) { - RARRAY(e)->ptr[j] = RARRAY(v)->ptr[j]; - } - RARRAY(e)->ptr[j++] = INT2NUM(memo->u3.cnt); - RARRAY(e)->ptr[j] = i; - RARRAY(e)->len = len + 2; - } - else { - e = rb_ary_new3(3, v, INT2NUM(memo->u3.cnt), i); - } - rb_ary_push(memo->u1.value, e); - memo->u3.cnt++; + e = rb_assoc_new(v, i); + rb_ary_push(ary, e); return Qnil; } -static VALUE -sort_by_sort_body(a) - VALUE a; +static int +sort_by_cmp(a, b) + VALUE *a, *b; { - return rb_ary_cmp(RARRAY(a)->ptr[0], RARRAY(a)->ptr[1]); + VALUE retval; + + retval = rb_funcall(RARRAY(*a)->ptr[0], id_cmp, 1, RARRAY(*b)->ptr[0]); + return rb_cmpint(retval); } static VALUE enum_sort_by(obj) VALUE obj; { - VALUE ary = rb_ary_new2(2000); - NODE *memo = rb_node_newnode(NODE_MEMO, ary, 0, 0); + VALUE ary; long i; - rb_iterate(rb_each, obj, sort_by_i, (VALUE)memo); - rb_gc_force_recycle((VALUE)memo); - rb_ary_sort_inplace(ary); + ary = rb_ary_new2((TYPE(obj) == T_ARRAY) ? RARRAY(obj)->len : 2000); + rb_iterate(rb_each, obj, sort_by_i, ary); + if (RARRAY(ary)->len <= 1) return ary; + qsort(RARRAY(ary)->ptr, RARRAY(ary)->len, sizeof(VALUE), sort_by_cmp); for (i=0; i<RARRAY(ary)->len; i++) { VALUE e = RARRAY(ary)->ptr[i]; - RARRAY(ary)->ptr[i] = RARRAY(e)->ptr[RARRAY(e)->len - 1]; + RARRAY(ary)->ptr[i] = RARRAY(e)->ptr[1]; } return ary; @@ -718,6 +718,10 @@ rb_sys_fail(mesg) int n = errno; VALUE ee; + if (errno == 0) { + rb_bug("rb_sys_fail() - errno == 0"); + } + err = strerror(errno); if (mesg) { volatile VALUE tmp = rb_str_inspect(rb_str_new2(mesg)); diff --git a/ext/curses/curses.c b/ext/curses/curses.c index c756c47caa..c1523823b6 100644 --- a/ext/curses/curses.c +++ b/ext/curses/curses.c @@ -460,18 +460,20 @@ static VALUE curses_curs_set(VALUE obj, VALUE visibility) { int n; - return (n = curs_set(FIX2INT(visibility)) != ERR) ? INT2FIX(n) : Qnil; + return (n = curs_set(NUM2INT(visibility)) != ERR) ? INT2FIX(n) : Qnil; } static VALUE curses_scrl(VALUE obj, VALUE n) { + /* may have to raise exception on ERR */ return (scrl(NUM2INT(n)) == OK) ? Qtrue : Qfalse; } static VALUE curses_setscrreg(VALUE obj, VALUE top, VALUE bottom) { + /* may have to raise exception on ERR */ return (setscrreg(NUM2INT(top), NUM2INT(bottom)) == OK) ? Qtrue : Qfalse; } @@ -479,21 +481,21 @@ static VALUE curses_attroff(VALUE obj, VALUE attrs) { return window_attroff(rb_stdscr,attrs); - /* return INT2FIX(attroff(FIX2INT(attrs))); */ + /* return INT2FIX(attroff(NUM2INT(attrs))); */ } static VALUE curses_attron(VALUE obj, VALUE attrs) { return window_attron(rb_stdscr,attrs); - /* return INT2FIX(attroff(FIX2INT(attrs))); */ + /* return INT2FIX(attroff(NUM2INT(attrs))); */ } static VALUE curses_attrset(VALUE obj, VALUE attrs) { return window_attrset(rb_stdscr,attrs); - /* return INT2FIX(attroff(FIX2INT(attrs))); */ + /* return INT2FIX(attroff(NUM2INT(attrs))); */ } static VALUE @@ -513,20 +515,23 @@ curses_bkgd(VALUE obj, VALUE ch) static VALUE curses_start_color(VALUE obj) { + /* may have to raise exception on ERR */ return (start_color() == OK) ? Qtrue : Qfalse; } static VALUE curses_init_pair(VALUE obj, VALUE pair, VALUE f, VALUE b) { - return (init_pair(FIX2INT(pair),FIX2INT(f),FIX2INT(b)) == OK) ? Qtrue : Qfalse; + /* may have to raise exception on ERR */ + return (init_pair(NUM2INT(pair),NUM2INT(f),NUM2INT(b)) == OK) ? Qtrue : Qfalse; } static VALUE curses_init_color(VALUE obj, VALUE color, VALUE r, VALUE g, VALUE b) { - return (init_color(FIX2INT(color),FIX2INT(r), - FIX2INT(g),FIX2INT(b)) == OK) ? Qtrue : Qfalse; + /* may have to raise exception on ERR */ + return (init_color(NUM2INT(color),NUM2INT(r), + NUM2INT(g),NUM2INT(b)) == OK) ? Qtrue : Qfalse; } static VALUE @@ -546,7 +551,7 @@ curses_color_content(VALUE obj, VALUE color) { short r,g,b; - color_content(FIX2INT(color),&r,&g,&b); + color_content(NUM2INT(color),&r,&g,&b); return rb_ary_new3(3,INT2FIX(r),INT2FIX(g),INT2FIX(b)); } @@ -555,20 +560,20 @@ curses_pair_content(VALUE obj, VALUE pair) { short f,b; - pair_content(FIX2INT(pair),&f,&b); + pair_content(NUM2INT(pair),&f,&b); return rb_ary_new3(2,INT2FIX(f),INT2FIX(b)); } static VALUE curses_color_pair(VALUE obj, VALUE attrs) { - return INT2FIX(COLOR_PAIR(FIX2INT(attrs))); + return INT2FIX(COLOR_PAIR(NUM2INT(attrs))); } static VALUE curses_pair_number(VALUE obj, VALUE attrs) { - return INT2FIX(PAIR_NUMBER(FIX2INT(attrs))); + return INT2FIX(PAIR_NUMBER(NUM2INT(attrs))); } #endif @@ -591,7 +596,7 @@ no_mevent() static void curses_mousedata_free(struct mousedata *mdata) { - if( mdata->mevent ) + if (mdata->mevent) free(mdata->mevent); }; @@ -604,7 +609,7 @@ curses_getmouse(VALUE obj) val = Data_Make_Struct(cMouseEvent,struct mousedata, 0,curses_mousedata_free,mdata); mdata->mevent = (MEVENT*)malloc(sizeof(MEVENT)); - return ( getmouse(mdata->mevent) == OK ) ? val : Qnil; + return (getmouse(mdata->mevent) == OK) ? val : Qnil; }; static VALUE @@ -898,8 +903,8 @@ window_box(argc, argv, self) c = NUM2CHR(corn); getyx(winp->window, cur_y, cur_x); - x = FIX2INT(window_maxx(self)) - 1; - y = FIX2INT(window_maxy(self)) - 1; + x = NUM2INT(window_maxx(self)) - 1; + y = NUM2INT(window_maxy(self)) - 1; wmove(winp->window, 0, 0); waddch(winp->window, c); wmove(winp->window, y, 0); @@ -1062,11 +1067,10 @@ static VALUE window_scrollok(VALUE obj, VALUE bf) { struct windata *winp; - int res; GetWINDOW(obj, winp); - res = scrollok(winp->window, (bf == Qtrue) ? TRUE : FALSE); - return (res == OK) ? Qtrue : Qfalse; + scrollok(winp->window, RTEST(bf) ? TRUE : FALSE); + return Qnil; } static VALUE @@ -1076,8 +1080,8 @@ window_idlok(VALUE obj, VALUE bf) int res; GetWINDOW(obj, winp); - res = idlok(winp->window, (bf == Qtrue) ? TRUE : FALSE); - return (res == OK) ? Qtrue : Qfalse; + idlok(winp->window, RTEST(bf) ? TRUE : FALSE); + return Qnil; } static VALUE @@ -1088,6 +1092,7 @@ window_setscrreg(VALUE obj, VALUE top, VALUE bottom) GetWINDOW(obj, winp); res = wsetscrreg(winp->window, NUM2INT(top), NUM2INT(bottom)); + /* may have to raise exception on ERR */ return (res == OK) ? Qtrue : Qfalse; }; @@ -1097,6 +1102,7 @@ window_scroll(VALUE obj) struct windata *winp; GetWINDOW(obj, winp); + /* may have to raise exception on ERR */ return (scroll(winp->window) == OK) ? Qtrue : Qfalse; } @@ -1106,6 +1112,7 @@ window_scrl(VALUE obj, VALUE n) struct windata *winp; GetWINDOW(obj, winp); + /* may have to raise exception on ERR */ return (wscrl(winp->window,NUM2INT(n)) == OK) ? Qtrue : Qfalse; } @@ -1115,7 +1122,7 @@ window_attroff(VALUE obj, VALUE attrs) struct windata *winp; GetWINDOW(obj,winp); - return INT2FIX(wattroff(winp->window,FIX2INT(attrs))); + return INT2FIX(wattroff(winp->window,NUM2INT(attrs))); }; static VALUE @@ -1125,10 +1132,10 @@ window_attron(VALUE obj, VALUE attrs) VALUE val; GetWINDOW(obj,winp); - val = INT2FIX(wattron(winp->window,FIX2INT(attrs))); + val = INT2FIX(wattron(winp->window,NUM2INT(attrs))); if( rb_block_given_p() ){ rb_yield(val); - wattroff(winp->window,FIX2INT(attrs)); + wattroff(winp->window,NUM2INT(attrs)); return val; } else{ @@ -1142,7 +1149,7 @@ window_attrset(VALUE obj, VALUE attrs) struct windata *winp; GetWINDOW(obj,winp); - return INT2FIX(wattrset(winp->window,FIX2INT(attrs))); + return INT2FIX(wattrset(winp->window,NUM2INT(attrs))); } static VALUE @@ -1182,10 +1189,11 @@ window_keypad(VALUE obj, VALUE val) GetWINDOW(obj,winp); /* keypad() of NetBSD's libcurses returns no value */ #if defined(__NetBSD__) && !defined(NCURSES_VERSION) - keypad(winp->window,(val == Qtrue ? TRUE : FALSE)); + keypad(winp->window,(RTEST(val) ? TRUE : FALSE)); return Qnil; #else - return (keypad(winp->window,(val == Qtrue) ? TRUE : FALSE)) == OK ? + /* may have to raise exception on ERR */ + return (keypad(winp->window,RTEST(val) ? TRUE : FALSE)) == OK ? Qtrue : Qfalse; #endif }; @@ -756,6 +756,8 @@ rb_gc_mark_children(ptr) for (i=0; i < len; i++) rb_gc_mark(*ptr++); } + if (FL_TEST(obj, ELTS_SHARED)) + rb_gc_mark(obj->as.array.aux.shared); break; case T_HASH: @@ -764,8 +766,9 @@ rb_gc_mark_children(ptr) break; case T_STRING: - if (obj->as.string.orig) { - rb_gc_mark((VALUE)obj->as.string.orig); +#define STR_ASSOC FL_USER2 /* copied from string.c */ + if (FL_TEST(obj, ELTS_SHARED|STR_ASSOC)) { + rb_gc_mark(obj->as.string.aux.shared); } break; @@ -945,13 +948,12 @@ obj_free(obj) } break; case T_STRING: -#define STR_NO_ORIG FL_USER2 /* copied from string.c */ - if (!RANY(obj)->as.string.orig || FL_TEST(obj, STR_NO_ORIG)) { + if (RANY(obj)->as.string.ptr && !FL_TEST(obj, ELTS_SHARED)) { RUBY_CRITICAL(free(RANY(obj)->as.string.ptr)); } break; case T_ARRAY: - if (RANY(obj)->as.array.ptr) { + if (RANY(obj)->as.array.ptr && !FL_TEST(obj, ELTS_SHARED)) { RUBY_CRITICAL(free(RANY(obj)->as.array.ptr)); } break; @@ -18,6 +18,7 @@ #include "rubysig.h" #define HASH_DELETED FL_USER1 +#define HASH_PROC_DEFAULT FL_USER2 static void rb_hash_modify(hash) @@ -38,13 +39,13 @@ rb_hash_freeze(hash) VALUE rb_cHash; static VALUE envtbl; -static ID hash; +static ID id_hash, id_yield, id_default; VALUE rb_hash(obj) VALUE obj; { - return rb_funcall(obj, hash, 0); + return rb_funcall(obj, id_hash, 0); } static VALUE @@ -93,7 +94,7 @@ rb_any_hash(a) default: DEFER_INTS; - hval = rb_funcall(a, hash, 0); + hval = rb_funcall(a, id_hash, 0); if (FIXNUM_P(hval)) { hval %= 536870917; } @@ -198,9 +199,18 @@ rb_hash_initialize(argc, argv, hash) { VALUE ifnone; - rb_scan_args(argc, argv, "01", &ifnone); rb_hash_modify(hash); - RHASH(hash)->ifnone = ifnone; + if (rb_block_given_p()) { + if (argc > 1) { + rb_raise(rb_eArgError, "wrong number of arguments", argc); + } + RHASH(hash)->ifnone = rb_f_lambda(); + FL_SET(hash, HASH_PROC_DEFAULT); + } + else { + rb_scan_args(argc, argv, "01", &ifnone); + RHASH(hash)->ifnone = ifnone; + } return hash; } @@ -284,7 +294,7 @@ rb_hash_aref(hash, key) VALUE val; if (!st_lookup(RHASH(hash)->tbl, key, &val)) { - return RHASH(hash)->ifnone; + return rb_funcall(hash, id_default, 1, key); } return val; } @@ -316,9 +326,17 @@ rb_hash_fetch(argc, argv, hash) } static VALUE -rb_hash_default(hash) +rb_hash_default(argc, argv, hash) + int argc; + VALUE *argv; VALUE hash; { + VALUE key; + + rb_scan_args(argc, argv, "01", &key); + if (FL_TEST(hash, HASH_PROC_DEFAULT)) { + return rb_funcall(RHASH(hash)->ifnone, id_yield, 2, hash, key); + } return RHASH(hash)->ifnone; } @@ -328,6 +346,7 @@ rb_hash_set_default(hash, ifnone) { rb_hash_modify(hash); RHASH(hash)->ifnone = ifnone; + FL_UNSET(hash, HASH_PROC_DEFAULT); return hash; } @@ -392,7 +411,7 @@ rb_hash_delete(hash, key) if (rb_block_given_p()) { return rb_yield(key); } - return RHASH(hash)->ifnone; + return Qnil; } struct shift_var { @@ -1433,7 +1452,9 @@ env_reject() void Init_Hash() { - hash = rb_intern("hash"); + id_hash = rb_intern("hash"); + id_yield = rb_intern("yield"); + id_default = rb_intern("default"); rb_cHash = rb_define_class("Hash", rb_cObject); @@ -1456,7 +1477,7 @@ Init_Hash() rb_define_method(rb_cHash,"fetch", rb_hash_fetch, -1); rb_define_method(rb_cHash,"[]=", rb_hash_aset, 2); rb_define_method(rb_cHash,"store", rb_hash_aset, 2); - rb_define_method(rb_cHash,"default", rb_hash_default, 0); + rb_define_method(rb_cHash,"default", rb_hash_default, -1); rb_define_method(rb_cHash,"default=", rb_hash_set_default, 1); rb_define_method(rb_cHash,"index", rb_hash_index, 1); rb_define_method(rb_cHash,"indexes", rb_hash_indexes, -1); @@ -513,6 +513,10 @@ io_fread(ptr, len, f) eof: if (ferror(f)) { if (errno == EINTR) continue; + if (errno == EAGAIN) return len - n; +#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN + if (errno == EWOULDBLOCK) return len - n; +#endif rb_sys_fail(0); } *ptr = '\0'; @@ -2187,6 +2191,25 @@ rb_f_putc(recv, ch) return rb_io_putc(rb_defout, ch); } +static VALUE rb_io_puts _((int, VALUE*, VALUE)); + +static VALUE +io_puts_ary(ary, out) + VALUE ary, out; +{ + VALUE tmp; + int i; + + for (i=0; i<RARRAY(ary)->len; i++) { + tmp = RARRAY(ary)->ptr[i]; + if (rb_inspecting_p(tmp)) { + tmp = rb_str_new2("[...]"); + } + rb_io_puts(1, &tmp, out); + } + return Qnil; +} + static VALUE rb_io_puts(argc, argv, out) int argc; @@ -2206,11 +2229,11 @@ rb_io_puts(argc, argv, out) line = rb_str_new2("nil"); } else { -#if 0 - if (TYPE(argv[i]) == T_ARRAY) { - rb_warn("puts behavior changed for Array"); + line = rb_check_convert_type(argv[i], T_ARRAY, "Array", "to_ary"); + if (!NIL_P(line)) { + rb_protect_inspect(io_puts_ary, line, out); + continue; } -#endif line = rb_obj_as_string(argv[i]); } rb_io_write(out, line); @@ -313,7 +313,6 @@ rb_obj_freeze(obj) if (rb_safe_level() >= 4 && !OBJ_TAINTED(obj)) { rb_raise(rb_eSecurityError, "Insecure: can't freeze object"); } - OBJ_FREEZE(obj); } return obj; @@ -1292,7 +1291,7 @@ Init_Object() rb_undef_method(rb_cClass, "append_features"); rb_cData = rb_define_class("Data", rb_cObject); - rb_undef_method(CLASS_OF(rb_cData), "new"); + rb_undef_method(CLASS_OF(rb_cData), "allocate"); ruby_top_self = rb_obj_alloc(rb_cObject); rb_global_variable(&ruby_top_self); @@ -3938,6 +3938,10 @@ str_extend(list, term, paren) case '-': tokadd(c); c = nextc(); + if (!is_identchar(c)) { + pushback(); + goto invalid_interporate; + } tokadd(c); goto fetch_id; @@ -3956,9 +3960,14 @@ str_extend(list, term, paren) goto refetch; } if (!is_identchar(c)) { - yyerror("bad global variable in string"); - newtok(); - return list; + invalid_interporate: + { + VALUE s = rb_str_new2("#"); + rb_str_cat(s, tok(), toklen()); + list_append(list, NEW_STR(s)); + newtok(); + return list; + } } } @@ -3997,6 +4006,9 @@ str_extend(list, term, paren) c = nextc(); } pushback(c); + if (toklen() == 1) { + goto invalid_interporate; + } break; case '{': @@ -4264,7 +4276,9 @@ gettable(id) return NEW_FALSE(); } else if (id == k__FILE__) { - return NEW_STR(rb_str_new2(ruby_sourcefile)); + VALUE f = rb_str_new2(ruby_sourcefile); + OBJ_FREEZE(f); + return NEW_STR(f); } else if (id == k__LINE__) { return NEW_LIT(INT2FIX(ruby_sourceline)); @@ -477,7 +477,7 @@ re_set_syntax(syntax) } while(0) #define WC2MBC1ST(c) \ - ((c<0x100)?(c):((current_mbctype != MBCTYPE_UTF8)?(((c)>>8)&0xff):utf8_firstbyte(c))) + ((current_mbctype != MBCTYPE_UTF8) ? ((c<0x100) ? (c) : (((c)>>8)&0xff)) : utf8_firstbyte(c)) static unsigned int utf8_firstbyte(c) @@ -247,6 +247,10 @@ VALUE rb_newobj _((void)); rb_singleton_class_attached(RBASIC(clone)->klass, (VALUE)clone);\ if (FL_TEST(obj, FL_EXIVAR)) rb_copy_generic_ivar((VALUE)clone,(VALUE)obj);\ } while (0) +#define DUPSETUP(dup,obj) do {\ + OBJSETUP(dup,rb_obj_class(obj),(RBASIC(obj)->flags)&(T_MASK|FL_EXIVAR|FL_TAINT));\ + if (FL_TEST(obj, FL_EXIVAR)) rb_copy_generic_ivar((VALUE)dup,(VALUE)obj);\ +} while (0) struct RBasic { unsigned long flags; @@ -270,16 +274,25 @@ struct RFloat { double value; }; +#define ELTS_SHARED FL_USER2 + struct RString { struct RBasic basic; long len; char *ptr; - VALUE orig; + union { + int capa; + VALUE shared; + } aux; }; struct RArray { struct RBasic basic; - long len, capa; + long len; + union { + int capa; + VALUE shared; + } aux; VALUE *ptr; }; diff --git a/sample/test.rb b/sample/test.rb index 663a8695e1..a6ab98ca63 100644 --- a/sample/test.rb +++ b/sample/test.rb @@ -470,6 +470,18 @@ test_ok(($x * 0).join(":") == '') test_ok($x.size == 7) test_ok($x == [1, 2, 3, 4, 5, 6, 7]) +$x = [1,2,3] +$x[1,0] = $x +test_ok($x == [1,1,2,3,2,3]) + +$x = [1,2,3] +$x[-1,0] = $x +test_ok($x == [1,2,1,2,3,3]) + +$x = [1,2,3] +$x.concat($x) +test_ok($x == [1,2,3,1,2,3]) + test_check "hash" $x = {1=>2, 2=>4, 3=>6} $y = {1, 2, 2, 4, 3, 6} @@ -505,17 +517,40 @@ $z = [1,2] $y[$z] = 256 test_ok($y[$z] == 256) -$x = [1,2,3] -$x[1,0] = $x -test_ok($x == [1,1,2,3,2,3]) - -$x = [1,2,3] -$x[-1,0] = $x -test_ok($x == [1,2,1,2,3,3]) - -$x = [1,2,3] -$x.concat($x) -test_ok($x == [1,2,3,1,2,3]) +$x = Hash.new(0) +$x[1] = 1 +test_ok($x[1] == 1) +test_ok($x[2] == 0) + +$x = Hash.new([]) +test_ok($x[22] == []) +test_ok($x[22].equal?($x[22])) + +$x = Hash.new{[]} +test_ok($x[22] == []) +test_ok(!$x[22].equal?($x[22])) + +$x = Hash.new{|h,k| $z = k; h[k] = k*2} +$z = 0 +test_ok($x[22] == 44) +test_ok($z == 22) +$z = 0 +test_ok($x[22] == 44) +test_ok($z == 0) +$x.default = 5 +test_ok($x[23] == 5) + +$x = Hash.new +def $x.default(k) + $z = k + self[k] = k*2 +end +$z = 0 +test_ok($x[22] == 44) +test_ok($z == 22) +$z = 0 +test_ok($x[22] == 44) +test_ok($z == 0) test_check "iterator" @@ -27,7 +27,6 @@ VALUE rb_cString; -#define STR_NO_ORIG FL_USER2 #define STR_ASSOC FL_USER3 VALUE rb_fs; @@ -41,13 +40,13 @@ rb_str_s_alloc(klass) str->ptr = 0; str->len = 0; - str->orig = 0; + str->aux.capa = 0; return (VALUE)str; } -VALUE -rb_str_new0(klass, ptr, len) +static VALUE +str_new(klass, ptr, len) VALUE klass; const char *ptr; long len; @@ -55,6 +54,7 @@ rb_str_new0(klass, ptr, len) VALUE str = rb_obj_alloc(klass); RSTRING(str)->len = len; + RSTRING(str)->aux.capa = len; RSTRING(str)->ptr = ALLOC_N(char,len+1); if (ptr) { memcpy(RSTRING(str)->ptr, ptr, len); @@ -68,7 +68,7 @@ rb_str_new(ptr, len) const char *ptr; long len; { - return rb_str_new0(rb_cString, ptr, len); + return str_new(rb_cString, ptr, len); } VALUE @@ -99,51 +99,52 @@ rb_tainted_str_new2(ptr) return str; } -VALUE -rb_str_new3(str) - VALUE str; +static VALUE +str_new3(klass, str) + VALUE klass, str; { - VALUE str2 = rb_obj_alloc(rb_obj_class(str)); + VALUE str2 = rb_obj_alloc(klass); RSTRING(str2)->len = RSTRING(str)->len; RSTRING(str2)->ptr = RSTRING(str)->ptr; - RSTRING(str2)->orig = str; + 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); +} + +VALUE rb_str_new4(orig) VALUE orig; { - VALUE klass; + VALUE klass, str; klass = rb_obj_class(orig); - if (RSTRING(orig)->orig) { - VALUE str; - - if (FL_TEST(orig, STR_NO_ORIG)) { - str = rb_str_new0(klass, RSTRING(orig)->ptr, RSTRING(orig)->len); - } - else { - str = rb_str_new3(RSTRING(orig)->orig); - RBASIC(str)->klass = klass; - } - OBJ_FREEZE(str); - return str; + if (FL_TEST(orig, ELTS_SHARED)) { + str = str_new3(klass, RSTRING(orig)->aux.shared); + } + else if (FL_TEST(orig, STR_ASSOC)) { + str = str_new(klass, RSTRING(orig)->ptr, RSTRING(orig)->len); } else { - VALUE str = rb_obj_alloc(klass); + str = rb_obj_alloc(klass); RSTRING(str)->len = RSTRING(orig)->len; RSTRING(str)->ptr = RSTRING(orig)->ptr; - RSTRING(orig)->orig = str; - OBJ_INFECT(str, orig); - OBJ_FREEZE(str); - - return str; + RSTRING(orig)->aux.shared = str; + FL_SET(orig, ELTS_SHARED); } + OBJ_INFECT(str, orig); + OBJ_FREEZE(str); + return str; } VALUE @@ -152,7 +153,7 @@ rb_str_new5(obj, ptr, len) const char *ptr; long len; { - return rb_str_new0(rb_obj_class(obj), ptr, len); + return str_new(rb_obj_class(obj), ptr, len); } #define STR_BUF_MIN_SIZE 128 @@ -163,12 +164,11 @@ rb_str_buf_new(capa) { VALUE str = rb_obj_alloc(rb_cString); - FL_SET(str, STR_NO_ORIG); if (capa < STR_BUF_MIN_SIZE) capa = STR_BUF_MIN_SIZE; RSTRING(str)->ptr = 0; RSTRING(str)->len = 0; - RSTRING(str)->orig = LONG2FIX(capa); + RSTRING(str)->aux.capa = capa; RSTRING(str)->ptr = ALLOC_N(char, capa+1); RSTRING(str)->ptr[0] = '\0'; @@ -210,16 +210,23 @@ rb_str_become(str, str2) if (NIL_P(str2)) { RSTRING(str)->ptr = 0; RSTRING(str)->len = 0; - RSTRING(str)->orig = 0; + RSTRING(str)->aux.capa = 0; return; } - if ((!RSTRING(str)->orig||FL_TEST(str,STR_NO_ORIG))&&RSTRING(str)->ptr) - free(RSTRING(str)->ptr); + if (FL_TEST(str, ELTS_SHARED)) free(RSTRING(str)->ptr); RSTRING(str)->ptr = RSTRING(str2)->ptr; RSTRING(str)->len = RSTRING(str2)->len; - RSTRING(str)->orig = RSTRING(str2)->orig; + if (FL_TEST(str2, ELTS_SHARED|STR_ASSOC)) { + FL_SET(str, RBASIC(str2)->flags & (ELTS_SHARED|STR_ASSOC)); + RSTRING(str)->aux.shared = RSTRING(str2)->aux.shared; + } + else { + RSTRING(str)->aux.capa = RSTRING(str2)->aux.capa; + } RSTRING(str2)->ptr = 0; /* abandon str2 */ RSTRING(str2)->len = 0; + RSTRING(str2)->aux.capa = 0; + FL_UNSET(str, ELTS_SHARED|STR_ASSOC); if (OBJ_TAINTED(str2)) OBJ_TAINT(str); } @@ -227,22 +234,23 @@ void rb_str_associate(str, add) VALUE str, add; { - if (FL_TEST(str, STR_NO_ORIG|STR_ASSOC) != (STR_NO_ORIG|STR_ASSOC)) { - if (FL_TEST(str, STR_NO_ORIG)) { + if (FL_TEST(str, STR_ASSOC)) { + /* already associated */ + rb_ary_concat(RSTRING(str)->aux.shared, add); + } + else { + if (FL_TEST(str, ELTS_SHARED)) { + rb_str_modify(str); + } + else if (RSTRING(str)->aux.shared) { /* str_buf */ - if (FIX2LONG(RSTRING(str)->orig) != RSTRING(str)->len) { + if (RSTRING(str)->aux.capa != RSTRING(str)->len) { REALLOC_N(RSTRING(str)->ptr, char, RSTRING(str)->len + 1); } } - else if (RSTRING(str)->orig) { - rb_str_modify(str); - } - RSTRING(str)->orig = add; - FL_SET(str, STR_NO_ORIG|STR_ASSOC); - } - else { - /* already associated */ - rb_ary_concat(RSTRING(str)->orig, add); + RSTRING(str)->aux.shared = add; + FL_UNSET(str, ELTS_SHARED); + FL_SET(str, STR_ASSOC); } } @@ -250,10 +258,10 @@ VALUE rb_str_associated(str) VALUE str; { - if (FL_TEST(str, STR_NO_ORIG|STR_ASSOC) != (STR_NO_ORIG|STR_ASSOC)) { - return Qfalse; + if (FL_TEST(str, STR_ASSOC)) { + return RSTRING(str)->aux.shared; } - return RSTRING(str)->orig; + return Qfalse; } static ID id_to_s; @@ -274,45 +282,53 @@ rb_obj_as_string(obj) return str; } -VALUE -rb_str_dup(str) +static VALUE +str_copy(str, clone) VALUE str; + int clone; { VALUE str2; VALUE klass; + int flags; StringValue(str); - klass = rb_obj_class(str); - if (OBJ_FROZEN(str)) str2 = rb_str_new3(str); - else if (FL_TEST(str, STR_NO_ORIG)) { - str2 = rb_str_new0(klass, RSTRING(str)->ptr, RSTRING(str)->len); + if (FL_TEST(str, ELTS_SHARED)) { + str2 = rb_str_new3(RSTRING(str)->aux.shared); } - else if (RSTRING(str)->orig) { - str2 = rb_str_new3(RSTRING(str)->orig); - RBASIC(str2)->klass = klass; - FL_UNSET(str2, FL_TAINT); - OBJ_INFECT(str2, str); + else if (FL_TEST(str, STR_ASSOC)) { + str2 = str_new(RSTRING(str)->ptr, RSTRING(str)->len); + RSTRING(str2)->aux.shared = RSTRING(str)->aux.shared; + } + else if (OBJ_FROZEN(str)) { + str2 = rb_str_new3(str); } else { str2 = rb_str_new3(rb_str_new4(str)); } - if (FL_TEST(str, FL_EXIVAR)) - rb_copy_generic_ivar(str2, str); - OBJ_INFECT(str2, str); + flags = FL_TEST(str2, ELTS_SHARED|STR_ASSOC); + if (clone) { + CLONESETUP(str2, str); + } + else { + DUPSETUP(str2, str); + } + if (flags) FL_SET(str2, flags); return str2; } +VALUE +rb_str_dup(str) + VALUE str; +{ + return str_copy(str, Qfalse); +} + static VALUE rb_str_clone(str) VALUE str; { - VALUE clone = rb_str_dup(str); - if (FL_TEST(str, STR_NO_ORIG)) - RSTRING(clone)->orig = RSTRING(str)->orig; - CLONESETUP(clone, str); - - return clone; + return str_copy(str, Qtrue); } static VALUE rb_str_replace _((VALUE, VALUE)); @@ -446,9 +462,7 @@ str_independent(str) if (OBJ_FROZEN(str)) rb_error_frozen("string"); if (!OBJ_TAINTED(str) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't modify string"); - if (!RSTRING(str)->orig || FL_TEST(str, STR_NO_ORIG)) return 1; - if (RBASIC(str)->flags == 0) abort(); - if (TYPE(RSTRING(str)->orig) != T_STRING) rb_bug("non string str->orig"); + if (!FL_TEST(str, ELTS_SHARED)) return 1; return 0; } @@ -465,7 +479,8 @@ rb_str_modify(str) } ptr[RSTRING(str)->len] = 0; RSTRING(str)->ptr = ptr; - RSTRING(str)->orig = 0; + RSTRING(str)->aux.capa = RSTRING(str)->len; + FL_UNSET(str, ELTS_SHARED|STR_ASSOC); } VALUE @@ -479,9 +494,9 @@ VALUE rb_str_dup_frozen(str) VALUE str; { - if (RSTRING(str)->orig && !FL_TEST(str, STR_NO_ORIG)) { - OBJ_FREEZE(RSTRING(str)->orig); - return RSTRING(str)->orig; + if (FL_TEST(str, ELTS_SHARED)) { + OBJ_FREEZE(RSTRING(str)->aux.shared); + return RSTRING(str)->aux.shared; } if (OBJ_FROZEN(str)) return str; str = rb_str_dup(str); @@ -516,21 +531,17 @@ rb_str_buf_cat(str, ptr, len) { long i, capa, total; - if (RSTRING(str)->orig == 0) { - capa = RSTRING(str)->len; - FL_SET(str, STR_NO_ORIG); - } - else { - capa = FIX2LONG(RSTRING(str)->orig); + if (FL_TEST(str, ELTS_SHARED)) { + rb_str_modify(str); } - + capa = RSTRING(str)->aux.capa; total = RSTRING(str)->len+len; if (capa <= total) { while (total > capa) { capa = (capa + 1) * 2; } REALLOC_N(RSTRING(str)->ptr, char, capa+1); - RSTRING(str)->orig = LONG2FIX(capa); + RSTRING(str)->aux.capa = capa; } memcpy(RSTRING(str)->ptr + RSTRING(str)->len, ptr, len); RSTRING(str)->len = total; @@ -557,8 +568,7 @@ rb_str_cat(str, ptr, len) rb_str_modify(str); if (len > 0) { - if (RSTRING(str)->orig == 0 || - (FL_TEST(str, STR_NO_ORIG) && !FL_TEST(str, STR_ASSOC))) { + if (!FL_TEST(str, ELTS_SHARED) && !FL_TEST(str, STR_ASSOC)) { return rb_str_buf_cat(str, ptr, len); } REALLOC_N(RSTRING(str)->ptr, char, RSTRING(str)->len+len+1); @@ -589,13 +599,10 @@ rb_str_buf_append(str, str2) { long i, capa, len; - if (RSTRING(str)->orig == 0) { - capa = RSTRING(str)->len; - FL_SET(str, STR_NO_ORIG); - } - else { - capa = FIX2LONG(RSTRING(str)->orig); + if (FL_TEST(str, ELTS_SHARED)) { + rb_str_modify(str); } + capa = RSTRING(str)->aux.capa; len = RSTRING(str)->len+RSTRING(str2)->len; if (capa <= len) { @@ -603,7 +610,7 @@ rb_str_buf_append(str, str2) capa = (capa + 1) * 2; } REALLOC_N(RSTRING(str)->ptr, char, capa+1); - RSTRING(str)->orig = LONG2FIX(capa); + RSTRING(str)->aux.capa = capa; } memcpy(RSTRING(str)->ptr + RSTRING(str)->len, RSTRING(str2)->ptr, RSTRING(str2)->len); @@ -623,11 +630,9 @@ rb_str_append(str, str2) rb_str_modify(str); if (RSTRING(str2)->len > 0) { len = RSTRING(str)->len+RSTRING(str2)->len; - if (RSTRING(str)->orig == 0 || - (FL_TEST(str, STR_NO_ORIG) && !FL_TEST(str, STR_ASSOC))) { + if (!FL_TEST(str, ELTS_SHARED) && !FL_TEST(str, STR_ASSOC)) { rb_str_buf_append(str, str2); OBJ_INFECT(str, str2); - return str; } REALLOC_N(RSTRING(str)->ptr, char, len+1); @@ -810,6 +815,13 @@ rb_str_match2(str) return rb_reg_match2(rb_reg_regcomp(str)); } +static VALUE +rb_str_match_m(str, re) + VALUE str, re; +{ + return rb_funcall(re, rb_intern("match"), 1, str); +} + static long rb_str_index(str, sub, offset) VALUE str, sub; @@ -1529,20 +1541,18 @@ str_gsub(argc, argv, str, bang) if (str_independent(str)) { free(RSTRING(str)->ptr); } - else { - RSTRING(str)->orig = 0; - } + FL_UNSET(str, ELTS_SHARED|STR_ASSOC); } else { VALUE dup = rb_obj_alloc(rb_obj_class(str)); OBJ_INFECT(dup, str); str = dup; - RSTRING(dup)->orig = 0; } RSTRING(str)->ptr = buf; RSTRING(str)->len = len = bp - buf; RSTRING(str)->ptr[len] = '\0'; + RSTRING(str)->aux.capa = len; if (tainted) OBJ_TAINT(str); return str; @@ -1573,13 +1583,19 @@ rb_str_replace(str, str2) if (str == str2) return str; StringValue(str2); - if (RSTRING(str2)->orig && !FL_TEST(str2, STR_NO_ORIG)) { + if (FL_TEST(str2, ELTS_SHARED)) { if (str_independent(str)) { free(RSTRING(str)->ptr); } RSTRING(str)->len = RSTRING(str2)->len; RSTRING(str)->ptr = RSTRING(str2)->ptr; - RSTRING(str)->orig = RSTRING(str2)->orig; + if (FL_TEST(str2, ELTS_SHARED|STR_ASSOC)) { + FL_SET(str, RBASIC(str2)->flags & (ELTS_SHARED|STR_ASSOC)); + RSTRING(str)->aux.shared = RSTRING(str2)->aux.shared; + } + else { + RSTRING(str)->aux.capa = RSTRING(str2)->aux.capa; + } } else { rb_str_modify(str); @@ -3113,6 +3129,7 @@ Init_String() rb_define_method(rb_cString, "empty?", rb_str_empty, 0); rb_define_method(rb_cString, "=~", rb_str_match, 1); rb_define_method(rb_cString, "~", rb_str_match2, 0); + rb_define_method(rb_cString, "match", rb_str_match_m, 1); rb_define_method(rb_cString, "succ", rb_str_succ, 0); rb_define_method(rb_cString, "succ!", rb_str_succ_bang, 0); rb_define_method(rb_cString, "next", rb_str_succ, 0); @@ -72,9 +72,9 @@ time_new_internal(klass, sec, usec) sec += usec / 1000000; usec %= 1000000; } - if (usec < 0) { /* usec underflow */ - sec -= (-usec) / 1000000; - usec %= 1000000; + while (usec < 0) { /* usec underflow */ + sec--; + usec += 1000000; } #ifndef NEGATIVE_TIME_T if (sec < 0 || (sec == 0 && usec < 0)) @@ -643,7 +643,13 @@ time_cmp(time1, time2) return INT2FIX(-1); } i = NUM2LONG(time2); - if (tobj1->tv.tv_sec == i) return INT2FIX(0); + if (tobj1->tv.tv_sec == i) { + if (tobj1->tv.tv_usec == 0) + return INT2FIX(0); + if (tobj1->tv.tv_usec > 0) + return INT2FIX(1); + return INT2FIX(-1); + } if (tobj1->tv.tv_sec > i) return INT2FIX(1); return INT2FIX(-1); } @@ -760,6 +766,35 @@ time_gmtime(time) } static VALUE +time_dup(time) + VALUE time; +{ + VALUE clone; + struct time_object *tobj, *tclone; + + GetTimeval(time, tobj); + clone = Data_Make_Struct(0, struct time_object, 0, free, tclone); + DUPSETUP(clone, time); + MEMCPY(tclone, tobj, struct time_object, 1); + + return clone; +} + +static VALUE +time_getlocaltime(time) + VALUE time; +{ + return time_localtime(time_dup(time)); +} + +static VALUE +time_getgmtime(time) + VALUE time; +{ + return time_gmtime(time_dup(time)); +} + +static VALUE time_get_tm(time, gmt) VALUE time; int gmt; @@ -1071,7 +1106,7 @@ rb_strftime(buf, format, time) * if the buffer is 1024 times bigger than the length of the * format string, it's not failing for lack of room. */ - if (len > 0 || len >= 1024 * flen) return len; + if (len > 0 || size >= 1024 * flen) return len; free(*buf); } /* not reached */ @@ -1109,7 +1144,10 @@ time_strftime(time, format) p += strlen(p) + 1; if (p <= pe) rb_str_cat(str, "\0", 1); - if (len > SMALLBUF) free(buf); + if (buf != buffer) { + free(buf); + buf = buffer; + } } return str; } @@ -1231,10 +1269,15 @@ Init_Time() rb_define_method(rb_cTime, "eql?", time_eql, 1); rb_define_method(rb_cTime, "hash", time_hash, 0); rb_define_method(rb_cTime, "clone", time_clone, 0); + rb_define_method(rb_cTime, "dup", time_dup, 0); rb_define_method(rb_cTime, "localtime", time_localtime, 0); rb_define_method(rb_cTime, "gmtime", time_gmtime, 0); rb_define_method(rb_cTime, "utc", time_gmtime, 0); + rb_define_method(rb_cTime, "getlocal", time_getlocaltime, 0); + rb_define_method(rb_cTime, "getgm", time_getgmtime, 0); + rb_define_method(rb_cTime, "getutc", time_getgmtime, 0); + rb_define_method(rb_cTime, "ctime", time_asctime, 0); rb_define_method(rb_cTime, "asctime", time_asctime, 0); rb_define_method(rb_cTime, "to_s", time_to_s, 0); @@ -384,31 +384,25 @@ __crt0_glob_function(char *path) /* mm.c */ -static int mmkind, mmsize, high, low; - #define A ((int*)a) #define B ((int*)b) #define C ((int*)c) #define D ((int*)d) -static void mmprepare(base, size) void *base; int size; -{ -#ifdef DEBUG - if (sizeof(int) != 4) die("sizeof(int) != 4"); - if (size <= 0) die("mmsize <= 0"); -#endif +#define mmprepare(base, size) do {\ + if (((long)base & (0x3)) == 0)\ + if (size >= 16) mmkind = 1;\ + else mmkind = 0;\ + else mmkind = -1;\ + high = (size & (~0xf));\ + low = (size & 0x0c);\ +} while (0)\ - if (((long)base & (4-1)) == 0 && ((long)base & (4-1)) == 0) - if (size >= 16) mmkind = 1; - else mmkind = 0; - else mmkind = -1; - - mmsize = size; - high = (size & (-16)); - low = (size & 0x0c); -} +#define mmarg mmkind, size, high, low -static void mmswap(a, b) register char *a, *b; +static void mmswap_(a, b, mmarg) + register char *a, *b; + int mmarg; { register int s; if (a == b) return; @@ -427,12 +421,15 @@ static void mmswap(a, b) register char *a, *b; if (low == 12) {s = A[2]; A[2] = B[2]; B[2] = s;}}} } else { - register char *t = a + mmsize; + register char *t = a + size; do {s = *a; *a++ = *b; *b++ = s;} while (a < t); } } +#define mmswap(a,b) mmswap_((a),(b),mmarg) -static void mmrot3(a, b, c) register char *a, *b, *c; +static void mmrot3_(a, b, c, mmarg) + register char *a, *b, *c; + int mmarg; { register int s; if (mmkind >= 0) { @@ -450,10 +447,11 @@ static void mmrot3(a, b, c) register char *a, *b, *c; if (low == 12) {s = A[2]; A[2] = B[2]; B[2] = C[2]; C[2] = s;}}} } else { - register char *t = a + mmsize; + register char *t = a + size; do {s = *a; *a++ = *b; *b++ = *c; *c++ = s;} while (a < t); } } +#define mmrot3(a,b,c) mmrot3_((a),(b),(c),mmarg) /* qs6.c */ /*****************************************************/ @@ -472,14 +470,19 @@ typedef struct { char *LL, *RR; } stack_node; /* Stack structure for L,l,R,r */ ((*cmp)(b,c)<0 ? b : ((*cmp)(a,c)<0 ? c : a)) : \ ((*cmp)(b,c)>0 ? b : ((*cmp)(a,c)<0 ? a : c))) -void ruby_qsort (base, nel, size, cmp) void* base; int nel; int size; int (*cmp)(); +void ruby_qsort (base, nel, size, cmp) + void* base; + const int nel; + const int size; + int (*cmp)(); { register char *l, *r, *m; /* l,r:left,right group m:median point */ register int t, eq_l, eq_r; /* eq_l: all items in left group are equal to S */ char *L = base; /* left end of curren region */ - char *R = (char*)base + size*(nel-1); /* right end of current region */ - int chklim = 63; /* threshold of ordering element check */ - stack_node stack[32], *top = stack; /* 32 is enough for 32bit CPU */ + char *R = (char*)base + size*(nel-1); /* right end of current region */ + int chklim = 63; /* threshold of ordering element check */ + stack_node stack[32], *top = stack; /* 32 is enough for 32bit CPU */ + int mmkind, high, low; if (nel <= 1) return; /* need not to sort */ mmprepare(base, size); @@ -491,7 +494,9 @@ void ruby_qsort (base, nel, size, cmp) void* base; int nel; int size; int (*cmp) for (;;) { start: - if (L + size == R) {if ((*cmp)(L,R) > 0) mmswap(L,R); goto nxt;}/* 2 elements */ + if (L + size == R) { /* 2 elements */ + if ((*cmp)(L,R) > 0) mmswap(L,R); goto nxt; + } l = L; r = R; t = (r - l + size) / size; /* number of elements */ @@ -559,7 +564,7 @@ void ruby_qsort (base, nel, size, cmp) void* base; int nel; int size; int (*cmp) if ((t = (*cmp)(m,r)) < 0) {goto loopA;} /*5-5-7*/ if (t > 0) {mmswap(l,r); goto loopB;} /*5-5-3*/ - /* deteming splitting type in case 5-5-5 */ /*5-5-5*/ + /* determining splitting type in case 5-5-5 */ /*5-5-5*/ for (;;) { if ((l += size) == r) goto nxt; /*5-5-5*/ if (l == m) continue; @@ -1,4 +1,4 @@ #define RUBY_VERSION "1.7.2" -#define RUBY_RELEASE_DATE "2001-12-09" +#define RUBY_RELEASE_DATE "2001-12-10" #define RUBY_VERSION_CODE 172 -#define RUBY_RELEASE_CODE 20011209 +#define RUBY_RELEASE_CODE 20011210 |