File: src\Dependencies\Collections\SegmentedCollectionsMarshal.cs
Web Access
Project: src\src\Workspaces\Core\Portable\Microsoft.CodeAnalysis.Workspaces.csproj (Microsoft.CodeAnalysis.Workspaces)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System.Diagnostics.CodeAnalysis;
 
namespace Microsoft.CodeAnalysis.Collections;
 
/// <summary>
/// An unsafe class that provides a set of methods to access the underlying data representations of immutable segmented
/// collections.
/// </summary>
internal static class SegmentedCollectionsMarshal
{
    /// <summary>
    /// Gets the backing storage array for a <see cref="SegmentedArray{T}"/>.
    /// </summary>
    /// <typeparam name="T">The type of elements stored in the array.</typeparam>
    /// <param name="array">The segmented array.</param>
    /// <returns>The backing storage array for the segmented array. Note that replacing segments within the returned
    /// value will invalidate the <see cref="SegmentedArray{T}"/> data structure.</returns>
    public static T[][] AsSegments<T>(SegmentedArray<T> array)
        => SegmentedArray<T>.PrivateMarshal.AsSegments(array);
 
    /// <summary>
    /// Gets a <see cref="SegmentedArray{T}"/> value wrapping the input T[][].
    /// </summary>
    /// <typeparam name="T">The type of elements in the input.</typeparam>
    /// <param name="length">The combined length of the input arrays</param>
    /// <param name="segments">The input array to wrap in the returned <see cref="SegmentedArray{T}"/> value.</param>
    /// <returns>A <see cref="SegmentedArray{T}"/> value wrapping <paramref name="segments"/>.</returns>
    /// <remarks>
    /// <para>
    /// When using this method, callers should take extra care to ensure that they're the sole owners of the input
    /// array, and that it won't be modified once the returned <see cref="SegmentedArray{T}"/> value starts
    /// being used. Doing so might cause undefined behavior in code paths which don't expect the contents of a given
    /// <see cref="SegmentedArray{T}"/> values to change outside their control.
    /// </para>
    /// </remarks>
    /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="segments"/> is <see langword="null"/></exception>
    public static SegmentedArray<T> AsSegmentedArray<T>(int length, T[][] segments)
        => SegmentedArray<T>.PrivateMarshal.AsSegmentedArray(length, segments);
 
    /// <summary>
    /// Gets either a ref to a <typeparamref name="TValue"/> in the <see cref="SegmentedDictionary{TKey, TValue}"/> or a
    /// ref null if it does not exist in the <paramref name="dictionary"/>.
    /// </summary>
    /// <param name="dictionary">The dictionary to get the ref to <typeparamref name="TValue"/> from.</param>
    /// <param name="key">The key used for lookup.</param>
    /// <typeparam name="TKey">The type of the keys in the dictionary.</typeparam>
    /// <typeparam name="TValue">The type of the values in the dictionary.</typeparam>
    /// <remarks>
    /// Items should not be added or removed from the <see cref="SegmentedDictionary{TKey, TValue}"/> while the ref
    /// <typeparamref name="TValue"/> is in use. The ref null can be detected using <see cref="M:System.Runtime.CompilerServices.Unsafe.IsNullRef``1(``0@)"/>.
    /// </remarks>
    [SuppressMessage("Documentation", "CA1200", Justification = "Not all targets can resolve the documented method reference.")]
    public static ref TValue GetValueRefOrNullRef<TKey, TValue>(SegmentedDictionary<TKey, TValue> dictionary, TKey key)
        where TKey : notnull
        => ref SegmentedDictionary<TKey, TValue>.PrivateMarshal.FindValue(dictionary, key);
 
    /// <summary>
    /// Gets either a read-only ref to a <typeparamref name="TValue"/> in the <see cref="ImmutableSegmentedDictionary{TKey, TValue}"/>
    /// or a ref null if it does not exist in the <paramref name="dictionary"/>.
    /// </summary>
    /// <param name="dictionary">The dictionary to get the ref to <typeparamref name="TValue"/> from.</param>
    /// <param name="key">The key used for lookup.</param>
    /// <typeparam name="TKey">The type of the keys in the dictionary.</typeparam>
    /// <typeparam name="TValue">The type of the values in the dictionary.</typeparam>
    /// <remarks>
    /// The ref null can be detected using <see cref="M:System.Runtime.CompilerServices.Unsafe.IsNullRef``1(``0@)"/>.
    /// </remarks>
    [SuppressMessage("Documentation", "CA1200", Justification = "Not all targets can resolve the documented method reference.")]
    public static ref readonly TValue GetValueRefOrNullRef<TKey, TValue>(ImmutableSegmentedDictionary<TKey, TValue> dictionary, TKey key)
        where TKey : notnull
        => ref ImmutableSegmentedDictionary<TKey, TValue>.PrivateMarshal.FindValue(dictionary, key);
 
    /// <summary>
    /// Gets either a ref to a <typeparamref name="TValue"/> in the <see cref="ImmutableSegmentedDictionary{TKey, TValue}.Builder"/>
    /// or a ref null if it does not exist in the <paramref name="dictionary"/>.
    /// </summary>
    /// <param name="dictionary">The dictionary to get the ref to <typeparamref name="TValue"/> from.</param>
    /// <param name="key">The key used for lookup.</param>
    /// <typeparam name="TKey">The type of the keys in the dictionary.</typeparam>
    /// <typeparam name="TValue">The type of the values in the dictionary.</typeparam>
    /// <remarks>
    /// Items should not be added or removed from the <see cref="ImmutableSegmentedDictionary{TKey, TValue}.Builder"/>
    /// while the ref <typeparamref name="TValue"/> is in use. The ref null can be detected using
    /// <see cref="M:System.Runtime.CompilerServices.Unsafe.IsNullRef``1(``0@)"/>.
    /// </remarks>
    [SuppressMessage("Documentation", "CA1200", Justification = "Not all targets can resolve the documented method reference.")]
    public static ref TValue GetValueRefOrNullRef<TKey, TValue>(ImmutableSegmentedDictionary<TKey, TValue>.Builder dictionary, TKey key)
        where TKey : notnull
        => ref ImmutableSegmentedDictionary<TKey, TValue>.Builder.PrivateMarshal.FindValue(dictionary, key);
 
    /// <summary>
    /// Gets an <see cref="ImmutableSegmentedList{T}"/> value wrapping the input <see cref="SegmentedList{T}"/>.
    /// </summary>
    /// <typeparam name="T">The type of elements in the input segmented list.</typeparam>
    /// <param name="list">The input segmented list to wrap in the returned <see cref="ImmutableSegmentedList{T}"/> value.</param>
    /// <returns>An <see cref="ImmutableSegmentedList{T}"/> value wrapping <paramref name="list"/>.</returns>
    /// <remarks>
    /// <para>
    /// When using this method, callers should take extra care to ensure that they're the sole owners of the input
    /// list, and that it won't be modified once the returned <see cref="ImmutableSegmentedList{T}"/> value starts
    /// being used. Doing so might cause undefined behavior in code paths which don't expect the contents of a given
    /// <see cref="ImmutableSegmentedList{T}"/> values to change after its creation.
    /// </para>
    /// <para>
    /// If <paramref name="list"/> is <see langword="null"/>, the returned <see cref="ImmutableSegmentedList{T}"/> value
    /// will be uninitialized (i.e. its <see cref="ImmutableSegmentedList{T}.IsDefault"/> property will be
    /// <see langword="true"/>).
    /// </para>
    /// </remarks>
    public static ImmutableSegmentedList<T> AsImmutableSegmentedList<T>(SegmentedList<T>? list)
        => ImmutableSegmentedList<T>.PrivateMarshal.AsImmutableSegmentedList(list);
 
    /// <summary>
    /// Gets the underlying <see cref="SegmentedList{T}"/> for an input <see cref="ImmutableSegmentedList{T}"/> value.
    /// </summary>
    /// <typeparam name="T">The type of elements in the input <see cref="ImmutableSegmentedList{T}"/> value.</typeparam>
    /// <param name="list">The input <see cref="ImmutableSegmentedList{T}"/> value to get the underlying <see cref="SegmentedList{T}"/> from.</param>
    /// <returns>The underlying <see cref="SegmentedList{T}"/> for <paramref name="list"/>, if present; otherwise, <see langword="null"/>.</returns>
    /// <remarks>
    /// <para>
    /// When using this method, callers should make sure to not pass the resulting underlying list to methods that
    /// might mutate it. Doing so might cause undefined behavior in code paths using <paramref name="list"/> which
    /// don't expect the contents of the <see cref="ImmutableSegmentedList{T}"/> value to change.
    /// </para>
    /// <para>
    /// If <paramref name="list"/> is uninitialized (i.e. its <see cref="ImmutableSegmentedList{T}.IsDefault"/> property is
    /// <see langword="true"/>), the resulting <see cref="SegmentedList{T}"/> will be <see langword="null"/>.
    /// </para>
    /// </remarks>
    public static SegmentedList<T>? AsSegmentedList<T>(ImmutableSegmentedList<T> list)
        => ImmutableSegmentedList<T>.PrivateMarshal.AsSegmentedList(list);
 
    /// <summary>
    /// Gets an <see cref="ImmutableSegmentedHashSet{T}"/> value wrapping the input <see cref="SegmentedHashSet{T}"/>.
    /// </summary>
    /// <typeparam name="T">The type of elements in the input segmented hash set.</typeparam>
    /// <param name="set">The input segmented hash set to wrap in the returned <see cref="ImmutableSegmentedHashSet{T}"/> value.</param>
    /// <returns>An <see cref="ImmutableSegmentedHashSet{T}"/> value wrapping <paramref name="set"/>.</returns>
    /// <remarks>
    /// <para>
    /// When using this method, callers should take extra care to ensure that they're the sole owners of the input
    /// set, and that it won't be modified once the returned <see cref="ImmutableSegmentedHashSet{T}"/> value starts
    /// being used. Doing so might cause undefined behavior in code paths which don't expect the contents of a given
    /// <see cref="ImmutableSegmentedHashSet{T}"/> values to change after its creation.
    /// </para>
    /// <para>
    /// If <paramref name="set"/> is <see langword="null"/>, the returned <see cref="ImmutableSegmentedHashSet{T}"/>
    /// value will be uninitialized (i.e. its <see cref="ImmutableSegmentedHashSet{T}.IsDefault"/> property will be
    /// <see langword="true"/>).
    /// </para>
    /// </remarks>
    public static ImmutableSegmentedHashSet<T> AsImmutableSegmentedHashSet<T>(SegmentedHashSet<T>? set)
        => ImmutableSegmentedHashSet<T>.PrivateMarshal.AsImmutableSegmentedHashSet(set);
 
    /// <summary>
    /// Gets the underlying <see cref="SegmentedHashSet{T}"/> for an input <see cref="ImmutableSegmentedHashSet{T}"/> value.
    /// </summary>
    /// <typeparam name="T">The type of elements in the input <see cref="ImmutableSegmentedHashSet{T}"/> value.</typeparam>
    /// <param name="set">The input <see cref="ImmutableSegmentedHashSet{T}"/> value to get the underlying <see cref="SegmentedHashSet{T}"/> from.</param>
    /// <returns>The underlying <see cref="SegmentedHashSet{T}"/> for <paramref name="set"/>, if present; otherwise, <see langword="null"/>.</returns>
    /// <remarks>
    /// <para>
    /// When using this method, callers should make sure to not pass the resulting underlying hash set to methods that
    /// might mutate it. Doing so might cause undefined behavior in code paths using <paramref name="set"/> which
    /// don't expect the contents of the <see cref="ImmutableSegmentedHashSet{T}"/> value to change.
    /// </para>
    /// <para>
    /// If <paramref name="set"/> is uninitialized (i.e. its <see cref="ImmutableSegmentedHashSet{T}.IsDefault"/>
    /// property is <see langword="true"/>), the resulting <see cref="SegmentedHashSet{T}"/> will be <see langword="null"/>.
    /// </para>
    /// </remarks>
    public static SegmentedHashSet<T>? AsSegmentedHashSet<T>(ImmutableSegmentedHashSet<T> set)
        => ImmutableSegmentedHashSet<T>.PrivateMarshal.AsSegmentedHashSet(set);
 
    /// <summary>
    /// Gets an <see cref="ImmutableSegmentedDictionary{TKey, TValue}"/> value wrapping the input <see cref="SegmentedDictionary{TKey, TValue}"/>.
    /// </summary>
    /// <typeparam name="TKey">The type of keys in the input segmented dictionary.</typeparam>
    /// <typeparam name="TValue">The type of values in the input segmented dictionary.</typeparam>
    /// <param name="dictionary">The input segmented dictionary to wrap in the returned <see cref="ImmutableSegmentedDictionary{TKey, TValue}"/> value.</param>
    /// <returns>An <see cref="ImmutableSegmentedDictionary{TKey, TValue}"/> value wrapping <paramref name="dictionary"/>.</returns>
    /// <remarks>
    /// <para>
    /// When using this method, callers should take extra care to ensure that they're the sole owners of the input
    /// dictionary, and that it won't be modified once the returned <see cref="ImmutableSegmentedDictionary{TKey, TValue}"/>
    /// value starts being used. Doing so might cause undefined behavior in code paths which don't expect the contents
    /// of a given <see cref="ImmutableSegmentedDictionary{TKey, TValue}"/> values to change after its creation.
    /// </para>
    /// <para>
    /// If <paramref name="dictionary"/> is <see langword="null"/>, the returned <see cref="ImmutableSegmentedDictionary{TKey, TValue}"/>
    /// value will be uninitialized (i.e. its <see cref="ImmutableSegmentedDictionary{TKey, TValue}.IsDefault"/>
    /// property will be <see langword="true"/>).
    /// </para>
    /// </remarks>
    public static ImmutableSegmentedDictionary<TKey, TValue> AsImmutableSegmentedDictionary<TKey, TValue>(SegmentedDictionary<TKey, TValue>? dictionary)
        where TKey : notnull
        => ImmutableSegmentedDictionary<TKey, TValue>.PrivateMarshal.AsImmutableSegmentedDictionary(dictionary);
 
    /// <summary>
    /// Gets the underlying <see cref="SegmentedDictionary{TKey, TValue}"/> for an input <see cref="ImmutableSegmentedDictionary{TKey, TValue}"/> value.
    /// </summary>
    /// <typeparam name="TKey">The type of keys in the input <see cref="ImmutableSegmentedDictionary{TKey, TValue}"/> value.</typeparam>
    /// <typeparam name="TValue">The type of values in the input <see cref="ImmutableSegmentedDictionary{TKey, TValue}"/> value.</typeparam>
    /// <param name="dictionary">The input <see cref="ImmutableSegmentedDictionary{TKey, TValue}"/> value to get the underlying <see cref="SegmentedDictionary{TKey, TValue}"/> from.</param>
    /// <returns>The underlying <see cref="SegmentedDictionary{TKey, TValue}"/> for <paramref name="dictionary"/>, if present; otherwise, <see langword="null"/>.</returns>
    /// <remarks>
    /// <para>
    /// When using this method, callers should make sure to not pass the resulting underlying dictionary to methods that
    /// might mutate it. Doing so might cause undefined behavior in code paths using <paramref name="dictionary"/> which
    /// don't expect the contents of the <see cref="ImmutableSegmentedDictionary{TKey, TValue}"/> value to change.
    /// </para>
    /// <para>
    /// If <paramref name="dictionary"/> is uninitialized (i.e. its <see cref="ImmutableSegmentedDictionary{TKey, TValue}.IsDefault"/>
    /// property is <see langword="true"/>), the resulting <see cref="SegmentedDictionary{TKey, TValue}"/> will be <see langword="null"/>.
    /// </para>
    /// </remarks>
    public static SegmentedDictionary<TKey, TValue>? AsSegmentedDictionary<TKey, TValue>(ImmutableSegmentedDictionary<TKey, TValue> dictionary)
        where TKey : notnull
        => ImmutableSegmentedDictionary<TKey, TValue>.PrivateMarshal.AsSegmentedDictionary(dictionary);
}