Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dedicated empty array enumerator for footprint reduction #82899

Merged
merged 2 commits into from
Mar 2, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public void Reset()
}
}

internal class SZGenericArrayEnumeratorBase
internal abstract class SZGenericArrayEnumeratorBase
{
protected readonly Array _array;
protected int _index;
Expand Down Expand Up @@ -104,10 +104,17 @@ public void Dispose()

internal sealed class SZGenericArrayEnumerator<T> : SZGenericArrayEnumeratorBase, IEnumerator<T>
{
// Array.Empty is intentionally omitted here, since we don't want to pay for generic instantiations that
// wouldn't have otherwise been used.
/// <summary>Provides an empty enumerator singleton.</summary>
/// <remarks>
/// If the consumer is using SZGenericArrayEnumerator elsewhere or is otherwise likely
/// to be using T[] elsewhere, this singleton should be used. Otherwise, GenericEmptyArrayEnumerator's
/// singleton should be used instead, as it doesn't reference T[] in order to reduce footprint.
/// </remarks>
#pragma warning disable CA1825
internal static readonly SZGenericArrayEnumerator<T> Empty = new SZGenericArrayEnumerator<T>(new T[0]);
internal static readonly SZGenericArrayEnumerator<T> Empty =
// Array.Empty is intentionally omitted here, since we don't want to pay for generic instantiations
// that wouldn't have otherwise been used.
new SZGenericArrayEnumerator<T>(new T[0]);
#pragma warning restore CA1825

public SZGenericArrayEnumerator(T[] array)
Expand All @@ -133,4 +140,39 @@ public T Current

object? IEnumerator.Current => Current;
}

internal abstract class GenericEmptyArrayEnumeratorBase
{
#pragma warning disable CA1822 // https://github.com/dotnet/roslyn-analyzers/issues/5911
public bool MoveNext() => false;

public void Reset() { }

public void Dispose() { }
#pragma warning restore CA1822
}

/// <summary>Provides an empty enumerator singleton.</summary>
/// <remarks>
/// If the consumer is using SZGenericArrayEnumerator elsewhere or is otherwise likely
/// to be using T[] elsewhere, SZGenericArrayEnumerator's singleton should be used. Otherwise,
/// this singleton should be used, as it doesn't reference T[] in order to reduce footprint.
/// </remarks>
internal sealed class GenericEmptyArrayEnumerator<T> : GenericEmptyArrayEnumeratorBase, IEnumerator<T>
stephentoub marked this conversation as resolved.
Show resolved Hide resolved
{
public static readonly GenericEmptyArrayEnumerator<T> Instance = new();

private GenericEmptyArrayEnumerator() { }

public T Current
{
get
{
ThrowHelper.ThrowInvalidOperationException_EnumCurrent(-1);
return default;
}
}

object? IEnumerator.Current => Current;
stephentoub marked this conversation as resolved.
Show resolved Hide resolved
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ private void CopyTo(KeyValuePair<TKey, TValue>[] array, int index)
public Enumerator GetEnumerator() => new Enumerator(this, Enumerator.KeyValuePair);

IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator() =>
Count == 0 ? SZGenericArrayEnumerator<KeyValuePair<TKey, TValue>>.Empty :
Count == 0 ? GenericEmptyArrayEnumerator<KeyValuePair<TKey, TValue>>.Instance :
GetEnumerator();

public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.
{
Container c = _container;
return c is null || c.FirstFreeEntry == 0 ?
SZGenericArrayEnumerator<KeyValuePair<TKey, TValue>>.Empty :
GenericEmptyArrayEnumerator<KeyValuePair<TKey, TValue>>.Instance :
new Enumerator(this);
}
}
Expand Down