// Copyright (c) Microsoft. All rights reserved. using System; using System.Collections; using System.Collections.Generic; using System.Linq; namespace Microsoft.Agents.AI.Workflows.Generators.Models; /// /// Provides an immutable list implementation which implements sequence equality. /// Copied from: https://github.com/dotnet/runtime/blob/main/src/libraries/Common/src/SourceGenerators/ImmutableEquatableArray.cs /// internal sealed class ImmutableEquatableArray : IEquatable>, IReadOnlyList where T : IEquatable { /// /// Creates a new empty . /// public static ImmutableEquatableArray Empty { get; } = new ImmutableEquatableArray(Array.Empty()); private readonly T[] _values; /// /// Gets the element at the specified index. /// /// /// public T this[int index] => this._values[index]; /// /// Gets the number of elements contained in the collection. /// public int Count => this._values.Length; /// /// Gets whether the array is empty. /// public bool IsEmpty => this._values.Length == 0; /// /// Initializes a new instance of the ImmutableEquatableArray{T} class that contains the elements from the specified /// collection. /// /// The elements from the provided collection are copied into the immutable array. Subsequent /// changes to the original collection do not affect the contents of this array. /// The collection of elements to initialize the array with. Cannot be null. public ImmutableEquatableArray(IEnumerable values) => this._values = values.ToArray(); /// public bool Equals(ImmutableEquatableArray? other) => other != null && ((ReadOnlySpan)this._values).SequenceEqual(other._values); /// public override bool Equals(object? obj) => obj is ImmutableEquatableArray other && this.Equals(other); /// public override int GetHashCode() { int hash = 0; foreach (T value in this._values) { hash = HashHelpers.Combine(hash, value is null ? 0 : value.GetHashCode()); } return hash; } /// public Enumerator GetEnumerator() => new(this._values); IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this._values).GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => this._values.GetEnumerator(); /// public struct Enumerator { private readonly T[] _values; private int _index; internal Enumerator(T[] values) { this._values = values; this._index = -1; } /// public bool MoveNext() { int newIndex = this._index + 1; if ((uint)newIndex < (uint)this._values.Length) { this._index = newIndex; return true; } return false; } /// /// The element at the current position of the enumerator. /// public readonly T Current => this._values[this._index]; } } internal static class ImmutableEquatableArray { public static ImmutableEquatableArray ToImmutableEquatableArray(this IEnumerable values) where T : IEquatable => new(values); } // Copied from https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Numerics/Hashing/HashHelpers.cs#L6 internal static class HashHelpers { public static int Combine(int h1, int h2) { // RyuJIT optimizes this to use the ROL instruction // Related GitHub pull request: https://github.com/dotnet/coreclr/pull/1830 uint rol5 = ((uint)h1 << 5) | ((uint)h1 >> 27); return ((int)rol5 + h1) ^ h2; } }