mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-09-07 16:36:52 +02:00
219 lines
7.9 KiB
C#
219 lines
7.9 KiB
C#
// Licensed to the .NET Foundation under one or more agreements.
|
|
// The .NET Foundation licenses this file to you under the MIT license.
|
|
// Taken from https://github.com/CommunityToolkit/dotnet/blob/ecd1711b740f4f88d2bb943ce292ae4fc90df1bc/src/CommunityToolkit.Mvvm.SourceGenerators/Helpers/EquatableArray%7BT%7D.cs
|
|
|
|
using System.Collections;
|
|
using System.Collections.Immutable;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Runtime.CompilerServices;
|
|
|
|
namespace Robust.Roslyn.Shared.Helpers;
|
|
|
|
#nullable enable
|
|
|
|
/// <summary>
|
|
/// Extensions for <see cref="EquatableArray{T}"/>.
|
|
/// </summary>
|
|
public static class EquatableArray
|
|
{
|
|
/// <summary>
|
|
/// Creates an <see cref="EquatableArray{T}"/> instance from a given <see cref="ImmutableArray{T}"/>.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of items in the input array.</typeparam>
|
|
/// <param name="array">The input <see cref="ImmutableArray{T}"/> instance.</param>
|
|
/// <returns>An <see cref="EquatableArray{T}"/> instance from a given <see cref="ImmutableArray{T}"/>.</returns>
|
|
public static EquatableArray<T> AsEquatableArray<T>(this ImmutableArray<T> array)
|
|
where T : IEquatable<T>
|
|
{
|
|
return new(array);
|
|
}
|
|
|
|
public static EquatableArray<T> AsEquatableArray<T>(this IEnumerable<T> enumerable)
|
|
where T : IEquatable<T>
|
|
{
|
|
return enumerable.ToImmutableArray().AsEquatableArray();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// An immutable, equatable array. This is equivalent to <see cref="ImmutableArray{T}"/> but with value equality support.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of values in the array.</typeparam>
|
|
public readonly struct EquatableArray<T> : IEquatable<EquatableArray<T>>, IEnumerable<T>
|
|
where T : IEquatable<T>
|
|
{
|
|
/// <summary>
|
|
/// The underlying <typeparamref name="T"/> array.
|
|
/// </summary>
|
|
private readonly T[]? array;
|
|
|
|
/// <summary>
|
|
/// Creates a new <see cref="EquatableArray{T}"/> instance.
|
|
/// </summary>
|
|
/// <param name="array">The input <see cref="ImmutableArray{T}"/> to wrap.</param>
|
|
public EquatableArray(ImmutableArray<T> array)
|
|
{
|
|
this.array = Unsafe.As<ImmutableArray<T>, T[]?>(ref array);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a reference to an item at a specified position within the array.
|
|
/// </summary>
|
|
/// <param name="index">The index of the item to retrieve a reference to.</param>
|
|
/// <returns>A reference to an item at a specified position within the array.</returns>
|
|
public ref readonly T this[int index]
|
|
{
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
get => ref AsImmutableArray().ItemRef(index);
|
|
}
|
|
|
|
public int Length => AsImmutableArray().Length;
|
|
|
|
/// <summary>
|
|
/// Gets a value indicating whether the current array is empty.
|
|
/// </summary>
|
|
public bool IsEmpty
|
|
{
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
get => AsImmutableArray().IsEmpty;
|
|
}
|
|
|
|
/// <sinheritdoc/>
|
|
public bool Equals(EquatableArray<T> array)
|
|
{
|
|
return AsSpan().SequenceEqual(array.AsSpan());
|
|
}
|
|
|
|
/// <sinheritdoc/>
|
|
public override bool Equals([NotNullWhen(true)] object? obj)
|
|
{
|
|
return obj is EquatableArray<T> array && Equals(this, array);
|
|
}
|
|
|
|
/// <sinheritdoc/>
|
|
public override int GetHashCode()
|
|
{
|
|
if (this.array is not T[] array)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
HashCode hashCode = default;
|
|
|
|
foreach (T item in array)
|
|
{
|
|
hashCode.Add(item);
|
|
}
|
|
|
|
return hashCode.ToHashCode();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets an <see cref="ImmutableArray{T}"/> instance from the current <see cref="EquatableArray{T}"/>.
|
|
/// </summary>
|
|
/// <returns>The <see cref="ImmutableArray{T}"/> from the current <see cref="EquatableArray{T}"/>.</returns>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public ImmutableArray<T> AsImmutableArray()
|
|
{
|
|
if (array == null)
|
|
return ImmutableArray<T>.Empty;
|
|
|
|
// If you check for null, you get a null warning here
|
|
// If you introduce a variable, you also get null if you use it in both places instead of just 1
|
|
// I don't know man
|
|
// Regardless, this fixes [] resulting in a default EquatableArray which means a null array
|
|
// Which leads to calling IsEmpty throwing an NRE, which is not very intuitive
|
|
// You could also just not use Unsafe.As here, but I guess we need to save 0.001 nanoseconds
|
|
return Unsafe.As<T[]?, ImmutableArray<T>>(ref Unsafe.AsRef(in array)!);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates an <see cref="EquatableArray{T}"/> instance from a given <see cref="ImmutableArray{T}"/>.
|
|
/// </summary>
|
|
/// <param name="array">The input <see cref="ImmutableArray{T}"/> instance.</param>
|
|
/// <returns>An <see cref="EquatableArray{T}"/> instance from a given <see cref="ImmutableArray{T}"/>.</returns>
|
|
public static EquatableArray<T> FromImmutableArray(ImmutableArray<T> array)
|
|
{
|
|
return new(array);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a <see cref="ReadOnlySpan{T}"/> wrapping the current items.
|
|
/// </summary>
|
|
/// <returns>A <see cref="ReadOnlySpan{T}"/> wrapping the current items.</returns>
|
|
public ReadOnlySpan<T> AsSpan()
|
|
{
|
|
return AsImmutableArray().AsSpan();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Copies the contents of this <see cref="EquatableArray{T}"/> instance to a mutable array.
|
|
/// </summary>
|
|
/// <returns>The newly instantiated array.</returns>
|
|
public T[] ToArray()
|
|
{
|
|
return AsImmutableArray().ToArray();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets an <see cref="ImmutableArray{T}.Enumerator"/> value to traverse items in the current array.
|
|
/// </summary>
|
|
/// <returns>An <see cref="ImmutableArray{T}.Enumerator"/> value to traverse items in the current array.</returns>
|
|
public ImmutableArray<T>.Enumerator GetEnumerator()
|
|
{
|
|
return AsImmutableArray().GetEnumerator();
|
|
}
|
|
|
|
/// <sinheritdoc/>
|
|
IEnumerator<T> IEnumerable<T>.GetEnumerator()
|
|
{
|
|
return ((IEnumerable<T>)AsImmutableArray()).GetEnumerator();
|
|
}
|
|
|
|
/// <sinheritdoc/>
|
|
IEnumerator IEnumerable.GetEnumerator()
|
|
{
|
|
return ((IEnumerable)AsImmutableArray()).GetEnumerator();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Implicitly converts an <see cref="ImmutableArray{T}"/> to <see cref="EquatableArray{T}"/>.
|
|
/// </summary>
|
|
/// <returns>An <see cref="EquatableArray{T}"/> instance from a given <see cref="ImmutableArray{T}"/>.</returns>
|
|
public static implicit operator EquatableArray<T>(ImmutableArray<T> array)
|
|
{
|
|
return FromImmutableArray(array);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Implicitly converts an <see cref="EquatableArray{T}"/> to <see cref="ImmutableArray{T}"/>.
|
|
/// </summary>
|
|
/// <returns>An <see cref="ImmutableArray{T}"/> instance from a given <see cref="EquatableArray{T}"/>.</returns>
|
|
public static implicit operator ImmutableArray<T>(EquatableArray<T> array)
|
|
{
|
|
return array.AsImmutableArray();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks whether two <see cref="EquatableArray{T}"/> values are the same.
|
|
/// </summary>
|
|
/// <param name="left">The first <see cref="EquatableArray{T}"/> value.</param>
|
|
/// <param name="right">The second <see cref="EquatableArray{T}"/> value.</param>
|
|
/// <returns>Whether <paramref name="left"/> and <paramref name="right"/> are equal.</returns>
|
|
public static bool operator ==(EquatableArray<T> left, EquatableArray<T> right)
|
|
{
|
|
return left.Equals(right);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks whether two <see cref="EquatableArray{T}"/> values are not the same.
|
|
/// </summary>
|
|
/// <param name="left">The first <see cref="EquatableArray{T}"/> value.</param>
|
|
/// <param name="right">The second <see cref="EquatableArray{T}"/> value.</param>
|
|
/// <returns>Whether <paramref name="left"/> and <paramref name="right"/> are not equal.</returns>
|
|
public static bool operator !=(EquatableArray<T> left, EquatableArray<T> right)
|
|
{
|
|
return !left.Equals(right);
|
|
}
|
|
}
|