Skip to content

Commit

Permalink
* enum.c (enum_join): add Enumerable#join.
Browse files Browse the repository at this point in the history
* array.c (ary_join_1): recursive join for Enumerators (and
  objects with #to_a).

* array.c (rb_ary_join): performance tune.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@23951 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
  • Loading branch information
matz committed Jul 3, 2009
1 parent e972280 commit 9d9986d
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 32 deletions.
9 changes: 9 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,15 @@ Wed Jul 1 06:47:09 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>

* enum.c (enum_grep): gets rid of type-punning calls.

Wed Jul 1 06:36:28 2009 Yukihiro Matsumoto <matz@ruby-lang.org>

* 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@ruby-lang.org>

* hash.c (rb_hash_hash): documentation fix. a patch from
Expand Down
123 changes: 91 additions & 32 deletions array.c
Original file line number Diff line number Diff line change
Expand Up @@ -1519,14 +1519,86 @@ rb_ary_resurrect(VALUE ary)

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, "[...]");
}
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;
}
}
return rb_ary_join(arg[0], arg[1]);
}

VALUE
Expand All @@ -1535,50 +1607,37 @@ 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];

args[0] = tmp;
args[1] = sep;
tmp = rb_exec_recursive(recursive_join, ary, (VALUE)args);
}
break;
default:
tmp = rb_obj_as_string(tmp);
val = RARRAY_PTR(ary)[i];
tmp = rb_check_string_type(val);

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;
}

Expand Down
12 changes: 12 additions & 0 deletions enum.c
Original file line number Diff line number Diff line change
Expand Up @@ -1803,6 +1803,17 @@ enum_cycle(int argc, VALUE *argv, VALUE obj)
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
Expand Down Expand Up @@ -1862,6 +1873,7 @@ Init_Enumerable(void)
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");
Expand Down

0 comments on commit 9d9986d

Please sign in to comment.