File: Language\Syntax\ArrayElement.cs
Web Access
Project: src\src\Razor\src\Compiler\Microsoft.CodeAnalysis.Razor.Compiler\src\Microsoft.CodeAnalysis.Razor.Compiler.csproj (Microsoft.CodeAnalysis.Razor.Compiler)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
#nullable disable
 
namespace Microsoft.AspNetCore.Razor.Language.Syntax;
 
internal struct ArrayElement<T>
{
    public T Value;
 
    public static implicit operator T(ArrayElement<T> element)
    {
        return element.Value;
    }
 
    //NOTE: there is no opposite conversion operator T -> ArrayElement<T>
    //
    // that is because it is preferred to update array elements in-place
    // "elements[i].Value = v" results in much better code than "elements[i] = (ArrayElement<T>)v"
    //
    // The reason is that x86 ABI requires that structs must be returned in
    // a return buffer even if they can fit in a register like this one.
    // Also since struct contains a reference, the write to the buffer is done with a checked GC barrier
    // as JIT does not know if the write goes to a stack or a heap location.
    // Assigning to Value directly easily avoids all this redundancy.
 
    public static ArrayElement<T>[] MakeElementArray(T[] items)
    {
        if (items == null)
        {
            return null;
        }
 
        var array = new ArrayElement<T>[items.Length];
        for (var i = 0; i < items.Length; i++)
        {
            array[i].Value = items[i];
        }
 
        return array;
    }
 
    public static T[] MakeArray(ArrayElement<T>[] items)
    {
        if (items == null)
        {
            return null;
        }
 
        var array = new T[items.Length];
        for (var i = 0; i < items.Length; i++)
        {
            array[i] = items[i].Value;
        }
 
        return array;
    }
}