Skip to content

Commit

Permalink
Unify Array enumerators between CoreCLR and NativeAOT
Browse files Browse the repository at this point in the history
Contributes to dotnet#82732
  • Loading branch information
jkotas committed Mar 1, 2023
1 parent 3d160bc commit d93d2e8
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 98 deletions.
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
@@ -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 Down Expand Up @@ -64,18 +66,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 +82,44 @@ internal SZGenericArrayEnumerator(T[] array)
public bool MoveNext()
{
int index = _index + 1;
if ((uint)index >= (uint)_array.Length)
int length = (int)_array.NativeLength;
if ((uint)index >= (uint)length)
{
_index = _array.Length;
_index = length;
return false;
}
_index = index;
return true;
}

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

#pragma warning disable CA1822 // Mark members as static
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 +131,5 @@ public T Current
}

object? IEnumerator.Current => Current;

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

public void Dispose()
{
}
}
}

0 comments on commit d93d2e8

Please sign in to comment.