diff options
| -rw-r--r-- | mrbgems/mruby-string-ext/mrblib/string.rb | 94 | ||||
| -rw-r--r-- | mrbgems/mruby-string-ext/src/string.c | 211 | ||||
| -rw-r--r-- | mrblib/array.rb | 32 | ||||
| -rw-r--r-- | src/array.c | 3 | ||||
| -rw-r--r-- | src/backtrace.c | 1 | ||||
| -rw-r--r-- | src/gc.c | 2 | ||||
| -rw-r--r-- | src/vm.c | 2 | ||||
| -rw-r--r-- | test/t/array.rb | 7 |
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 { @@ -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: @@ -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 |
