Repository: dotnet/roslyn
File: src/Compilers/Core/Portable/Text/SourceText.cs (C#)

Code before:
#if NET
            result = string.Create(length, (this, position, length, tempBuffer), static (buffer, arg) =>
            {
                var (sourceText, position, length, tempBuffer) = arg;

                while (buffer.Length > 0)
                {
                    int copyLength = Math.Min(tempBuffer.Length, length);
                    sourceText.CopyTo(position, tempBuffer, 0, copyLength);
                    tempBuffer.AsSpan(0, copyLength).CopyTo(buffer);

                    buffer = buffer[copyLength..];
                    length -= copyLength;
                    position += copyLength;
                }
            });
#else
            var builder = PooledStringBuilder.GetInstance();
            builder.Builder.EnsureCapacity(length);

            while (position < this.Length && length > 0)
            {
                int copyLength = Math.Min(tempBuffer.Length, length);
                this.CopyTo(position, tempBuffer, 0, copyLength);
                builder.Builder.Append(tempBuffer, 0, copyLength);
                length -= copyLength;
                position += copyLength;
            }

            result = builder.ToStringAndFree();
#endif

            s_charArrayPool.Free(tempBuffer);
            return result;
        }

        #region Changes

        /// <summary>
        /// Constructs a new SourceText from this text with the specified changes.
        /// </summary>
        public virtual SourceText WithChanges(IEnumerable<TextChange> changes)
        {
            if (changes == null)
            {
                throw new ArgumentNullException(nameof(changes));
            }

            if (!changes.Any())
            {
                return this;

Review comment (suggestion):
If we just had a CopyTo that took a span instead of an array, could we eliminate the array allocation entirely? It's pooled so it's not the worst, but still curious.

Code after:
#if NET
            result = string.Create(length, (this, position, length, tempBuffer), static (buffer, arg) =>
            {
                var (sourceText, position, length, tempBuffer) = arg;

                while (buffer.Length > 0)
                {
                    int copyLength = Math.Min(tempBuffer.Length, length);
                    sourceText.CopyTo(position, tempBuffer, 0, copyLength);
                    tempBuffer.AsSpan(0, copyLength).CopyTo(buffer);

                    buffer = buffer[copyLength..];
                    length -= copyLength;
                    position += copyLength;
                }
            });
#else
            unsafe
            {
                result = new('\0', length);
                fixed (char* pointer = result)
                {
                    while (position < this.Length && length > 0)
                    {
                        int copyLength = Math.Min(tempBuffer.Length, length);
                        this.CopyTo(position, tempBuffer, 0, copyLength);
                        tempBuffer.AsSpan(0, copyLength).CopyTo(new Span<char>(pointer + (position - span.Start), copyLength));
                        length -= copyLength;
                        position += copyLength;
                    }
                }
            }
#endif

            s_charArrayPool.Free(tempBuffer);
            return result;
        }

        #region Changes

        /// <summary>
        /// Constructs a new SourceText from this text with the specified changes.
        /// </summary>
        public virtual SourceText WithChanges(IEnumerable<TextChange> changes)
        {
            if (changes == null)
            {
                throw new ArgumentNullException(nameof(changes));
            }

            if (!changes.Any())