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
16 changes: 16 additions & 0 deletions src/ChibiRuby/MRubyState.Object.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ public RString NewString(ref Utf8StringWriter<ArrayBufferWriter<byte>> format)

public RArray NewArray(params ReadOnlySpan<MRubyValue> values) => new(values, ArrayClass);

internal RArray NewArray(RArray source, int start, int length) =>
source.CopySubSequence(start, length, ArrayClass);

internal RArray NewSharedArray(RArray source, int start, int length) =>
source.SharedSubSequence(start, length, ArrayClass);

public RHash NewHash(int capacity = 4) => new(
capacity,
HashKeyEqualityComparer,
Expand Down Expand Up @@ -473,6 +479,16 @@ internal void SpliceArray(RArray array, int start, int length, MRubyValue args)
}

var originalLength = array.Length;
if (length == newValues.Length && start >= 0 && end <= originalLength)
{
array.MakeModifiable(originalLength);
if (length > 0)
{
newValues.CopyTo(array.AsSpan(start, length));
}
return;
}

if (start >= originalLength)
{
length = start + newValues.Length;
Expand Down
15 changes: 7 additions & 8 deletions src/ChibiRuby/MRubyState.Vm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -740,8 +740,8 @@ static void GetConstSlowPath(MRubyState state, ref MRubyValue registerA, ref MRu
var valueB = Unsafe.Add(ref registerA, 1);
switch (registerA.Object)
{
case RArray array when valueB.IsInteger && array.Class == ArrayClass:
registerA = array[(int)valueB.IntegerValue];
case RArray array when valueB.IsFixnum && array.Class == ArrayClass:
registerA = array[(int)valueB.FixnumValue];
goto Next;
case RHash hash when hash.Class == HashClass:
registerA = hash.GetValueOrDefault(valueB, this);
Expand Down Expand Up @@ -799,9 +799,9 @@ static void GetConstSlowPath(MRubyState state, ref MRubyValue registerA, ref MRu
var setVal = Unsafe.Add(ref registerA, 2);
switch (registerA.Object)
{
case RArray array when keyVal.IsInteger && array.Class == ArrayClass
case RArray array when keyVal.IsFixnum && array.Class == ArrayClass
&& !array.HasFlag(MRubyObjectFlags.Frozen):
array[(int)keyVal.IntegerValue] = setVal;
array.Set((int)keyVal.FixnumValue, setVal);
registerA = setVal;
goto Next;
case RHash hash when hash.Class == HashClass
Expand Down Expand Up @@ -2345,7 +2345,7 @@ static void BlkPush(MRubyState state, ref MRubyCallInfo callInfo, Span<MRubyValu
Markers.ASet();
bbb = OperandBBB.Read(ref sequence, ref callInfo.ProgramCounter);
var array = Unsafe.Add(ref registers, bbb.B).As<RArray>();
array[bbb.C] = Unsafe.Add(ref registers, bbb.A);
array.Set(bbb.C, Unsafe.Add(ref registers, bbb.A));
goto Next;
}
case OpCode.APost:
Expand All @@ -2366,8 +2366,7 @@ static void BlkPush(MRubyState state, ref MRubyCallInfo callInfo, Span<MRubyValu
[MethodImpl(MethodImplOptions.NoInlining)]
static void APostShort(MRubyState state, RArray array, OperandBBB bbb, int pre, int post, ref MRubyValue registerA)
{
var slice = array.AsSpan().Slice(bbb.B, array.Length - pre - post);
registerA = state.NewArray(slice);
registerA = state.NewSharedArray(array, bbb.B, array.Length - pre - post);
registerA = ref Unsafe.Add(ref registerA, 1);
while (post-- > 0)
{
Expand Down Expand Up @@ -3060,4 +3059,4 @@ void _Raise(ReadOnlySpan<MRubyValue> args)
}
}
}
}
}
1 change: 0 additions & 1 deletion src/ChibiRuby/RProc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -145,4 +145,3 @@ public override int GetHashCode()
return HashCode.Combine(Upper, Scope);
}
}

27 changes: 27 additions & 0 deletions tests/ChibiRuby.Tests/ruby/test/array.rb
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,10 @@ class SubArray < Array

assert_equal([1,2,3,4], a)
assert_equal([1,2,3,4], b)

a.shift
a.push(5)
assert_equal([2,3,4,5], a)
end

assert('Array#replace', '15.2.12.5.23') do
Expand Down Expand Up @@ -368,6 +372,29 @@ class SubArray < Array
assert_nil(a.slice(10, -3))
assert_equal([], a.slice(10..7))
assert_equal(b, a)

# Slices are allowed to share storage internally, but writes on either side
# must detach before mutating.
parent = [0, 1, 2, 3, 4]
child = parent.slice(1, 3)
nested = child.slice(1, 2)
assert_equal([2, 3], nested)
parent[2] = 20
assert_equal([1, 2, 3], child)
nested[0] = 30
assert_equal([0, 1, 20, 3, 4], parent)
assert_equal([1, 2, 3], child)
assert_equal([30, 3], nested)

shifted = [0, 1, 2, 3, 4]
shifted.shift
shifted_dup = shifted.dup
shifted_slice = shifted.slice(1, 2)
assert_equal([1, 2, 3, 4], shifted_dup)
assert_equal([2, 3], shifted_slice)
shifted_dup[0] = 10
shifted_slice[0] = 20
assert_equal([1, 2, 3, 4], shifted)
end

assert('Array#unshift', '15.2.12.5.30') do
Expand Down
Loading