summaryrefslogtreecommitdiff
path: root/array.c
diff options
context:
space:
mode:
authormatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-07-03 18:14:33 +0000
committermatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-07-03 18:14:33 +0000
commit9d9986d25cc08e68afadacdfec7ebb57f8e26251 (patch)
tree21a3fd6942126f5f2fcb89988a272d1872687258 /array.c
parente97228092110119cd4c1d9ab7af92a143ce9f3e0 (diff)
* 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. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@23951 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'array.c')
-rw-r--r--array.c123
1 files changed, 91 insertions, 32 deletions
diff --git a/array.c b/array.c
index cb37a2ead7..059574026c 100644
--- a/array.c
+++ b/array.c
@@ -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
@@ -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;
}