File: System\Text\StringBuilder.NativeAot.cs
Web Access
Project: src\src\runtime\src\coreclr\nativeaot\System.Private.CoreLib\src\System.Private.CoreLib.csproj (System.Private.CoreLib)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System.Text
{
    public partial class StringBuilder
    {

        /// <summary>
        /// Calculate the new length for array allocation when marshalling StringBuilder in interop
        /// while taking current capacity into account
        /// This is needed to ensure compat with desktop CLR behavior
        /// </summary>
        internal int GetAllocationLength(int requiredLength)
        {
            int currentLength = Capacity;
            if (currentLength < requiredLength)
            {
                // round the current length to the nearest multiple of 2
                // that is >= the required length
                return (requiredLength + 1) & ~1;
            }

            return currentLength;
        }

        /// <summary>
        /// Throw away the current contents in this StringBuffer and replace it with a new char[]
        /// NOTE: The buffer in StringBuilder is *not* NULL-terminated.
        /// This is only called from MCG code
        /// </summary>
        internal unsafe void ReplaceBuffer(char* newBuffer)
        {
            int len = string.wcslen(newBuffer);

            // the '+1' is for back-compat with desktop CLR in terms of length calculation because desktop
            // CLR had '\0'
            char[] chunkChars = new char[GetAllocationLength(len + 1)];

            new ReadOnlySpan<char>(newBuffer, len).CopyTo(chunkChars);

            ReplaceBufferInternal(chunkChars, len);
        }

        /// <summary>
        /// Throw away the current contents in this StringBuffer and replace it with a new char[]
        /// NOTE: The buffer in StringBuilder is *not* NULL-terminated.
        /// This is only called from MCG code
        /// </summary>
        internal void ReplaceBuffer(char[] chunkCharsCandidate)
        {
            int len = chunkCharsCandidate.Length;
            int newLen = GetAllocationLength(len + 1);
            if (len == newLen)
            {
                ReplaceBufferInternal(chunkCharsCandidate, len);
            }
            else
            {
                char[] chunkChars = new char[GetAllocationLength(len + 1)];

                new ReadOnlySpan<char>(chunkCharsCandidate, 0, len).CopyTo(chunkChars);

                ReplaceBufferInternal(chunkChars, len);
            }
        }

        /// <summary>
        /// Replace the internal buffer with the specified length
        /// This is only called from MCG code
        /// </summary>
        private void ReplaceBufferInternal(char[] chunkChars, int length)
        {
            m_ChunkChars = chunkChars;
            m_ChunkOffset = 0;
            m_ChunkLength = length;
            m_ChunkPrevious = null;
        }

        /// <summary>
        /// Return buffer if single chunk, for MCG interop
        /// </summary>
        internal char[] GetBuffer(out int len)
        {
            len = 0;

            if (m_ChunkOffset == 0)
            {
                len = Length;

                return m_ChunkChars;
            }
            else
            {
                return null;
            }
        }
    }
}