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
53 changes: 53 additions & 0 deletions doc/string/succ.rdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
Returns the successor to +self+. The successor is calculated by
incrementing characters.

The first character to be incremented is the rightmost alphanumeric:
or, if no alphanumerics, the rightmost character:

'THX1138'.succ # => "THX1139"
'<<koala>>'.succ # => "<<koalb>>"
'***'.succ # => '**+'
'тест'.succ # => "тесу"
'こんにちは'.succ # => "こんにちば"

The successor to a digit is another digit, "carrying" to the next-left
character for a "rollover" from 9 to 0, and prepending another digit
if necessary:

'00'.succ # => "01"
'09'.succ # => "10"
'99'.succ # => "100"

The successor to a letter is another letter of the same case,
carrying to the next-left character for a rollover,
and prepending another same-case letter if necessary:

'aa'.succ # => "ab"
'az'.succ # => "ba"
'zz'.succ # => "aaa"
'AA'.succ # => "AB"
'AZ'.succ # => "BA"
'ZZ'.succ # => "AAA"

The successor to a non-alphanumeric character is the next character
in the underlying character set's collating sequence,
carrying to the next-left character for a rollover,
and prepending another character if necessary:

s = 0.chr * 3 # => "\x00\x00\x00"
s.succ # => "\x00\x00\x01"
s = 255.chr * 3 # => "\xFF\xFF\xFF"
s.succ # => "\x01\x00\x00\x00"

Carrying can occur between and among mixtures of alphanumeric characters:

s = 'zz99zz99' # => "zz99zz99"
s.succ # => "aaa00aa00"
s = '99zz99zz' # => "99zz99zz"
s.succ # => "100aa00aa"

The successor to an empty +String+ is a new empty +String+:

''.succ # => ""

Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
4 changes: 3 additions & 1 deletion ractor.c
Original file line number Diff line number Diff line change
Expand Up @@ -1940,8 +1940,10 @@ move_enter(VALUE obj, struct obj_traverse_replace_data *data)
}
else {
VALUE type = RB_BUILTIN_TYPE(obj);
size_t slot_size = rb_gc_obj_slot_size(obj);
type |= wb_protected_types[type] ? FL_WB_PROTECTED : 0;
NEWOBJ_OF(moved, struct RBasic, 0, type, rb_gc_obj_slot_size(obj), 0);
NEWOBJ_OF(moved, struct RBasic, 0, type, slot_size, 0);
MEMZERO(&moved[1], char, slot_size - sizeof(*moved));
data->replacement = (VALUE)moved;
return traverse_cont;
}
Expand Down
56 changes: 4 additions & 52 deletions string.c
Original file line number Diff line number Diff line change
Expand Up @@ -5315,57 +5315,7 @@ static VALUE str_succ(VALUE str);
* call-seq:
* succ -> new_str
*
* Returns the successor to +self+. The successor is calculated by
* incrementing characters.
*
* The first character to be incremented is the rightmost alphanumeric:
* or, if no alphanumerics, the rightmost character:
*
* 'THX1138'.succ # => "THX1139"
* '<<koala>>'.succ # => "<<koalb>>"
* '***'.succ # => '**+'
*
* The successor to a digit is another digit, "carrying" to the next-left
* character for a "rollover" from 9 to 0, and prepending another digit
* if necessary:
*
* '00'.succ # => "01"
* '09'.succ # => "10"
* '99'.succ # => "100"
*
* The successor to a letter is another letter of the same case,
* carrying to the next-left character for a rollover,
* and prepending another same-case letter if necessary:
*
* 'aa'.succ # => "ab"
* 'az'.succ # => "ba"
* 'zz'.succ # => "aaa"
* 'AA'.succ # => "AB"
* 'AZ'.succ # => "BA"
* 'ZZ'.succ # => "AAA"
*
* The successor to a non-alphanumeric character is the next character
* in the underlying character set's collating sequence,
* carrying to the next-left character for a rollover,
* and prepending another character if necessary:
*
* s = 0.chr * 3
* s # => "\x00\x00\x00"
* s.succ # => "\x00\x00\x01"
* s = 255.chr * 3
* s # => "\xFF\xFF\xFF"
* s.succ # => "\x01\x00\x00\x00"
*
* Carrying can occur between and among mixtures of alphanumeric characters:
*
* s = 'zz99zz99'
* s.succ # => "aaa00aa00"
* s = '99zz99zz'
* s.succ # => "100aa00aa"
*
* The successor to an empty +String+ is a new empty +String+:
*
* ''.succ # => ""
* :include: doc/string/succ.rdoc
*
*/

Expand Down Expand Up @@ -5470,7 +5420,9 @@ str_succ(VALUE str)
* call-seq:
* succ! -> self
*
* Equivalent to String#succ, but modifies +self+ in place; returns +self+.
* Like String#succ, but modifies +self+ in place; returns +self+.
*
* Related: see {Modifying}[rdoc-ref:String@Modifying].
*/

static VALUE
Expand Down
13 changes: 13 additions & 0 deletions test/ruby/test_ractor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,19 @@ def initialize(*)
RUBY
end

def test_move_nested_hash_during_gc_with_yjit
original_gc_stress = GC.stress
assert_ractor(<<~'RUBY', args: [{ "RUBY_YJIT_ENABLE" => "1" }])
GC.stress = true
hash = { foo: { bar: "hello" }, baz: { qux: "there" } }
result = Ractor.new { Ractor.receive }.send(hash, move: true).value
assert_equal "hello", result[:foo][:bar]
assert_equal "there", result[:baz][:qux]
RUBY
ensure
GC.stress = original_gc_stress
end

def test_fork_raise_isolation_error
assert_ractor(<<~'RUBY')
ractor = Ractor.new do
Expand Down
2 changes: 1 addition & 1 deletion vm_method.c
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ vm_ccs_invalidate(struct rb_class_cc_entries *ccs)
}
}

void
static void
rb_vm_ccs_invalidate_and_free(struct rb_class_cc_entries *ccs)
{
RB_DEBUG_COUNTER_INC(ccs_free);
Expand Down