From 2213deeeaaa39ee28dc2d369f71fe7ffdee09e54 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 21 Apr 2018 22:30:54 +0900 Subject: Implement `String#upto` in Ruby. Avoid using `mrb_yield` in C code. The function is not recommended. Because it doesn't work well with fibers. --- mrbgems/mruby-string-ext/src/string.c | 130 ---------------------------------- 1 file changed, 130 deletions(-) (limited to 'mrbgems/mruby-string-ext/src/string.c') diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index 48fa27085..4cab49094 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -470,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 str and - * ending at other_str inclusive, passing each value in turn to - * the block. The String#succ 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 - * - * produces: - * - * a8 a9 b0 b1 b2 b3 b4 b5 b6 - * a8 a9 b0 b1 b2 b3 b4 b5 b6 - * - * If str and other_str 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 @@ -759,7 +630,6 @@ mrb_mruby_string_ext_gem_init(mrb_state* mrb) 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)); -- cgit v1.2.3