49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
# File 'ext/efficient_join/efficient_join.c', line 49
VALUE rb_efficient_join(VALUE self, VALUE _header, VALUE _footer, VALUE _item_prefix, VALUE _item_suffix, VALUE _join, VALUE number_array) {
VALUE out;
const long array_len = RARRAY_LEN(number_array);
const char* header = StringValuePtr(_header);
const char* footer = StringValuePtr(_footer);
const char* item_prefix = StringValuePtr(_item_prefix);
const char* item_suffix = StringValuePtr(_item_suffix);
const char* join = StringValuePtr(_join);
VALUE *c_array = RARRAY_PTR(number_array);
const size_t prefix_len = RSTRING_LEN(_item_prefix);
const size_t suffix_len = RSTRING_LEN(_item_suffix);
const size_t join_len = RSTRING_LEN(_join);
struct strbuf_t join_buf = strbuf_new(suffix_len + join_len + prefix_len);
// estimate likely maximum buffer size, to avoid reallocs
struct strbuf_t buf = strbuf_new((array_len + 1) * (join_buf.pos + 10));
// build joining string
strbuf_write_str(&join_buf, item_suffix, suffix_len);
strbuf_write_str(&join_buf, join, join_len);
strbuf_write_str(&join_buf, item_prefix, prefix_len);
strbuf_write_str(&buf, header, RSTRING_LEN(_header));
strbuf_write_str(&buf, item_prefix, prefix_len);
for (long i=0; i<array_len; ++i) {
VALUE v = c_array[i];
switch (TYPE(v)) {
case T_FIXNUM:
strbuf_write_int64(&buf, FIX2LONG(v));
break;
case T_BIGNUM:
strbuf_write_int64(&buf, rb_big2ll(v));
break;
case T_STRING:
strbuf_write_str(&buf, StringValuePtr(v), RSTRING_LEN(v));
break;
default:
// rb_raise does not return control, so clean up first
strbuf_free(&join_buf);
strbuf_free(&buf);
rb_raise(rb_eTypeError, "array must contain only strings and integers");
}
if (i < array_len - 1) {
strbuf_write_str(&buf, join_buf.buf, join_buf.pos);
}
}
strbuf_write_str(&buf, item_suffix, suffix_len);
strbuf_write_str(&buf, footer, RSTRING_LEN(_footer));
out = rb_str_new(buf.buf, buf.pos);
strbuf_free(&join_buf);
strbuf_free(&buf);
return out;
}
|