Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions mrbgems/mruby-encoding/test/string.rb
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,29 @@
end
end

assert('String#reverse! leaves what the bytes read as standing') do
# Reversing puts the same bytes back with every character whole, so a string
# that read as UTF-8 still does, and one that did not still does not. The
# reversal is where that is decided; asking afterwards is how it is seen.
if UTF8STRING
a = "あいうz"
a.reverse!
assert_equal "zういあ", a
assert_equal 4, a.length
assert_true a.valid_encoding?

b = "abc"
b.reverse!
assert_equal 3, b.length
assert_true b.valid_encoding?

c = "a\xE3\x81"
c.reverse!
assert_equal "\x81\xE3a".b, c.b
assert_false c.valid_encoding?
end
end

Comment thread
takumin marked this conversation as resolved.
assert('String#encoding') do
if UTF8STRING
a = "あ"
Expand Down
15 changes: 13 additions & 2 deletions src/string.c
Original file line number Diff line number Diff line change
Expand Up @@ -2969,13 +2969,22 @@ mrb_str_reverse_bang(mrb_state *mrb, mrb_value str)
struct RString *s = mrb_str_ptr(str);
char *p, *e;

/* Reversing writes the string's own bytes back in another order, and both
paths below leave every character whole, so what the bytes read as is
still what they read as: both write through str_modify_keep_cr(). */

#ifdef MRB_UTF8_STRING
/* mrb_str_char_len() walks the string and records what it finds. The
multi-byte path turns each character's bytes around where they stand and
then turns the whole buffer around, which puts the characters back in the
reverse order with each one whole, so that record still holds and the
next asker is spared the same walk. */
mrb_int utf8_len = mrb_str_char_len(mrb, str);
mrb_int len = RSTR_LEN(s);

if (utf8_len < 2) return str;
if (utf8_len < len) {
mrb_str_modify(mrb, s);
str_modify_keep_cr(mrb, s);
p = RSTR_PTR(s);
e = p + RSTR_LEN(s);
while (p<e) {
Expand All @@ -2987,8 +2996,10 @@ mrb_str_reverse_bang(mrb_state *mrb, mrb_value str)
}
#endif

/* Reached with one character per byte, where the reversal below is a byte
reversal that cuts no character in two. */
if (RSTR_LEN(s) > 1) {
mrb_str_modify(mrb, s);
str_modify_keep_cr(mrb, s);
goto bytes;
}
return str;
Expand Down
Loading