|
| 1 | +using System.Collections; |
| 2 | +using System.Collections.Immutable; |
| 3 | +using System.Diagnostics.CodeAnalysis; |
| 4 | +using System.Runtime.CompilerServices; |
| 5 | +using System.Runtime.InteropServices; |
| 6 | + |
| 7 | +#pragma warning disable IDE0303 // Simplify collection initialization |
| 8 | +#pragma warning disable CA1305 // Specify IFormatProvider |
| 9 | + |
| 10 | +namespace Singulink.Collections; |
| 11 | + |
| 12 | +/// <summary> |
| 13 | +/// Provides methods for creating an <see cref="ComparerEquatableArray{T}"/>. |
| 14 | +/// </summary> |
| 15 | +public static class ComparerEquatableArray |
| 16 | +{ |
| 17 | + /// <summary> |
| 18 | + /// Returns an instance of the <see cref="ComparerEquatableArray{T}"/> class from the given collection with the default comparer. |
| 19 | + /// </summary> |
| 20 | + /// <remarks> |
| 21 | + /// Note: values of the collection are assumed to be immutable and interchangeable (that is, the standard equality and hash code contracts must be held, but |
| 22 | + /// also must be consistent indefinitely, and the value you read out of the array is only guaranteed to be equal to the one passed in, not necessarily the |
| 23 | + /// same instance or bits). |
| 24 | + /// </remarks> |
| 25 | + public static ComparerEquatableArray<T> Create<T>(ImmutableArray<T> items) => Create((IEqualityComparer<T>)null, items); |
| 26 | + |
| 27 | + /// <inheritdoc cref="Create{T}(ImmutableArray{T})" /> |
| 28 | + public static ComparerEquatableArray<T> Create<T>(IEnumerable<T> items) => Create((IEqualityComparer<T>)null, items); |
| 29 | + |
| 30 | + /// <inheritdoc cref="Create{T}(ImmutableArray{T})" /> |
| 31 | + public static ComparerEquatableArray<T> Create<T>(params ReadOnlySpan<T> items) => Create(null, items); |
| 32 | + |
| 33 | + /// <inheritdoc cref="Create{T}(ImmutableArray{T})" /> |
| 34 | + public static ComparerEquatableArray<T> Create<T>(params T[] items) => Create((IEqualityComparer<T>)null, items); |
| 35 | + |
| 36 | + /// <summary> |
| 37 | + /// Returns an instance of the <see cref="ComparerEquatableArray{T}"/> class from the given collection with the specified comparer. |
| 38 | + /// </summary> |
| 39 | + /// <remarks> |
| 40 | + /// <para>Note: values of the collection are assumed to be immutable and interchangeable (that is, the standard equality and hash code contracts must be held, but |
| 41 | + /// also must be consistent indefinitely, and the value you read out of the array is only guaranteed to be equal to the one passed in, not necessarily the |
| 42 | + /// same instance or bits).</para> |
| 43 | + /// <para> |
| 44 | + /// Note: the values for the comparer are compared by reference equality, but with <see langword="null" /> considered equivalent to |
| 45 | + /// <see cref="EqualityComparer{T}.Default" />.</para> |
| 46 | + /// </remarks> |
| 47 | + public static ComparerEquatableArray<T> Create<T>(IEqualityComparer<T>? comparer, ImmutableArray<T> items) |
| 48 | + { |
| 49 | + if ((comparer == null || comparer == EqualityComparer<T>.Default) && (items == default || items.Length == 0)) |
| 50 | + return ComparerEquatableArray<T>.Empty; |
| 51 | + |
| 52 | + return new(items, comparer); |
| 53 | + } |
| 54 | + |
| 55 | + /// <inheritdoc cref="Create{T}(IEqualityComparer{T}?, ImmutableArray{T})" /> |
| 56 | + public static ComparerEquatableArray<T> Create<T>(IEqualityComparer<T>? comparer, IEnumerable<T> items) |
| 57 | + { |
| 58 | + // Optimize for common simple cases: |
| 59 | + |
| 60 | + if (items is ImmutableArray<T> immutableArray) |
| 61 | + return Create(comparer, immutableArray); |
| 62 | + |
| 63 | + if (items is ComparerEquatableArray<T> comparerEquatableArray) |
| 64 | + { |
| 65 | + if (comparerEquatableArray.Comparer == (comparer ?? EqualityComparer<T>.Default)) |
| 66 | + return comparerEquatableArray; |
| 67 | + else |
| 68 | + return Create(comparer, comparerEquatableArray.UnderlyingArray); |
| 69 | + } |
| 70 | + |
| 71 | + if (items is EquatableArray<T> equatableArray) |
| 72 | + { |
| 73 | + return Create(comparer, equatableArray.UnderlyingArray); |
| 74 | + } |
| 75 | + |
| 76 | + if ( |
| 77 | + (comparer == null || comparer == EqualityComparer<T>.Default) && |
| 78 | +#if NET |
| 79 | + items.TryGetNonEnumeratedCount(out int count) && count == 0) |
| 80 | +#else |
| 81 | + items is ICollection<T> { Count: 0 } or ICollection { Count: 0 }) |
| 82 | +#endif |
| 83 | + { |
| 84 | + return ComparerEquatableArray<T>.Empty; |
| 85 | + } |
| 86 | + |
| 87 | + // Otherwise, just create from the full collection: |
| 88 | + return new ComparerEquatableArray<T>(ImmutableArray.CreateRange(items), comparer); |
| 89 | + } |
| 90 | + |
| 91 | + /// <inheritdoc cref="Create{T}(IEqualityComparer{T}?, ImmutableArray{T})" /> |
| 92 | + public static ComparerEquatableArray<T> Create<T>(IEqualityComparer<T>? comparer, params ReadOnlySpan<T> items) |
| 93 | + { |
| 94 | + if (items.Length == 0 && (comparer == null || comparer == EqualityComparer<T>.Default)) |
| 95 | + return ComparerEquatableArray<T>.Empty; |
| 96 | + |
| 97 | +#if NET |
| 98 | + var array = GC.AllocateUninitializedArray<T>(items.Length); |
| 99 | +#else |
| 100 | + var array = new T[items.Length]; |
| 101 | +#endif |
| 102 | + |
| 103 | + items.CopyTo(array); |
| 104 | + |
| 105 | +#if NET8_0_OR_GREATER |
| 106 | + var immutableArray = ImmutableCollectionsMarshal.AsImmutableArray(array); |
| 107 | +#else |
| 108 | + var immutableArray = Unsafe.As<T[], ImmutableArray<T>>(ref array); |
| 109 | +#endif |
| 110 | + |
| 111 | + return new ComparerEquatableArray<T>(immutableArray, comparer); |
| 112 | + } |
| 113 | + |
| 114 | + /// <inheritdoc cref="Create{T}(IEqualityComparer{T}?, ImmutableArray{T})" /> |
| 115 | + public static ComparerEquatableArray<T> Create<T>(IEqualityComparer<T>? comparer, params T[] items) => Create(comparer, (ReadOnlySpan<T>)items); |
| 116 | + |
| 117 | + /// <inheritdoc cref="Create{T}(IEqualityComparer{T}?, ImmutableArray{T})" /> |
| 118 | + public static ComparerEquatableArray<T> ToComparerEquatableArray<T>(this ImmutableArray<T> value, IEqualityComparer<T>? comparer = null) => Create(comparer, value); |
| 119 | + |
| 120 | + /// <inheritdoc cref="Create{T}(IEqualityComparer{T}?, ImmutableArray{T})" /> |
| 121 | + public static ComparerEquatableArray<T> ToEquatableArray<T>(this IEnumerable<T> value, IEqualityComparer<T>? comparer = null) => Create(comparer, value); |
| 122 | + |
| 123 | + /// <inheritdoc cref="Create{T}(IEqualityComparer{T}?, ImmutableArray{T})" /> |
| 124 | + public static ComparerEquatableArray<T> ToEquatableArray<T>(this ReadOnlySpan<T> value, IEqualityComparer<T>? comparer = null) => Create(comparer, value); |
| 125 | +} |
| 126 | + |
| 127 | +/// <summary> |
| 128 | +/// An immutable array wrapper that provides value-based equality semantics with a custom comparer. |
| 129 | +/// </summary> |
| 130 | +/// <remarks> |
| 131 | +/// Note: values of the array are assumed to be immutable and interchangeable (that is, the standard equality and hash code contracts must be held, but also |
| 132 | +/// must be consistent indefinitely, and the value you read out of the array is only guaranteed to be equal to the one passed in, not necessarily the same |
| 133 | +/// instance or bits). |
| 134 | +/// </remarks> |
| 135 | +[CollectionBuilder(typeof(ComparerEquatableArray), "Create")] |
| 136 | +public sealed class ComparerEquatableArray<T> : IReadOnlyList<T>, IList<T>, IEquatable<ComparerEquatableArray<T>>, IFormattable |
| 137 | +{ |
| 138 | + // See EquatableArrayImpl for explanation. |
| 139 | + private static nint _staticCreateIndex; |
| 140 | + |
| 141 | + // Comparer field: |
| 142 | + private readonly IEqualityComparer<T>? _comparer; |
| 143 | + |
| 144 | + // Impl field: |
| 145 | + private EquatableArrayImpl<T> _impl; |
| 146 | + |
| 147 | + /// <summary> |
| 148 | + /// Initializes a new instance of the <see cref="ComparerEquatableArray{T}"/> class from the given immutable array and comparer. |
| 149 | + /// </summary> |
| 150 | + /// <remarks> |
| 151 | + /// <para> |
| 152 | + /// Note: values of the array are assumed to be immutable and interchangeable (that is, the standard equality and hash code contracts must be held, but also |
| 153 | + /// must be consistent indefinitely, and the value you read out of the array is only guaranteed to be equal to the one passed in, not necessarily the same |
| 154 | + /// instance or bits). Note: this constructor does not de-duplicate against existing instances when created (however, it can still later) - it is a quick |
| 155 | + /// constructor that just copies the provided value directly, other than ensuring non-<see langword="null" /> - use methods on |
| 156 | + /// <see cref="ComparerEquatableArray" /> to get de-duplication.</para> |
| 157 | + /// <para> |
| 158 | + /// Note: the values for the comparer are compared by reference equality, but with <see langword="null" /> considered equivalent to |
| 159 | + /// <see cref="EqualityComparer{T}.Default" />.</para> |
| 160 | + /// </remarks> |
| 161 | + public ComparerEquatableArray(ImmutableArray<T> array, IEqualityComparer<T>? comparer = null) |
| 162 | + { |
| 163 | + _impl = new(array, ref _staticCreateIndex); |
| 164 | + _comparer = comparer == EqualityComparer<T>.Default ? null : comparer; |
| 165 | + } |
| 166 | + |
| 167 | + /// <summary> |
| 168 | + /// Gets the shared empty instance of the <see cref="ComparerEquatableArray{T}"/> class with the default comparer. |
| 169 | + /// </summary> |
| 170 | + public static ComparerEquatableArray<T> Empty { get; } = new(ImmutableArray<T>.Empty); |
| 171 | + |
| 172 | + /// <inheritdoc cref="EquatableArray{T}.UnderlyingArray" /> |
| 173 | + public ImmutableArray<T> UnderlyingArray => _impl.UnderlyingArray; |
| 174 | + |
| 175 | + /// <summary> |
| 176 | + /// Gets the comparer used for value-based equality. |
| 177 | + /// </summary> |
| 178 | + public IEqualityComparer<T> Comparer => _comparer ?? EqualityComparer<T>.Default; |
| 179 | + |
| 180 | + /// <inheritdoc cref="EquatableArray{T}.UnderlyingArray" /> |
| 181 | + public override int GetHashCode() => _impl.GetHashCode(_comparer); |
| 182 | + |
| 183 | + /// <inheritdoc cref="Equals(object?)" /> |
| 184 | + public bool Equals([NotNullWhen(true)] ComparerEquatableArray<T>? other) |
| 185 | + { |
| 186 | + // Check simple cases: |
| 187 | + if (other is null) |
| 188 | + return false; |
| 189 | + if (ReferenceEquals(this, other)) |
| 190 | + return true; |
| 191 | + if (_comparer != other._comparer) |
| 192 | + return false; |
| 193 | + |
| 194 | + // Call into impl: |
| 195 | + return _impl.Equals(ref other._impl, _comparer); |
| 196 | + } |
| 197 | + |
| 198 | + /// <summary>Determines whether the specified object is equal to the current object.</summary> |
| 199 | + /// <param name="obj">The object to compare with the current object.</param> |
| 200 | + /// <returns><see langword="true" /> if the specified object is equal to the current object; otherwise, <see langword="false" />.</returns> |
| 201 | + /// <remarks>Returns <see langword="false" /> if the two instances of <see cref="ComparerEquatableArray{T}"/> have different comparers.</remarks> |
| 202 | + public override bool Equals(object? obj) => Equals(obj as ComparerEquatableArray<T>); |
| 203 | + |
| 204 | + /// <summary> |
| 205 | + /// Value-based equality operator. |
| 206 | + /// </summary> |
| 207 | + /// <remarks>Returns <see langword="false" /> if the two instances of <see cref="ComparerEquatableArray{T}"/> have different comparers.</remarks> |
| 208 | + public static bool operator ==(ComparerEquatableArray<T>? left, ComparerEquatableArray<T>? right) => Equals(left, right); |
| 209 | + |
| 210 | + /// <summary> |
| 211 | + /// Value-based inequality operator. |
| 212 | + /// </summary> |
| 213 | + /// <remarks>Returns <see langword="false" /> if the two instances of <see cref="ComparerEquatableArray{T}"/> have different comparers.</remarks> |
| 214 | + public static bool operator !=(ComparerEquatableArray<T>? left, ComparerEquatableArray<T>? right) => !(left == right); |
| 215 | + |
| 216 | + /// <inheritdoc cref="EquatableArray{T}.Length" /> |
| 217 | + public int Length => _impl.Length; |
| 218 | + |
| 219 | + /// <inheritdoc cref="EquatableArray{T}.IsEmpty" /> |
| 220 | + public bool IsEmpty => _impl.IsEmpty; |
| 221 | + |
| 222 | + /// <inheritdoc cref="EquatableArray{T}.this[int]" /> |
| 223 | + public ref readonly T this[int index] => ref _impl[index]; |
| 224 | + |
| 225 | + /// <inheritdoc /> |
| 226 | + int ICollection<T>.Count => Length; |
| 227 | + |
| 228 | + /// <inheritdoc /> |
| 229 | + int IReadOnlyCollection<T>.Count => Length; |
| 230 | + |
| 231 | + /// <inheritdoc /> |
| 232 | + bool ICollection<T>.IsReadOnly => true; |
| 233 | + |
| 234 | + /// <inheritdoc /> |
| 235 | + T IList<T>.this[int index] |
| 236 | + { |
| 237 | + get => this[index]; |
| 238 | + set => EquatableArrayImpl.ThrowReadOnlyException(); |
| 239 | + } |
| 240 | + |
| 241 | + /// <inheritdoc /> |
| 242 | + T IReadOnlyList<T>.this[int index] => this[index]; |
| 243 | + |
| 244 | + /// <inheritdoc /> |
| 245 | + IEnumerator<T> IEnumerable<T>.GetEnumerator() => _impl.IEnumerableTGetEnumerator(); |
| 246 | + |
| 247 | + /// <inheritdoc /> |
| 248 | + IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable<T>)this).GetEnumerator(); |
| 249 | + |
| 250 | + /// <inheritdoc /> |
| 251 | + void IList<T>.Insert(int index, T item) => EquatableArrayImpl.ThrowReadOnlyException(); |
| 252 | + |
| 253 | + /// <inheritdoc /> |
| 254 | + void IList<T>.RemoveAt(int index) => EquatableArrayImpl.ThrowReadOnlyException(); |
| 255 | + |
| 256 | + /// <inheritdoc /> |
| 257 | + void ICollection<T>.Add(T item) => EquatableArrayImpl.ThrowReadOnlyException(); |
| 258 | + |
| 259 | + /// <inheritdoc /> |
| 260 | + void ICollection<T>.Clear() => EquatableArrayImpl.ThrowReadOnlyException(); |
| 261 | + |
| 262 | + /// <inheritdoc /> |
| 263 | + void ICollection<T>.CopyTo(T[] array, int arrayIndex) => CopyTo(array, arrayIndex); |
| 264 | + |
| 265 | + /// <inheritdoc /> |
| 266 | + bool ICollection<T>.Remove(T item) => EquatableArrayImpl.ThrowReadOnlyException<bool>(); |
| 267 | + |
| 268 | + /// <inheritdoc /> |
| 269 | + public override string ToString() => _impl.ToString(); |
| 270 | + |
| 271 | + /// <inheritdoc cref="EquatableArray{T}.ToString(IFormatProvider?)" /> |
| 272 | + public string ToString(IFormatProvider? formatProvider) => _impl.ToString(formatProvider); |
| 273 | + |
| 274 | + /// <inheritdoc cref="EquatableArray{T}.ToString(string?)" /> |
| 275 | + public string ToString(string? elementFormat) => _impl.ToString(elementFormat); |
| 276 | + |
| 277 | + /// <inheritdoc cref="EquatableArray{T}.ToString(string?, IFormatProvider?)" /> |
| 278 | + public string ToString(string? elementFormat, IFormatProvider? formatProvider) => _impl.ToString(elementFormat, formatProvider); |
| 279 | + |
| 280 | + /// <inheritdoc cref="IFormattable.ToString(string?, IFormatProvider?)" /> |
| 281 | + string IFormattable.ToString(string? format, IFormatProvider? formatProvider) => ToString(format, formatProvider); |
| 282 | + |
| 283 | + /// <inheritdoc cref="EquatableArray{T}.Enumerator" /> |
| 284 | + public struct Enumerator |
| 285 | + { |
| 286 | + private EquatableArrayImpl<T>.Enumerator _impl; |
| 287 | + |
| 288 | + internal Enumerator(ComparerEquatableArray<T> array) |
| 289 | + { |
| 290 | + _impl = array._impl.GetEnumerator(); |
| 291 | + } |
| 292 | + |
| 293 | + /// <inheritdoc cref="EquatableArray{T}.Enumerator.Current" /> |
| 294 | + public readonly T Current => _impl.Current; |
| 295 | + |
| 296 | + /// <inheritdoc cref="EquatableArray{T}.Enumerator.MoveNext()" /> |
| 297 | + public bool MoveNext() => _impl.MoveNext(); |
| 298 | + } |
| 299 | + |
| 300 | + /// <inheritdoc cref="EquatableArray{T}.AsMemory()" /> |
| 301 | + public ReadOnlyMemory<T> AsMemory() => _impl.AsMemory(); |
| 302 | + |
| 303 | + /// <inheritdoc cref="EquatableArray{T}.AsSpan()" /> |
| 304 | + public ReadOnlySpan<T> AsSpan() => _impl.AsSpan(); |
| 305 | + |
| 306 | + /// <inheritdoc cref="EquatableArray{T}.AsSpan(int, int)" /> |
| 307 | + public ReadOnlySpan<T> AsSpan(int start, int length) => _impl.AsSpan(start, length); |
| 308 | + |
| 309 | + /// <inheritdoc cref="EquatableArray{T}.AsSpan(Range)" /> |
| 310 | + public ReadOnlySpan<T> AsSpan(Range range) => _impl.AsSpan(range); |
| 311 | + |
| 312 | + /// <inheritdoc cref="EquatableArray{T}.Contains(T)" /> |
| 313 | + public bool Contains(T item) => _impl.Contains(item, _comparer); |
| 314 | + |
| 315 | + /// <inheritdoc cref="EquatableArray{T}.Contains(T, IEqualityComparer{T}?)" /> |
| 316 | + public bool Contains(T item, IEqualityComparer<T>? equalityComparer) => _impl.Contains(item, equalityComparer ?? _comparer); |
| 317 | + |
| 318 | + /// <inheritdoc cref="EquatableArray{T}.CopyTo(Span{T})" /> |
| 319 | + public void CopyTo(Span<T> destination) => _impl.CopyTo(destination); |
| 320 | + |
| 321 | + /// <inheritdoc cref="EquatableArray{T}.CopyTo(T[])" /> |
| 322 | + public void CopyTo(T[] destination) => _impl.CopyTo(destination); |
| 323 | + |
| 324 | + /// <inheritdoc cref="EquatableArray{T}.CopyTo(T[], int)" /> |
| 325 | + public void CopyTo(T[] destination, int destinationIndex) => _impl.CopyTo(destination, destinationIndex); |
| 326 | + |
| 327 | + /// <inheritdoc cref="EquatableArray{T}.CopyTo(int, T[], int, int)" /> |
| 328 | + public void CopyTo(int sourceIndex, T[] destination, int destinationIndex, int length) => _impl.CopyTo(sourceIndex, destination, destinationIndex, length); |
| 329 | + |
| 330 | + /// <inheritdoc cref="EquatableArray{T}.GetEnumerator()" /> |
| 331 | + public Enumerator GetEnumerator() => new(this); |
| 332 | + |
| 333 | + /// <inheritdoc cref="EquatableArray{T}.IndexOf(T)" /> |
| 334 | + public int IndexOf(T item) => _impl.IndexOf(item, _comparer); |
| 335 | + |
| 336 | + /// <inheritdoc cref="EquatableArray{T}.IndexOf(T, IEqualityComparer{T}?)" /> |
| 337 | + public int IndexOf(T item, IEqualityComparer<T>? equalityComparer) => _impl.IndexOf(item, equalityComparer ?? _comparer); |
| 338 | + |
| 339 | + /// <inheritdoc cref="EquatableArray{T}.IndexOf(T, int)" /> |
| 340 | + public int IndexOf(T item, int startIndex) => _impl.IndexOf(item, startIndex, _comparer); |
| 341 | + |
| 342 | + /// <inheritdoc cref="EquatableArray{T}.IndexOf(T, int, IEqualityComparer{T}?)" /> |
| 343 | + public int IndexOf(T item, int startIndex, IEqualityComparer<T>? equalityComparer) => _impl.IndexOf(item, startIndex, equalityComparer ?? _comparer); |
| 344 | + |
| 345 | + /// <inheritdoc cref="EquatableArray{T}.IndexOf(T, int, int)" /> |
| 346 | + public int IndexOf(T item, int startIndex, int count) => _impl.IndexOf(item, startIndex, count, _comparer); |
| 347 | + |
| 348 | + /// <inheritdoc cref="EquatableArray{T}.IndexOf(T, int, int, IEqualityComparer{T}?)" /> |
| 349 | + public int IndexOf(T item, int startIndex, int count, IEqualityComparer<T>? equalityComparer) => _impl.IndexOf(item, startIndex, count, equalityComparer ?? _comparer); |
| 350 | + |
| 351 | + /// <inheritdoc cref="EquatableArray{T}.LastIndexOf(T)" /> |
| 352 | + public int LastIndexOf(T item) => _impl.LastIndexOf(item, _comparer); |
| 353 | + |
| 354 | + /// <inheritdoc cref="EquatableArray{T}.LastIndexOf(T, IEqualityComparer{T}?)" /> |
| 355 | + public int LastIndexOf(T item, IEqualityComparer<T>? equalityComparer) => _impl.LastIndexOf(item, equalityComparer ?? _comparer); |
| 356 | + |
| 357 | + /// <inheritdoc cref="EquatableArray{T}.LastIndexOf(T, int)" /> |
| 358 | + public int LastIndexOf(T item, int startIndex) => _impl.LastIndexOf(item, startIndex, _comparer); |
| 359 | + |
| 360 | + /// <inheritdoc cref="EquatableArray{T}.LastIndexOf(T, int, IEqualityComparer{T}?)" /> |
| 361 | + public int LastIndexOf(T item, int startIndex, IEqualityComparer<T>? equalityComparer) => _impl.LastIndexOf(item, startIndex, equalityComparer ?? _comparer); |
| 362 | + |
| 363 | + /// <inheritdoc cref="EquatableArray{T}.LastIndexOf(T, int, int)" /> |
| 364 | + public int LastIndexOf(T item, int startIndex, int count) => _impl.LastIndexOf(item, startIndex, count, _comparer); |
| 365 | + |
| 366 | + /// <inheritdoc cref="EquatableArray{T}.LastIndexOf(T, int, int, IEqualityComparer{T}?)" /> |
| 367 | + public int LastIndexOf(T item, int startIndex, int count, IEqualityComparer<T>? equalityComparer) => _impl.LastIndexOf(item, startIndex, count, equalityComparer ?? _comparer); |
| 368 | + |
| 369 | + /// <inheritdoc cref="EquatableArray{T}.Slice(int, int)" /> |
| 370 | + public ComparerEquatableArray<T> Slice(int start, int length) => _impl.Slice(start, length, out bool identical) switch |
| 371 | + { |
| 372 | + _ when identical => this, |
| 373 | + var x => ComparerEquatableArray.Create(_comparer, x), |
| 374 | + }; |
| 375 | + |
| 376 | + /// <summary> |
| 377 | + /// Returns an <see cref="ComparerEquatableArray{T}"/> instance with the specified comparer over the current values. |
| 378 | + /// </summary> |
| 379 | + public ComparerEquatableArray<T> WithComparer(IEqualityComparer<T>? comparer) |
| 380 | + { |
| 381 | + if (comparer == EqualityComparer<T>.Default) |
| 382 | + comparer = null; |
| 383 | + |
| 384 | + if (comparer == _comparer) |
| 385 | + return this; |
| 386 | + |
| 387 | + return ComparerEquatableArray.Create(comparer, UnderlyingArray); |
| 388 | + } |
| 389 | +} |
0 commit comments