diff --git a/Recyclable.Collections/RecyclableStack.AddRange.cs b/Recyclable.Collections/RecyclableStack.AddRange.cs index 517dce5..33326fb 100644 --- a/Recyclable.Collections/RecyclableStack.AddRange.cs +++ b/Recyclable.Collections/RecyclableStack.AddRange.cs @@ -79,10 +79,38 @@ namespace Recyclable.Collections [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] internal static void AddRange(this RecyclableStack stack, ReadOnlySpan items) { - for (int i = 0; i < items.Length; i++) + int count = items.Length; + if (count == 0) { - stack.Push(items[i]); + return; } + + EnsureCapacity(stack, stack._count + count); + + RecyclableArrayPoolChunk chunk = stack._current; + int index = chunk.Index; + int chunkLength = chunk.Value.Length; + int copied = 0; + + while (copied < count) + { + if (index == chunkLength) + { + chunk.Index = index; + Grow(stack); + chunk = stack._current; + index = chunk.Index; + chunkLength = chunk.Value.Length; + } + + int toCopy = Math.Min(chunkLength - index, count - copied); + items.Slice(copied, toCopy).CopyTo(new Span(chunk.Value, index, toCopy)); + copied += toCopy; + index += toCopy; + } + + chunk.Index = index; + stack._count += count; } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] @@ -94,10 +122,39 @@ namespace Recyclable.Collections [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] internal static void AddRange(this RecyclableStack stack, in Array items) { - for (int i = 0; i < items.Length; i++) + int count = items.Length; + if (count == 0) { - stack.Push((T)items.GetValue(i)!); + return; } + + EnsureCapacity(stack, stack._count + count); + + RecyclableArrayPoolChunk chunk = stack._current; + int index = chunk.Index; + int chunkLength = chunk.Value.Length; + int copied = 0; + int lower = items.GetLowerBound(0); + + while (copied < count) + { + if (index == chunkLength) + { + chunk.Index = index; + Grow(stack); + chunk = stack._current; + index = chunk.Index; + chunkLength = chunk.Value.Length; + } + + int toCopy = Math.Min(chunkLength - index, count - copied); + Array.Copy(items, lower + copied, chunk.Value, index, toCopy); + copied += toCopy; + index += toCopy; + } + + chunk.Index = index; + stack._count += count; } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] @@ -118,11 +175,33 @@ namespace Recyclable.Collections items.CopyTo(buffer, 0); - for (int i = 0; i < count; i++) + EnsureCapacity(stack, stack._count + count); + + RecyclableArrayPoolChunk chunk = stack._current; + int index = chunk.Index; + int chunkLength = chunk.Value.Length; + int copied = 0; + + while (copied < count) { - stack.Push(buffer[i]); + if (index == chunkLength) + { + chunk.Index = index; + Grow(stack); + chunk = stack._current; + index = chunk.Index; + chunkLength = chunk.Value.Length; + } + + int toCopy = Math.Min(chunkLength - index, count - copied); + Array.Copy(buffer, copied, chunk.Value, index, toCopy); + copied += toCopy; + index += toCopy; } + chunk.Index = index; + stack._count += count; + if (count >= RecyclableDefaults.MinPooledArrayLength) { RecyclableArrayPool.ReturnShared(buffer, RecyclableStack._needsClearing); @@ -144,11 +223,33 @@ namespace Recyclable.Collections items.CopyTo(buffer, 0); - for (int i = 0; i < count; i++) + EnsureCapacity(stack, stack._count + count); + + RecyclableArrayPoolChunk chunk = stack._current; + int index = chunk.Index; + int chunkLength = chunk.Value.Length; + int copied = 0; + + while (copied < count) { - stack.Push(buffer[i]); + if (index == chunkLength) + { + chunk.Index = index; + Grow(stack); + chunk = stack._current; + index = chunk.Index; + chunkLength = chunk.Value.Length; + } + + int toCopy = Math.Min(chunkLength - index, count - copied); + Array.Copy(buffer, copied, chunk.Value, index, toCopy); + copied += toCopy; + index += toCopy; } + chunk.Index = index; + stack._count += count; + if (count >= RecyclableDefaults.MinPooledArrayLength) { RecyclableArrayPool.ReturnShared(buffer, RecyclableStack._needsClearing);