ruby-changes:12262
From: matz <ko1@a...>
Date: Sat, 4 Jul 2009 03:14:52 +0900 (JST)
Subject: [ruby-changes:12262] Ruby:r23951 (trunk): * enum.c (enum_join): add Enumerable#join.
matz 2009-07-04 03:14:33 +0900 (Sat, 04 Jul 2009) New Revision: 23951 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=23951 Log: * enum.c (enum_join): add Enumerable#join. * array.c (ary_join_1): recursive join for Enumerators (and objects with #to_a). * array.c (rb_ary_join): performance tune. Modified files: trunk/ChangeLog trunk/array.c trunk/enum.c Index: array.c =================================================================== --- array.c (revision 23950) +++ array.c (revision 23951) @@ -1519,66 +1519,125 @@ extern VALUE rb_output_fs; +static void ary_join_1(VALUE ary, VALUE sep, long i, VALUE result); + static VALUE -recursive_join(VALUE ary, VALUE argp, int recur) +recursive_join(VALUE obj, VALUE argp, int recur) { VALUE *arg = (VALUE *)argp; + VALUE ary = arg[0]; + VALUE sep = arg[1]; + VALUE result = arg[2]; + if (recur) { - return rb_usascii_str_new2("[...]"); + rb_str_buf_cat_ascii(result, "[...]"); } - return rb_ary_join(arg[0], arg[1]); + else { + ary_join_1(ary, sep, 0, result); + } + return Qnil; } +static void +ary_join_0(VALUE ary, VALUE sep, long max, VALUE result) +{ + long i; + VALUE val; + + for (i=0; i<max; i++) { + val = RARRAY_PTR(ary)[i]; + if (i > 0 && !NIL_P(sep)) + rb_str_buf_append(result, sep); + rb_str_buf_append(result, val); + if (OBJ_TAINTED(val)) OBJ_TAINT(result); + if (OBJ_UNTRUSTED(val)) OBJ_TAINT(result); + } +} + +static void +ary_join_1(VALUE ary, VALUE sep, long i, VALUE result) +{ + VALUE val, tmp; + + for (; i<RARRAY_LEN(ary); i++) { + if (i > 0 && !NIL_P(sep)) + rb_str_buf_append(result, sep); + + val = RARRAY_PTR(ary)[i]; + switch (TYPE(val)) { + case T_STRING: + str_join: + rb_str_buf_append(result, val); + break; + case T_ARRAY: + ary_join: + if (val == ary) { + val = rb_usascii_str_new2("[...]"); + goto str_join; + } + else { + VALUE args[3]; + + args[0] = val; + args[1] = sep; + args[2] = result; + rb_exec_recursive(recursive_join, ary, (VALUE)args); + } + break; + default: + tmp = rb_check_string_type(val); + if (!NIL_P(tmp)) { + val = tmp; + goto str_join; + } + tmp = rb_check_convert_type(val, T_ARRAY, "Array", "to_a"); + if (!NIL_P(tmp)) { + val = tmp; + goto ary_join; + } + val = rb_obj_as_string(val); + goto str_join; + } + } +} + VALUE rb_ary_join(VALUE ary, VALUE sep) { long len = 1, i; int taint = Qfalse; int untrust = Qfalse; - VALUE result, tmp; + VALUE val, tmp, result; if (RARRAY_LEN(ary) == 0) return rb_str_new(0, 0); if (OBJ_TAINTED(ary) || OBJ_TAINTED(sep)) taint = Qtrue; if (OBJ_UNTRUSTED(ary) || OBJ_UNTRUSTED(sep)) untrust = Qtrue; - for (i=0; i<RARRAY_LEN(ary); i++) { - tmp = rb_check_string_type(RARRAY_PTR(ary)[i]); - len += NIL_P(tmp) ? 10 : RSTRING_LEN(tmp); - } if (!NIL_P(sep)) { StringValue(sep); len += RSTRING_LEN(sep) * (RARRAY_LEN(ary) - 1); } - result = rb_str_buf_new(len); for (i=0; i<RARRAY_LEN(ary); i++) { - tmp = RARRAY_PTR(ary)[i]; - switch (TYPE(tmp)) { - case T_STRING: - break; - case T_ARRAY: - if (tmp == ary) { - tmp = rb_usascii_str_new2("[...]"); - } - else { - VALUE args[2]; + val = RARRAY_PTR(ary)[i]; + tmp = rb_check_string_type(val); - args[0] = tmp; - args[1] = sep; - tmp = rb_exec_recursive(recursive_join, ary, (VALUE)args); - } - break; - default: - tmp = rb_obj_as_string(tmp); + if (NIL_P(tmp) || tmp != val) { + result = rb_str_buf_new(len + (RARRAY_LEN(ary)-i)*10); + if (taint) OBJ_TAINT(result); + if (untrust) OBJ_UNTRUST(result); + ary_join_0(ary, sep, i, result); + ary_join_1(ary, sep, i, result); + return result; } - if (i > 0 && !NIL_P(sep)) - rb_str_buf_append(result, sep); - rb_str_buf_append(result, tmp); - if (OBJ_TAINTED(tmp)) taint = Qtrue; - if (OBJ_UNTRUSTED(tmp)) untrust = Qtrue; + + len += RSTRING_LEN(tmp); } + result = rb_str_buf_new(len); if (taint) OBJ_TAINT(result); if (untrust) OBJ_UNTRUST(result); + ary_join_0(ary, sep, RARRAY_LEN(ary), result); + return result; } Index: ChangeLog =================================================================== --- ChangeLog (revision 23950) +++ ChangeLog (revision 23951) @@ -79,6 +79,15 @@ * enum.c (enum_grep): gets rid of type-punning calls. +Wed Jul 1 06:36:28 2009 Yukihiro Matsumoto <matz@r...> + + * enum.c (enum_join): add Enumerable#join. + + * array.c (ary_join_1): recursive join for Enumerators (and + objects with #to_a). + + * array.c (rb_ary_join): performance tune. + Tue Jun 30 18:19:07 2009 Yukihiro Matsumoto <matz@r...> * hash.c (rb_hash_hash): documentation fix. a patch from Index: enum.c =================================================================== --- enum.c (revision 23950) +++ enum.c (revision 23951) @@ -1803,6 +1803,17 @@ return Qnil; /* not reached */ } +static VALUE +enum_join(int argc, VALUE *argv, VALUE obj) +{ + VALUE sep; + + rb_scan_args(argc, argv, "01", &sep); + if (NIL_P(sep)) sep = rb_output_fs; + + return rb_ary_join(enum_to_a(0, 0, obj), sep); +} + /* * The <code>Enumerable</code> mixin provides collection classes with * several traversal and searching methods, and with the ability to @@ -1862,6 +1873,7 @@ rb_define_method(rb_mEnumerable, "drop", enum_drop, 1); rb_define_method(rb_mEnumerable, "drop_while", enum_drop_while, 0); rb_define_method(rb_mEnumerable, "cycle", enum_cycle, -1); + rb_define_method(rb_mEnumerable, "join", enum_join, -1); id_eqq = rb_intern("==="); id_each = rb_intern("each"); -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/