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

Unify Array enumerators between CoreCLR and NativeAOT #82751

Merged
merged 7 commits into from
Mar 2, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
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 @@ -1157,38 +1157,6 @@ private static int LastIndexOfImpl<T>(T[] array, T value, int startIndex, int co
}
}

internal class ArrayEnumeratorBase : ICloneable
{
protected int _index;
protected int _endIndex;

internal ArrayEnumeratorBase()
{
_index = -1;
}

public bool MoveNext()
{
if (_index < _endIndex)
{
_index++;
return (_index < _endIndex);
}
return false;
}

public object Clone()
{
return MemberwiseClone();
}

#pragma warning disable CA1822 // https://github.com/dotnet/roslyn-analyzers/issues/5911
public void Dispose()
{
}
#pragma warning restore CA1822
}

//
// Note: the declared base type and interface list also determines what Reflection returns from TypeInfo.BaseType and TypeInfo.ImplementedInterfaces for array types.
// This also means the class must be declared "public" so that the framework can reflect on it.
Expand All @@ -1200,17 +1168,15 @@ private Array() { }

public new IEnumerator<T> GetEnumerator()
{
// get length so we don't have to call the Length property again in ArrayEnumerator constructor
// and avoid more checking there too.
int length = this.Length;
return length == 0 ? ArrayEnumerator.Empty : new ArrayEnumerator(Unsafe.As<T[]>(this), length);
T[] @this = Unsafe.As<T[]>(this);
return @this.Length == 0 ? SZGenericArrayEnumerator<T>.Empty : new SZGenericArrayEnumerator<T>(@this);
}

public int Count
{
get
{
return this.Length;
return Unsafe.As<T[]>(this).Length;
}
}

Expand Down Expand Up @@ -1240,13 +1206,14 @@ public void Clear()

public bool Contains(T item)
{
T[] array = Unsafe.As<T[]>(this);
return Array.IndexOf(array, item, 0, array.Length) >= 0;
T[] @this = Unsafe.As<T[]>(this);
return Array.IndexOf(@this, item, 0, @this.Length) >= 0;
}

public void CopyTo(T[] array, int arrayIndex)
{
Array.Copy(Unsafe.As<T[]>(this), 0, array, arrayIndex, this.Length);
T[] @this = Unsafe.As<T[]>(this);
Array.Copy(@this, 0, array, arrayIndex, @this.Length);
}

public bool Remove(T item)
Expand Down Expand Up @@ -1284,8 +1251,8 @@ public T this[int index]

public int IndexOf(T item)
{
T[] array = Unsafe.As<T[]>(this);
return Array.IndexOf(array, item, 0, array.Length);
T[] @this = Unsafe.As<T[]>(this);
return Array.IndexOf(@this, item, 0, @this.Length);
}

public void Insert(int index, T item)
Expand All @@ -1297,43 +1264,6 @@ public void RemoveAt(int index)
{
ThrowHelper.ThrowNotSupportedException();
}

private sealed class ArrayEnumerator : ArrayEnumeratorBase, IEnumerator<T>
{
private readonly T[] _array;

// Passing -1 for endIndex so that MoveNext always returns false without mutating _index
internal static readonly ArrayEnumerator Empty = new ArrayEnumerator(null, -1);

internal ArrayEnumerator(T[] array, int endIndex)
{
_array = array;
_endIndex = endIndex;
}

public T Current
{
get
{
if ((uint)_index >= (uint)_endIndex)
ThrowHelper.ThrowInvalidOperationException();
return _array[_index];
}
}

object IEnumerator.Current
{
get
{
return Current;
}
}

void IEnumerator.Reset()
{
_index = -1;
}
}
}

public class MDArray
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1057,7 +1057,7 @@ public TypeDesc ArrayOfTEnumeratorType
{
get
{
_systemArrayOfTEnumeratorType ??= _systemArrayOfTEnumeratorType = ArrayOfTClass.GetNestedType("ArrayEnumerator");
_systemArrayOfTEnumeratorType ??= _systemArrayOfTEnumeratorType = _context.SystemModule.GetKnownType("System", "SZGenericArrayEnumerator`1");
jkotas marked this conversation as resolved.
Show resolved Hide resolved
return _systemArrayOfTEnumeratorType;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Diagnostics;

namespace System
Expand All @@ -26,9 +28,10 @@ public object Clone()
public bool MoveNext()
{
nint index = _index + 1;
if ((nuint)index >= _array.NativeLength)
nuint length = _array.NativeLength;
if ((nuint)index >= length)
{
_index = (nint)_array.NativeLength;
_index = (nint)length;
return false;
}
_index = index;
Expand Down Expand Up @@ -64,18 +67,12 @@ public void Reset()
}
}

internal sealed class SZGenericArrayEnumerator<T> : IEnumerator<T>
internal class SZGenericArrayEnumeratorBase
{
private readonly T[] _array;
private int _index;
protected readonly Array _array;
protected int _index;

// Array.Empty is intentionally omitted here, since we don't want to pay for generic instantiations that
// wouldn't have otherwise been used.
#pragma warning disable CA1825
internal static readonly SZGenericArrayEnumerator<T> Empty = new SZGenericArrayEnumerator<T>(new T[0]);
#pragma warning restore CA1825

internal SZGenericArrayEnumerator(T[] array)
protected SZGenericArrayEnumeratorBase(Array array)
{
Debug.Assert(array != null);

Expand All @@ -86,21 +83,44 @@ internal SZGenericArrayEnumerator(T[] array)
public bool MoveNext()
{
int index = _index + 1;
if ((uint)index >= (uint)_array.Length)
uint length = (uint)_array.NativeLength;
if ((uint)index >= length)
{
_index = _array.Length;
_index = (int)length;
return false;
}
_index = index;
return true;
}

public void Reset() => _index = -1;

#pragma warning disable CA1822 // Mark members as static
jkotas marked this conversation as resolved.
Show resolved Hide resolved
public void Dispose()
{
}
#pragma warning restore CA1822
}

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.
#pragma warning disable CA1825
internal static readonly SZGenericArrayEnumerator<T> Empty = new SZGenericArrayEnumerator<T>(new T[0]);
#pragma warning restore CA1825

public SZGenericArrayEnumerator(T[] array)
: base(array)
{
}

public T Current
{
get
{
int index = _index;
T[] array = _array;
T[] array = Unsafe.As<T[]>(_array);

if ((uint)index >= (uint)array.Length)
{
Expand All @@ -112,11 +132,5 @@ public T Current
}

object? IEnumerator.Current => Current;

void IEnumerator.Reset() => _index = -1;

public void Dispose()
{
}
}
}