diff --git a/mrbgems/mruby-string-ext/mrblib/string.rb b/mrbgems/mruby-string-ext/mrblib/string.rb
index 9f940ca32..37b5fcb75 100644
--- a/mrbgems/mruby-string-ext/mrblib/string.rb
+++ b/mrbgems/mruby-string-ext/mrblib/string.rb
@@ -13,103 +13,6 @@ class String
self.replace("")
end
- ##
- # call-seq:
- # str.lstrip -> new_str
- #
- # Returns a copy of str with leading whitespace removed. See also
- # String#rstrip and String#strip.
- #
- # " hello ".lstrip #=> "hello "
- # "hello".lstrip #=> "hello"
- #
- def lstrip
- a = 0
- z = self.size - 1
- a += 1 while a <= z and " \f\n\r\t\v".include?(self[a])
- (z >= 0) ? self[a..z] : ""
- end
-
- ##
- # call-seq:
- # str.rstrip -> new_str
- #
- # Returns a copy of str with trailing whitespace removed. See also
- # String#lstrip and String#strip.
- #
- # " hello ".rstrip #=> " hello"
- # "hello".rstrip #=> "hello"
- #
- def rstrip
- a = 0
- z = self.size - 1
- z -= 1 while a <= z and " \f\n\r\t\v\0".include?(self[z])
- (z >= 0) ? self[a..z] : ""
- end
-
- ##
- # call-seq:
- # str.strip -> new_str
- #
- # Returns a copy of str with leading and trailing whitespace removed.
- #
- # " hello ".strip #=> "hello"
- # "\tgoodbye\r\n".strip #=> "goodbye"
- #
- def strip
- a = 0
- z = self.size - 1
- a += 1 while a <= z and " \f\n\r\t\v".include?(self[a])
- z -= 1 while a <= z and " \f\n\r\t\v\0".include?(self[z])
- (z >= 0) ? self[a..z] : ""
- end
-
- ##
- # call-seq:
- # str.lstrip! -> self or nil
- #
- # Removes leading whitespace from str, returning nil if no
- # change was made. See also String#rstrip! and
- # String#strip!.
- #
- # " hello ".lstrip #=> "hello "
- # "hello".lstrip! #=> nil
- #
- def lstrip!
- raise FrozenError, "can't modify frozen String" if frozen?
- s = self.lstrip
- (s == self) ? nil : self.replace(s)
- end
-
- ##
- # call-seq:
- # str.rstrip! -> self or nil
- #
- # Removes trailing whitespace from str, returning nil if
- # no change was made. See also String#lstrip! and
- # String#strip!.
- #
- # " hello ".rstrip #=> " hello"
- # "hello".rstrip! #=> nil
- #
- def rstrip!
- raise FrozenError, "can't modify frozen String" if frozen?
- s = self.rstrip
- (s == self) ? nil : self.replace(s)
- end
-
- ##
- # call-seq:
- # str.strip! -> str or nil
- #
- # Removes leading and trailing whitespace from str. Returns
- # nil if str was not altered.
- #
- def strip!
- raise FrozenError, "can't modify frozen String" if frozen?
- s = self.strip
- (s == self) ? nil : self.replace(s)
- end
def partition(sep)
raise TypeError, "type mismatch: #{sep.class} given" unless sep.is_a? String
diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c
index 2410612b4..d3ee353bc 100644
--- a/mrbgems/mruby-string-ext/src/string.c
+++ b/mrbgems/mruby-string-ext/src/string.c
@@ -1344,6 +1344,255 @@ str_b(mrb_state *mrb, mrb_value self)
return str;
}
+/*
+ * Check if character is whitespace (space, tab, newline, carriage return, form feed, vertical tab)
+ */
+static inline mrb_bool
+is_whitespace(char c)
+{
+ return (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v');
+}
+
+/*
+ * Check if character is whitespace or null (for rstrip)
+ */
+static inline mrb_bool
+is_whitespace_or_null(char c)
+{
+ return (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v' || c == '\0');
+}
+
+/*
+ * call-seq:
+ * str.lstrip -> new_str
+ *
+ * Returns a copy of str with leading whitespace removed.
+ *
+ * " hello ".lstrip #=> "hello "
+ * "hello".lstrip #=> "hello"
+ */
+static mrb_value
+str_lstrip(mrb_state *mrb, mrb_value self)
+{
+ struct RString *s = mrb_str_ptr(self);
+ const char *ptr = RSTR_PTR(s);
+ mrb_int len = RSTR_LEN(s);
+ mrb_int start = 0;
+
+ /* Find first non-whitespace character */
+ while (start < len && is_whitespace(ptr[start])) {
+ start++;
+ }
+
+ /* Return empty string if all whitespace */
+ if (start >= len) {
+ return mrb_str_new_lit(mrb, "");
+ }
+
+ /* Return substring from first non-whitespace to end */
+ return mrb_str_substr(mrb, self, start, len - start);
+}
+
+/*
+ * call-seq:
+ * str.rstrip -> new_str
+ *
+ * Returns a copy of str with trailing whitespace removed.
+ *
+ * " hello ".rstrip #=> " hello"
+ * "hello".rstrip #=> "hello"
+ */
+static mrb_value
+str_rstrip(mrb_state *mrb, mrb_value self)
+{
+ struct RString *s = mrb_str_ptr(self);
+ const char *ptr = RSTR_PTR(s);
+ mrb_int len = RSTR_LEN(s);
+ mrb_int end = len;
+
+ /* Find last non-whitespace character */
+ while (end > 0 && is_whitespace_or_null(ptr[end - 1])) {
+ end--;
+ }
+
+ /* Return empty string if all whitespace */
+ if (end <= 0) {
+ return mrb_str_new_lit(mrb, "");
+ }
+
+ /* Return substring from start to last non-whitespace */
+ return mrb_str_substr(mrb, self, 0, end);
+}
+
+/*
+ * call-seq:
+ * str.strip -> new_str
+ *
+ * Returns a copy of str with leading and trailing whitespace removed.
+ *
+ * " hello ".strip #=> "hello"
+ * "\tgoodbye\r\n".strip #=> "goodbye"
+ */
+static mrb_value
+str_strip(mrb_state *mrb, mrb_value self)
+{
+ struct RString *s = mrb_str_ptr(self);
+ const char *ptr = RSTR_PTR(s);
+ mrb_int len = RSTR_LEN(s);
+ mrb_int start = 0;
+ mrb_int end = len;
+
+ /* Find first non-whitespace character */
+ while (start < len && is_whitespace(ptr[start])) {
+ start++;
+ }
+
+ /* Find last non-whitespace character */
+ while (end > start && is_whitespace_or_null(ptr[end - 1])) {
+ end--;
+ }
+
+ /* Return empty string if all whitespace */
+ if (start >= end) {
+ return mrb_str_new_lit(mrb, "");
+ }
+
+ /* Return substring from first to last non-whitespace */
+ return mrb_str_substr(mrb, self, start, end - start);
+}
+
+/*
+ * call-seq:
+ * str.lstrip! -> self or nil
+ *
+ * Removes leading whitespace from str, returning nil if no change was made.
+ *
+ * " hello ".lstrip! #=> "hello "
+ * "hello".lstrip! #=> nil
+ */
+static mrb_value
+str_lstrip_bang(mrb_state *mrb, mrb_value self)
+{
+ struct RString *s = mrb_str_ptr(self);
+ char *ptr = RSTR_PTR(s);
+ mrb_int len = RSTR_LEN(s);
+ mrb_int start = 0;
+
+ mrb_check_frozen(mrb, mrb_obj_ptr(self));
+ mrb_str_modify(mrb, s);
+
+ /* Find first non-whitespace character */
+ while (start < len && is_whitespace(ptr[start])) {
+ start++;
+ }
+
+ /* No change needed */
+ if (start == 0) {
+ return mrb_nil_value();
+ }
+
+ /* Move remaining characters to beginning */
+ if (start < len) {
+ memmove(ptr, ptr + start, len - start);
+ RSTR_SET_LEN(s, len - start);
+ } else {
+ /* All whitespace - make empty */
+ RSTR_SET_LEN(s, 0);
+ }
+
+ return self;
+}
+
+/*
+ * call-seq:
+ * str.rstrip! -> self or nil
+ *
+ * Removes trailing whitespace from str, returning nil if no change was made.
+ *
+ * " hello ".rstrip! #=> " hello"
+ * "hello".rstrip! #=> nil
+ */
+static mrb_value
+str_rstrip_bang(mrb_state *mrb, mrb_value self)
+{
+ struct RString *s = mrb_str_ptr(self);
+ char *ptr = RSTR_PTR(s);
+ mrb_int len = RSTR_LEN(s);
+ mrb_int end = len;
+
+ mrb_check_frozen(mrb, mrb_obj_ptr(self));
+ mrb_str_modify(mrb, s);
+
+ /* Find last non-whitespace character */
+ while (end > 0 && is_whitespace_or_null(ptr[end - 1])) {
+ end--;
+ }
+
+ /* No change needed */
+ if (end == len) {
+ return mrb_nil_value();
+ }
+
+ /* Truncate string */
+ RSTR_SET_LEN(s, end);
+
+ return self;
+}
+
+/*
+ * call-seq:
+ * str.strip! -> self or nil
+ *
+ * Removes leading and trailing whitespace from str, returning nil if no change was made.
+ *
+ * " hello ".strip! #=> "hello"
+ * "hello".strip! #=> nil
+ */
+static mrb_value
+str_strip_bang(mrb_state *mrb, mrb_value self)
+{
+ struct RString *s = mrb_str_ptr(self);
+ char *ptr = RSTR_PTR(s);
+ mrb_int len = RSTR_LEN(s);
+ mrb_int start = 0;
+ mrb_int end = len;
+ mrb_bool changed = FALSE;
+
+ mrb_check_frozen(mrb, mrb_obj_ptr(self));
+ mrb_str_modify(mrb, s);
+
+ /* Find first non-whitespace character */
+ while (start < len && is_whitespace(ptr[start])) {
+ start++;
+ }
+
+ /* Find last non-whitespace character */
+ while (end > start && is_whitespace_or_null(ptr[end - 1])) {
+ end--;
+ }
+
+ /* Check if any changes needed */
+ if (start > 0) {
+ changed = TRUE;
+ if (start < end) {
+ memmove(ptr, ptr + start, end - start);
+ }
+ }
+
+ if (end != len) {
+ changed = TRUE;
+ }
+
+ if (!changed) {
+ return mrb_nil_value();
+ }
+
+ /* Set new length */
+ RSTR_SET_LEN(s, end - start);
+
+ return self;
+}
+
void
mrb_mruby_string_ext_gem_init(mrb_state* mrb)
{
@@ -1388,6 +1637,14 @@ mrb_mruby_string_ext_gem_init(mrb_state* mrb)
mrb_define_method_id(mrb, s, MRB_SYM(__lines), str_lines, MRB_ARGS_NONE());
mrb_define_method_id(mrb, s, MRB_SYM(__codepoints), str_codepoints, MRB_ARGS_NONE());
+ /* Optimized strip methods implemented in C */
+ mrb_define_method_id(mrb, s, MRB_SYM(lstrip), str_lstrip, MRB_ARGS_NONE());
+ mrb_define_method_id(mrb, s, MRB_SYM(rstrip), str_rstrip, MRB_ARGS_NONE());
+ mrb_define_method_id(mrb, s, MRB_SYM(strip), str_strip, MRB_ARGS_NONE());
+ mrb_define_method_id(mrb, s, MRB_SYM_B(lstrip), str_lstrip_bang, MRB_ARGS_NONE());
+ mrb_define_method_id(mrb, s, MRB_SYM_B(rstrip), str_rstrip_bang, MRB_ARGS_NONE());
+ mrb_define_method_id(mrb, s, MRB_SYM_B(strip), str_strip_bang, MRB_ARGS_NONE());
+
mrb_define_method_id(mrb, mrb->integer_class, MRB_SYM(chr), int_chr, MRB_ARGS_OPT(1));
}