summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--mrbgems/mruby-string-ext/mrblib/string.rb94
-rw-r--r--mrbgems/mruby-string-ext/src/string.c211
-rw-r--r--mrblib/array.rb32
-rw-r--r--src/array.c3
-rw-r--r--src/backtrace.c1
-rw-r--r--src/gc.c2
-rw-r--r--src/vm.c2
-rw-r--r--test/t/array.rb7
8 files changed, 152 insertions, 200 deletions
diff --git a/mrbgems/mruby-string-ext/mrblib/string.rb b/mrbgems/mruby-string-ext/mrblib/string.rb
index 0da84daed..27ca30610 100644
--- a/mrbgems/mruby-string-ext/mrblib/string.rb
+++ b/mrbgems/mruby-string-ext/mrblib/string.rb
@@ -365,4 +365,98 @@ class String
self[0, 0] = arg
self
end
+
+ ##
+ # call-seq:
+ # string.lines -> array of string
+ # string.lines {|s| block} -> array of string
+ #
+ # Returns strings per line;
+ #
+ # a = "abc\ndef"
+ # a.lines #=> ["abc\n", "def"]
+ #
+ # If a block is given, it works the same as <code>each_line</code>.
+ def lines(&blk)
+ lines = self.__lines
+ if blk
+ lines.each do |line|
+ blk.call(line)
+ end
+ end
+ lines
+ end
+
+ ##
+ # call-seq:
+ # str.upto(other_str, exclusive=false) {|s| block } -> str
+ # str.upto(other_str, exclusive=false) -> an_enumerator
+ #
+ # Iterates through successive values, starting at <i>str</i> and
+ # ending at <i>other_str</i> inclusive, passing each value in turn to
+ # the block. The <code>String#succ</code> method is used to generate
+ # each value. If optional second argument exclusive is omitted or is false,
+ # the last value will be included; otherwise it will be excluded.
+ #
+ # If no block is given, an enumerator is returned instead.
+ #
+ # "a8".upto("b6") {|s| print s, ' ' }
+ # for s in "a8".."b6"
+ # print s, ' '
+ # end
+ #
+ # <em>produces:</em>
+ #
+ # a8 a9 b0 b1 b2 b3 b4 b5 b6
+ # a8 a9 b0 b1 b2 b3 b4 b5 b6
+ #
+ # If <i>str</i> and <i>other_str</i> contains only ascii numeric characters,
+ # both are recognized as decimal numbers. In addition, the width of
+ # string (e.g. leading zeros) is handled appropriately.
+ #
+ # "9".upto("11").to_a #=> ["9", "10", "11"]
+ # "25".upto("5").to_a #=> []
+ # "07".upto("11").to_a #=> ["07", "08", "09", "10", "11"]
+ def upto(max, exclusive=false, &block)
+ return to_enum(:upto, max, exclusive) unless block
+ raise TypeError, "no implicit conversion of #{max.class} into String" unless max.kind_of? String
+
+ len = self.length
+ maxlen = max.length
+ # single character
+ if len == 1 and maxlen == 1
+ c = self.ord
+ e = max.ord
+ while c <= e
+ break if exclusive and c == e
+ yield c.chr
+ c += 1
+ end
+ return self
+ end
+ # both edges are all digits
+ bi = self.to_i(10)
+ ei = max.to_i(10)
+ len = self.length
+ if (bi > 0 or bi == "0"*len) and (ei > 0 or ei == "0"*maxlen)
+ while bi <= ei
+ break if exclusive and bi == ei
+ s = bi.to_s
+ s = s.rjust(len, "0") if s.length < len
+ yield s
+ bi += 1
+ end
+ return self
+ end
+ bs = self
+ while true
+ n = (bs <=> max)
+ break if n > 0
+ break if exclusive and n == 0
+ yield bs
+ break if n == 0
+ bs = bs.succ
+ end
+ self
+ end
end
diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c
index 45e8bb4ff..4cab49094 100644
--- a/mrbgems/mruby-string-ext/src/string.c
+++ b/mrbgems/mruby-string-ext/src/string.c
@@ -309,60 +309,6 @@ mrb_fixnum_chr(mrb_state *mrb, mrb_value num)
/*
* call-seq:
- * string.lines -> array of string
- *
- * Returns strings per line;
- *
- * a = "abc\ndef"
- * a.lines #=> ["abc\n", "def"]
- */
-static mrb_value
-mrb_str_lines(mrb_state *mrb, mrb_value self)
-{
- mrb_value result;
- mrb_value blk;
- int ai;
- mrb_int len;
- mrb_value arg;
- char *b = RSTRING_PTR(self);
- char *p = b, *t;
- char *e = b + RSTRING_LEN(self);
-
- mrb_get_args(mrb, "&", &blk);
-
- result = mrb_ary_new(mrb);
- ai = mrb_gc_arena_save(mrb);
- if (!mrb_nil_p(blk)) {
- while (p < e) {
- t = p;
- while (p < e && *p != '\n') p++;
- if (*p == '\n') p++;
- len = (mrb_int) (p - t);
- arg = mrb_str_new(mrb, t, len);
- mrb_yield_argv(mrb, blk, 1, &arg);
- mrb_gc_arena_restore(mrb, ai);
- if (b != RSTRING_PTR(self)) {
- ptrdiff_t diff = p - b;
- b = RSTRING_PTR(self);
- p = b + diff;
- }
- e = b + RSTRING_LEN(self);
- }
- return self;
- }
- while (p < e) {
- t = p;
- while (p < e && *p != '\n') p++;
- if (*p == '\n') p++;
- len = (mrb_int) (p - t);
- mrb_ary_push(mrb, result, mrb_str_new(mrb, t, len));
- mrb_gc_arena_restore(mrb, ai);
- }
- return result;
-}
-
-/*
- * call-seq:
* string.succ -> string
*
* Returns next sequence of the string;
@@ -524,135 +470,6 @@ mrb_str_ord(mrb_state* mrb, mrb_value str)
}
#endif
-static mrb_bool
-all_digits_p(const char *s, mrb_int len)
-{
- while (len-- > 0) {
- if (!ISDIGIT(*s)) return FALSE;
- s++;
- }
- return TRUE;
-}
-
-/*
- * call-seq:
- * str.upto(other_str, exclusive=false) {|s| block } -> str
- * str.upto(other_str, exclusive=false) -> an_enumerator
- *
- * Iterates through successive values, starting at <i>str</i> and
- * ending at <i>other_str</i> inclusive, passing each value in turn to
- * the block. The <code>String#succ</code> method is used to generate
- * each value. If optional second argument exclusive is omitted or is false,
- * the last value will be included; otherwise it will be excluded.
- *
- * If no block is given, an enumerator is returned instead.
- *
- * "a8".upto("b6") {|s| print s, ' ' }
- * for s in "a8".."b6"
- * print s, ' '
- * end
- *
- * <em>produces:</em>
- *
- * a8 a9 b0 b1 b2 b3 b4 b5 b6
- * a8 a9 b0 b1 b2 b3 b4 b5 b6
- *
- * If <i>str</i> and <i>other_str</i> contains only ascii numeric characters,
- * both are recognized as decimal numbers. In addition, the width of
- * string (e.g. leading zeros) is handled appropriately.
- *
- * "9".upto("11").to_a #=> ["9", "10", "11"]
- * "25".upto("5").to_a #=> []
- * "07".upto("11").to_a #=> ["07", "08", "09", "10", "11"]
- */
-static mrb_value
-mrb_str_upto(mrb_state *mrb, mrb_value beg)
-{
- mrb_value end;
- mrb_value exclusive = mrb_false_value();
- mrb_value block = mrb_nil_value();
- mrb_value current, after_end;
- mrb_int n;
- mrb_bool excl;
-
- mrb_get_args(mrb, "o|o&", &end, &exclusive, &block);
-
- if (mrb_nil_p(block)) {
- return mrb_funcall(mrb, beg, "to_enum", 3, mrb_symbol_value(mrb_intern_lit(mrb, "upto")), end, exclusive);
- }
- end = mrb_string_type(mrb, end);
- excl = mrb_test(exclusive);
-
- /* single character */
- if (RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1 &&
- ISASCII(RSTRING_PTR(beg)[0]) && ISASCII(RSTRING_PTR(end)[0])) {
- char c = RSTRING_PTR(beg)[0];
- char e = RSTRING_PTR(end)[0];
- int ai = mrb_gc_arena_save(mrb);
-
- if (c > e || (excl && c == e)) return beg;
- for (;;) {
- mrb_yield(mrb, block, mrb_str_new(mrb, &c, 1));
- mrb_gc_arena_restore(mrb, ai);
- if (!excl && c == e) break;
- c++;
- if (excl && c == e) break;
- }
- return beg;
- }
- /* both edges are all digits */
- if (ISDIGIT(RSTRING_PTR(beg)[0]) && ISDIGIT(RSTRING_PTR(end)[0]) &&
- all_digits_p(RSTRING_PTR(beg), RSTRING_LEN(beg)) &&
- all_digits_p(RSTRING_PTR(end), RSTRING_LEN(end))) {
- mrb_int min_width = RSTRING_LEN(beg);
- mrb_int bi = mrb_int(mrb, mrb_str_to_inum(mrb, beg, 10, FALSE));
- mrb_int ei = mrb_int(mrb, mrb_str_to_inum(mrb, end, 10, FALSE));
- int ai = mrb_gc_arena_save(mrb);
-
- while (bi <= ei) {
- mrb_value ns, str;
-
- if (excl && bi == ei) break;
- ns = mrb_format(mrb, "%S", mrb_fixnum_value(bi));
- if (min_width > RSTRING_LEN(ns)) {
- str = mrb_str_new(mrb, NULL, min_width);
- memset(RSTRING_PTR(str), '0', min_width-RSTRING_LEN(ns));
- memcpy(RSTRING_PTR(str)+min_width-RSTRING_LEN(ns),
- RSTRING_PTR(ns), RSTRING_LEN(ns));
- }
- else {
- str = ns;
- }
- mrb_yield(mrb, block, str);
- mrb_gc_arena_restore(mrb, ai);
- bi++;
- }
-
- return beg;
- }
- /* normal case */
- n = mrb_int(mrb, mrb_funcall(mrb, beg, "<=>", 1, end));
- if (n > 0 || (excl && n == 0)) return beg;
-
- after_end = mrb_funcall(mrb, end, "succ", 0);
- current = mrb_str_dup(mrb, beg);
- while (!mrb_str_equal(mrb, current, after_end)) {
- int ai = mrb_gc_arena_save(mrb);
- mrb_value next = mrb_nil_value();
- if (excl || !mrb_str_equal(mrb, current, end))
- next = mrb_funcall(mrb, current, "succ", 0);
- mrb_yield(mrb, block, current);
- if (mrb_nil_p(next)) break;
- current = mrb_str_to_str(mrb, next);
- if (excl && mrb_str_equal(mrb, current, end)) break;
- if (RSTRING_LEN(current) > RSTRING_LEN(end) || RSTRING_LEN(current) == 0)
- break;
- mrb_gc_arena_restore(mrb, ai);
- }
-
- return beg;
-}
-
/*
* call-seq:
* str.delete_prefix!(prefix) -> self or nil
@@ -765,6 +582,31 @@ mrb_str_del_suffix(mrb_state *mrb, mrb_value self)
return mrb_str_substr(mrb, self, 0, slen-plen);
}
+static mrb_value
+mrb_str_lines(mrb_state *mrb, mrb_value self)
+{
+ mrb_value result;
+ int ai;
+ mrb_int len;
+ char *b = RSTRING_PTR(self);
+ char *p = b, *t;
+ char *e = b + RSTRING_LEN(self);
+
+ mrb_get_args(mrb, "");
+
+ result = mrb_ary_new(mrb);
+ ai = mrb_gc_arena_save(mrb);
+ while (p < e) {
+ t = p;
+ while (p < e && *p != '\n') p++;
+ if (*p == '\n') p++;
+ len = (mrb_int) (p - t);
+ mrb_ary_push(mrb, result, mrb_str_new(mrb, t, len));
+ mrb_gc_arena_restore(mrb, ai);
+ }
+ return result;
+}
+
void
mrb_mruby_string_ext_gem_init(mrb_state* mrb)
{
@@ -783,18 +625,17 @@ mrb_mruby_string_ext_gem_init(mrb_state* mrb)
mrb_define_method(mrb, s, "hex", mrb_str_hex, MRB_ARGS_NONE());
mrb_define_method(mrb, s, "oct", mrb_str_oct, MRB_ARGS_NONE());
mrb_define_method(mrb, s, "chr", mrb_str_chr, MRB_ARGS_NONE());
- mrb_define_method(mrb, s, "lines", mrb_str_lines, MRB_ARGS_NONE());
mrb_define_method(mrb, s, "succ", mrb_str_succ, MRB_ARGS_NONE());
mrb_define_method(mrb, s, "succ!", mrb_str_succ_bang, MRB_ARGS_NONE());
mrb_alias_method(mrb, s, mrb_intern_lit(mrb, "next"), mrb_intern_lit(mrb, "succ"));
mrb_alias_method(mrb, s, mrb_intern_lit(mrb, "next!"), mrb_intern_lit(mrb, "succ!"));
mrb_define_method(mrb, s, "ord", mrb_str_ord, MRB_ARGS_NONE());
- mrb_define_method(mrb, s, "upto", mrb_str_upto, MRB_ARGS_ANY());
mrb_define_method(mrb, s, "delete_prefix!", mrb_str_del_prefix_bang, MRB_ARGS_REQ(1));
mrb_define_method(mrb, s, "delete_prefix", mrb_str_del_prefix, MRB_ARGS_REQ(1));
mrb_define_method(mrb, s, "delete_suffix!", mrb_str_del_suffix_bang, MRB_ARGS_REQ(1));
mrb_define_method(mrb, s, "delete_suffix", mrb_str_del_suffix, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, s, "__lines", mrb_str_lines, MRB_ARGS_NONE());
mrb_define_method(mrb, mrb->fixnum_class, "chr", mrb_fixnum_chr, MRB_ARGS_NONE());
}
diff --git a/mrblib/array.rb b/mrblib/array.rb
index d76756335..334f4e984 100644
--- a/mrblib/array.rb
+++ b/mrblib/array.rb
@@ -197,24 +197,28 @@ class Array
# left : the beginning of sort region
# right : the end of sort region
def __sort_sub__(left, right, &block)
- if left < right
- i = left
- j = right
- pivot = self[i + (j - i) / 2]
- while true
- while ((block)? block.call(self[i], pivot): (self[i] <=> pivot)) < 0
+ stack = [ [left, right] ]
+ until stack.empty?
+ left, right = stack.pop
+ if left < right
+ i = left
+ j = right
+ pivot = self[i + (j - i) / 2]
+ while true
+ while ((block)? block.call(self[i], pivot): (self[i] <=> pivot)) < 0
+ i += 1
+ end
+ while ((block)? block.call(pivot, self[j]): (pivot <=> self[j])) < 0
+ j -= 1
+ end
+ break if (i >= j)
+ tmp = self[i]; self[i] = self[j]; self[j] = tmp;
i += 1
- end
- while ((block)? block.call(pivot, self[j]): (pivot <=> self[j])) < 0
j -= 1
end
- break if (i >= j)
- tmp = self[i]; self[i] = self[j]; self[j] = tmp;
- i += 1
- j -= 1
+ stack.push [left, i-1]
+ stack.push [j+1, right]
end
- __sort_sub__(left, i-1, &block)
- __sort_sub__(j+1, right, &block)
end
end
# private :__sort_sub__
diff --git a/src/array.c b/src/array.c
index bfa6e5f06..2152e292d 100644
--- a/src/array.c
+++ b/src/array.c
@@ -377,6 +377,9 @@ ary_replace(mrb_state *mrb, struct RArray *a, struct RArray *b)
if (ARY_EMBED_P(a)) {
ARY_UNSET_EMBED_FLAG(a);
}
+ else {
+ mrb_free(mrb, a->as.heap.ptr);
+ }
a->as.heap.ptr = b->as.heap.ptr;
a->as.heap.len = len;
a->as.heap.aux.shared = b->as.heap.aux.shared;
diff --git a/src/backtrace.c b/src/backtrace.c
index 30febdc1c..57ae7fd7f 100644
--- a/src/backtrace.c
+++ b/src/backtrace.c
@@ -51,6 +51,7 @@ each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, mrb_code *pc0, each_backtrace_fu
pc = mrb->c->cibase[i].err;
}
else if (i+1 <= ciidx) {
+ if (!mrb->c->cibase[i + 1].pc) continue;
pc = &mrb->c->cibase[i+1].pc[-1];
}
else {
diff --git a/src/gc.c b/src/gc.c
index 8e2072788..69121d630 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -938,7 +938,7 @@ gc_gray_mark(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
break;
case MRB_TT_ENV:
- children += (int)obj->flags;
+ children += MRB_ENV_STACK_LEN(obj);
break;
case MRB_TT_FIBER:
diff --git a/src/vm.c b/src/vm.c
index 9e43d0a4e..429cc2648 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -527,6 +527,8 @@ mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p)
return MRB_PROC_CFUNC(p)(mrb, self);
}
ci->nregs = p->body.irep->nregs;
+ ci->env = MRB_PROC_ENV(p);
+ if (ci->env) ci->env->stack[0] = self;
if (ci->argc < 0) keep = 3;
else keep = ci->argc + 2;
if (ci->nregs < keep) {
diff --git a/test/t/array.rb b/test/t/array.rb
index d2edd0189..ecec39363 100644
--- a/test/t/array.rb
+++ b/test/t/array.rb
@@ -392,3 +392,10 @@ assert('Array#freeze') do
a[0] = 1
end
end
+
+assert('shared array replace') do
+ a = [0] * 40
+ b = [0, 1, 2]
+ b.replace a[1, 20].dup
+ assert_equal 20, b.size
+end