diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2021-08-30 12:02:21 +0900 |
|---|---|---|
| committer | Yukihiro "Matz" Matsumoto <[email protected]> | 2021-09-01 07:00:54 +0900 |
| commit | 37a7ff228b4b8b5c0230ef5a80ba1312763d93f8 (patch) | |
| tree | bbb7254053b2b0c57a28b7fc2d42b5c328547445 | |
| parent | f6e5c902f0591e32088623d6ed4146e34f58fd85 (diff) | |
| download | mruby-37a7ff228b4b8b5c0230ef5a80ba1312763d93f8.tar.gz mruby-37a7ff228b4b8b5c0230ef5a80ba1312763d93f8.zip | |
string-ext/string.c: implement `casecmp` in C.
* should not raise error for non-string arguments
* avoid allocating case converted string internally
| -rw-r--r-- | mrbgems/mruby-string-ext/mrblib/string.rb | 30 | ||||
| -rw-r--r-- | mrbgems/mruby-string-ext/src/string.c | 56 |
2 files changed, 56 insertions, 30 deletions
diff --git a/mrbgems/mruby-string-ext/mrblib/string.rb b/mrbgems/mruby-string-ext/mrblib/string.rb index 2b3071567..d485c51ef 100644 --- a/mrbgems/mruby-string-ext/mrblib/string.rb +++ b/mrbgems/mruby-string-ext/mrblib/string.rb @@ -111,36 +111,6 @@ class String (s == self) ? nil : self.replace(s) end - ## - # call-seq: - # str.casecmp(other_str) -> -1, 0, +1 or nil - # - # Case-insensitive version of <code>String#<=></code>. - # - # "abcdef".casecmp("abcde") #=> 1 - # "aBcDeF".casecmp("abcdef") #=> 0 - # "abcdef".casecmp("abcdefg") #=> -1 - # "abcdef".casecmp("ABCDEF") #=> 0 - # - def casecmp(str) - self.downcase <=> str.__to_str.downcase - rescue NoMethodError - nil - end - - ## - # call-seq: - # str.casecmp?(other) -> true, false, or nil - # - # Returns true if str and other_str are equal after case folding, - # false if they are not equal, and nil if other_str is not a string. - - def casecmp?(str) - c = self.casecmp(str) - return nil if c.nil? - return c == 0 - end - def partition(sep) raise TypeError, "type mismatch: #{sep.class} given" unless sep.is_a? String n = index(sep) diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index 39ab94c26..8fafcc089 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -1174,6 +1174,60 @@ mrb_str_del_suffix(mrb_state *mrb, mrb_value self) return mrb_str_substr(mrb, self, 0, slen-plen); } +#define lesser(a,b) (((a)>(b))?(b):(a)) + +/* + * call-seq: + * str.casecmp(other_str) -> -1, 0, +1 or nil + * + * Case-insensitive version of <code>String#<=></code>. + * + * "abcdef".casecmp("abcde") #=> 1 + * "aBcDeF".casecmp("abcdef") #=> 0 + * "abcdef".casecmp("abcdefg") #=> -1 + * "abcdef".casecmp("ABCDEF") #=> 0 + */ +static mrb_value +mrb_str_casecmp(mrb_state *mrb, mrb_value self) +{ + mrb_value str; + + mrb_get_args(mrb, "o", &str); + if (!mrb_string_p(str)) return mrb_nil_value(); + + struct RString *s1 = mrb_str_ptr(self); + struct RString *s2 = mrb_str_ptr(str); + mrb_int len = lesser(RSTR_LEN(s1), RSTR_LEN(s2)); + char *p1 = RSTR_PTR(s1); + char *p2 = RSTR_PTR(s2); + + for (mrb_int i=0; i<len; i++) { + int c1 = p1[i], c2 = p2[i]; + if (ISASCII(c1) && ISUPPER(c1)) c1 = TOLOWER(c1); + if (ISASCII(c2) && ISUPPER(c2)) c2 = TOLOWER(c2); + if (c1 > c2) return mrb_fixnum_value(1); + if (c1 < c2) return mrb_fixnum_value(-1); + } + if (RSTR_LEN(s1) == RSTR_LEN(s2)) return mrb_fixnum_value(0); + if (RSTR_LEN(s1) > RSTR_LEN(s2)) return mrb_fixnum_value(1); + return mrb_fixnum_value(-1); +} + +/* + * call-seq: + * str.casecmp?(other) -> true, false, or nil + * + * Returns true if str and other_str are equal after case folding, + * false if they are not equal, and nil if other is not a string. + */ +static mrb_value +mrb_str_casecmp_p(mrb_state *mrb, mrb_value self) +{ + mrb_value c = mrb_str_casecmp(mrb, self); + if (mrb_nil_p(c)) return c; + return mrb_bool_value(mrb_fixnum(c) == 0); +} + static mrb_value mrb_str_lines(mrb_state *mrb, mrb_value self) { @@ -1231,6 +1285,8 @@ mrb_mruby_string_ext_gem_init(mrb_state* mrb) 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, "casecmp", mrb_str_casecmp, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, s, "casecmp?", mrb_str_casecmp_p, MRB_ARGS_REQ(1)); mrb_define_method(mrb, s, "__lines", mrb_str_lines, MRB_ARGS_NONE()); |
