Permalink
Browse files

improve String#reverse performance with ascii compatible string

* before
     user     system      total        real
22.430000   0.420000  22.850000 ( 20.853809)

* after
    user     system      total        real
1.080000   0.000000   1.080000 (  1.089038)

Test Code:
----
require 'benchmark'

Benchmark.bm do |x|
  str = "foobarbaz" * 5000
  x.report do
    50_000.times do
      str.reverse!
    end
  end
end
  • Loading branch information...
1 parent b43448a commit e5e8046ce0c60589f8657b11bed0a7c8040959b4 @Watson1978 Watson1978 committed Sep 6, 2012
Showing with 35 additions and 14 deletions.
  1. +35 −14 string.c
View
@@ -5328,6 +5328,35 @@ rstr_transform(VALUE str, SEL sel, VALUE transform_pat)
return rb_unicode_str_new(new_chars, (long)capacity);
}
+void
+rstr_reverse_bang_uchar32(VALUE str)
+{
+ char *new_bytes = xmalloc(RSTR(str)->length_in_bytes);
+ __block long pos = RSTR(str)->length_in_bytes;
+ str_each_uchar32(RSTR(str), ^(UChar32 c, long start_index, long char_len, bool *stop) {
+ pos -= char_len;
+ memcpy(&new_bytes[pos], &RSTR(str)->bytes[start_index], char_len);
+ });
+ assert(pos == 0);
+
+ RSTR(str)->capacity_in_bytes = RSTR(str)->length_in_bytes;
+ GC_WB(&RSTR(str)->bytes, new_bytes);
+}
+
+void
+rstr_reverse_bang_ascii(VALUE str)
+{
+ char *s, *e, c;
+ s = RSTR(str)->bytes;
+ e = RSTR(str)->bytes + RSTR(str)->length_in_bytes - 1;
+
+ while (s < e) {
+ c = *s;
+ *s++ = *e;
+ *e-- = c;
+ }
+}
+
/*
* call-seq:
* str.reverse! => str
@@ -5344,20 +5373,12 @@ rstr_reverse_bang(VALUE str, SEL sel)
return str;
}
- char *new_bytes = xmalloc(RSTR(str)->length_in_bytes);
- __block long pos = RSTR(str)->length_in_bytes;
- str_each_uchar32(RSTR(str), ^(UChar32 c, long start_index, long char_len, bool *stop) {
- pos -= char_len;
- memcpy(&new_bytes[pos], &RSTR(str)->bytes[start_index], char_len);
- });
- assert(pos == 0);
-
- RSTR(str)->capacity_in_bytes = RSTR(str)->length_in_bytes;
- GC_WB(&RSTR(str)->bytes, new_bytes);
-
- // we modify it directly so the information stored
- // in the facultative flags might be outdated
- str_reset_flags(RSTR(str));
+ if (str_is_ruby_ascii_only(RSTR(str))) {
+ rstr_reverse_bang_ascii(str);
+ }
+ else {
+ rstr_reverse_bang_uchar32(str);
+ }
return str;
}

0 comments on commit e5e8046

Please sign in to comment.