-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
Bring back old array enumerator code #88371
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1099,7 +1099,10 @@ private Array() { } | |
public new IEnumerator<T> GetEnumerator() | ||
{ | ||
T[] @this = Unsafe.As<T[]>(this); | ||
return @this.Length == 0 ? SZGenericArrayEnumerator<T>.Empty : new SZGenericArrayEnumerator<T>(@this); | ||
// 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 ? SZGenericArrayEnumerator<T>.Empty : new SZGenericArrayEnumerator<T>(@this, length); | ||
} | ||
|
||
public int Count | ||
|
@@ -1196,6 +1199,68 @@ public void RemoveAt(int index) | |
} | ||
} | ||
|
||
internal class SZGenericArrayEnumeratorBase : IDisposable | ||
{ | ||
protected int _index; | ||
protected int _endIndex; | ||
|
||
internal SZGenericArrayEnumeratorBase() | ||
{ | ||
_index = -1; | ||
} | ||
|
||
public bool MoveNext() | ||
{ | ||
if (_index < _endIndex) | ||
{ | ||
_index++; | ||
return (_index < _endIndex); | ||
} | ||
return false; | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
} | ||
} | ||
|
||
internal sealed class SZGenericArrayEnumerator<T> : SZGenericArrayEnumeratorBase, IEnumerator<T> | ||
{ | ||
private readonly T[] _array; | ||
|
||
// Passing -1 for endIndex so that MoveNext always returns false without mutating _index | ||
internal static readonly SZGenericArrayEnumerator<T> Empty = new SZGenericArrayEnumerator<T>(null, -1); | ||
|
||
internal SZGenericArrayEnumerator(T[] array, int endIndex) | ||
{ | ||
_array = array; | ||
_endIndex = endIndex; | ||
} | ||
|
||
public T Current | ||
{ | ||
get | ||
{ | ||
if ((uint)_index >= (uint)_endIndex) | ||
ThrowHelper.ThrowInvalidOperationException(); | ||
return _array[_index]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will bounds check on every access, should this maybe use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this enumerator used often enough on hot paths for it to make a meaningful difference? In general, we have stayed away from manual bounds-check elimination using unsafe code in collections. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I'd say that arrays are fairly often passed to methods taking There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Looks like we have an explicit bounds check on line 1244 now, so eliminating the one built into array accesses would be safe and worthwhile here. |
||
} | ||
} | ||
|
||
object IEnumerator.Current | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this style change now preferred to the other way in line 143? object? IEnumerator.Current => Current; |
||
{ | ||
get | ||
{ | ||
return Current; | ||
} | ||
} | ||
|
||
void IEnumerator.Reset() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this be in the base class - same as in the shared one? |
||
{ | ||
_index = -1; | ||
} | ||
} | ||
|
||
public class MDArray | ||
{ | ||
public const int MinRank = 1; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would it be better to capture the _endIndex in the construction as the whole point of this base class is to inline and read-only the the length?