File: MemoryBuilderExtensions.cs
Web Access
Project: src\src\Razor\src\Shared\Microsoft.AspNetCore.Razor.Utilities.Shared\Microsoft.AspNetCore.Razor.Utilities.Shared.csproj (Microsoft.AspNetCore.Razor.Utilities.Shared)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
 
namespace Microsoft.AspNetCore.Razor;
 
internal static class MemoryBuilderExtensions
{
    public static void Append(this ref MemoryBuilder<ReadOnlyMemory<char>> builder, string value)
    {
        builder.Append(value.AsMemory());
    }
 
    /// <summary>
    ///  Builds a string from the contents of a <see cref="MemoryBuilder{T}"/> where T is <see cref="ReadOnlyMemory{T}"/> of <see cref="char"/>.
    /// </summary>
    /// <param name="builder">
    ///  The memory builder containing <see cref="ReadOnlyMemory{T}"/> of <see cref="char"/> chunks.
    /// </param>
    /// <returns>
    ///  A string created by concatenating all chunks in the builder. Returns <see cref="string.Empty"/> if the builder is empty.
    ///  If the builder contains only one chunk, returns that chunk directly to avoid allocations when possible.
    /// </returns>
    /// <remarks>
    ///  This method is optimized for the common case where the builder contains only one chunk,
    ///  in which case no additional allocation is made if the chunk represents an entire string.
    /// </remarks>
    public static string CreateString(this ref MemoryBuilder<ReadOnlyMemory<char>> builder)
    {
        if (builder.Length == 0)
        {
            return string.Empty;
        }
 
        if (builder.Length == 1)
        {
            // If we only have one chunk, we can return it directly.
            // It is guaranteed to be the same as the content that was originally
            // passed in. Calling ToString() on this will not allocate if the
            // original content represented an entire string.
 
            return builder.AsMemory().Span[0].ToString();
        }
 
        var chunks = builder.AsMemory();
        var length = 0;
 
        foreach (var chunk in chunks.Span)
        {
            length += chunk.Length;
        }
 
        return string.Create(length, chunks, (destination, chunks) =>
        {
            foreach (var chunk in chunks.Span)
            {
                chunk.Span.CopyTo(destination);
                destination = destination[chunk.Length..];
            }
        });
    }
}