|
// 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;
using System.Linq;
using System.Runtime.CompilerServices;
namespace Microsoft.CodeAnalysis.Shared.Collections
{
internal static class TemporaryArrayExtensions
{
/// <summary>
/// Gets a mutable reference to a <see cref="TemporaryArray{T}"/> stored in a <c>using</c> variable.
/// </summary>
/// <remarks>
/// <para>This supporting method allows <see cref="TemporaryArray{T}"/>, a non-copyable <see langword="struct"/>
/// implementing <see cref="IDisposable"/>, to be used with <c>using</c> statements while still allowing them to
/// be passed by reference in calls. The following two calls are equivalent:</para>
///
/// <code>
/// using var array = TemporaryArray<T>.Empty;
///
/// // Using the 'Unsafe.AsRef' method
/// Method(ref Unsafe.AsRef(in array));
///
/// // Using this helper method
/// Method(ref array.AsRef());
/// </code>
///
/// <para>⚠ Do not move or rename this method without updating the corresponding
/// <see href="https://github.com/dotnet/roslyn-analyzers/blob/30180a51af8c4711e51d98df7345f14d083efb63/src/Roslyn.Diagnostics.Analyzers/Core/TemporaryArrayAsRefAnalyzer.cs">RS0049</see>
/// analyzer.</para>
/// </remarks>
/// <typeparam name="T">The type of element stored in the temporary array.</typeparam>
/// <param name="array">A read-only reference to a temporary array which is part of a <c>using</c> statement.</param>
/// <returns>A mutable reference to the temporary array.</returns>
public static ref TemporaryArray<T> AsRef<T>(this in TemporaryArray<T> array)
#pragma warning disable RS0042 // https://github.com/dotnet/roslyn-analyzers/issues/7128
=> ref Unsafe.AsRef(in array);
#pragma warning restore RS0042
public static bool Any<T>(this in TemporaryArray<T> array, Func<T, bool> predicate)
{
foreach (var item in array)
{
if (predicate(item))
return true;
}
return false;
}
public static bool All<T>(this in TemporaryArray<T> array, Func<T, bool> predicate)
{
foreach (var item in array)
{
if (!predicate(item))
return false;
}
return true;
}
private static void ThrowSequenceContainsMoreThanOneElement()
=> new[] { 0, 0 }.Single();
public static T? SingleOrDefault<T>(this in TemporaryArray<T> array, Func<T, bool> predicate)
{
var first = true;
T? result = default;
foreach (var item in array)
{
if (predicate(item))
{
if (!first)
{
ThrowSequenceContainsMoreThanOneElement();
}
first = false;
result = item;
}
}
return result;
}
public static T? SingleOrDefault<T, TArg>(this in TemporaryArray<T> array, Func<T, TArg, bool> predicate, TArg arg)
{
var first = true;
T? result = default;
foreach (var item in array)
{
if (predicate(item, arg))
{
if (!first)
{
ThrowSequenceContainsMoreThanOneElement();
}
first = false;
result = item;
}
}
return result;
}
public static T? FirstOrDefault<T>(this in TemporaryArray<T> array)
=> array.Count > 0 ? array[0] : default;
public static T? FirstOrDefault<T, TArg>(this in TemporaryArray<T> array, Func<T, TArg, bool> predicate, TArg arg)
{
foreach (var item in array)
{
if (predicate(item, arg))
return item;
}
return default;
}
public static int IndexOf<T, TArg>(this in TemporaryArray<T> array, Func<T, TArg, bool> predicate, TArg arg)
{
var index = 0;
foreach (var item in array)
{
if (predicate(item, arg))
return index;
index++;
}
return -1;
}
public static void AddIfNotNull<T>(this ref TemporaryArray<T> array, T? value)
where T : struct
{
if (value is not null)
{
array.Add(value.Value);
}
}
public static void AddIfNotNull<T>(this ref TemporaryArray<T> array, T? value)
where T : class
{
if (value is not null)
{
array.Add(value);
}
}
}
}
|