Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all 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
5 changes: 4 additions & 1 deletion src/System.Linq/src/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,7 @@
<data name="NoMatch" xml:space="preserve">
<value>Sequence contains no matching element</value>
</data>
</root>
<data name="ArrayPlusOffTooSmall" xml:space="preserve">
<value>Destination array is not long enough to copy all the items in the collection. Check array index and length.</value>
</data>
</root>
27 changes: 26 additions & 1 deletion src/System.Linq/src/System/Linq/Partition.SpeedOpt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace System.Linq
/// Returning an instance of this type is useful to quickly handle scenarios where it is known
/// that an operation will result in zero elements.
/// </remarks>
internal sealed class EmptyPartition<TElement> : IPartition<TElement>, IEnumerator<TElement>
internal sealed class EmptyPartition<TElement> : IPartition<TElement>, IEnumerator<TElement>, IList<TElement>, IReadOnlyList<TElement>
{
/// <summary>
/// A cached, immutable instance of an empty enumerable.
Expand All @@ -28,6 +28,31 @@ private EmptyPartition()
{
}

public int Count => 0;

public bool IsReadOnly => true;

public TElement this[int index]
{
get => ThrowHelper.ThrowArgumentOutOfRangeException<TElement>(ExceptionArgument.index);
set => ThrowHelper.ThrowNotSupportedException();
}

public void CopyTo(TElement[] array, int arrayIndex)
{
// Do nothing.
}

public bool Contains(TElement item) => false;

public int IndexOf(TElement item) => -1;

void ICollection<TElement>.Add(TElement item) => ThrowHelper.ThrowNotSupportedException();
bool ICollection<TElement>.Remove(TElement item) => ThrowHelper.ThrowNotSupportedException<bool>();
void ICollection<TElement>.Clear() => ThrowHelper.ThrowNotSupportedException();
void IList<TElement>.Insert(int index, TElement item) => ThrowHelper.ThrowNotSupportedException();
void IList<TElement>.RemoveAt(int index) => ThrowHelper.ThrowNotSupportedException();

public IEnumerator<TElement> GetEnumerator() => this;

IEnumerator IEnumerable.GetEnumerator() => this;
Expand Down
11 changes: 1 addition & 10 deletions src/System.Linq/src/System/Linq/Range.SpeedOpt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,7 @@ public int[] ToArray()
return array;
}

public List<int> ToList()
{
List<int> list = new List<int>(_end - _start);
for (int cur = _start; cur != _end; cur++)
{
list.Add(cur);
}

return list;
}
public List<int> ToList() => new List<int>(this);

public int GetCount(bool onlyIfCheap) => unchecked(_end - _start);

Expand Down
57 changes: 56 additions & 1 deletion src/System.Linq/src/System/Linq/Range.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public static IEnumerable<int> Range(int start, int count)
/// <summary>
/// An iterator that yields a range of consecutive integers.
/// </summary>
private sealed partial class RangeIterator : Iterator<int>
private sealed partial class RangeIterator : Iterator<int>, IList<int>, IReadOnlyList<int>
{
private readonly int _start;
private readonly int _end;
Expand All @@ -40,6 +40,61 @@ public RangeIterator(int start, int count)
_end = unchecked(start + count);
}

public int Count => unchecked(_end - _start);

public bool IsReadOnly => true;

public int this[int index]
{
get
{
if ((uint)index >= (uint)Count)
{
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index);
}
return unchecked(index + _start);
}
set => ThrowHelper.ThrowNotSupportedException();
}

public void CopyTo(int[] array, int arrayIndex)
{
if (array is null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);

if ((uint)arrayIndex >= (uint)array.Length)
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.arrayIndex);

unchecked
{
if (array.Length - arrayIndex < Count)
ThrowHelper.ThrowArgumentArrayPlusOffTooSmall();

int end = arrayIndex + Count;
for (int index = arrayIndex, value = _start; index < end; index++, value++)
{
array[index] = value;
}
}
}

public bool Contains(int item) => item >= _start && item < _end;

public int IndexOf(int item)
{
if (item < _start || item >= _end)
{
return -1;
}
return unchecked(item - _start);
}

void ICollection<int>.Add(int item) => ThrowHelper.ThrowNotSupportedException();
bool ICollection<int>.Remove(int item) => ThrowHelper.ThrowNotSupportedException<bool>();
void ICollection<int>.Clear() => ThrowHelper.ThrowNotSupportedException();
void IList<int>.Insert(int index, int item) => ThrowHelper.ThrowNotSupportedException();
void IList<int>.RemoveAt(int index) => ThrowHelper.ThrowNotSupportedException();

public override Iterator<int> Clone() => new RangeIterator(_start, _end - _start);

public override bool MoveNext()
Expand Down
11 changes: 1 addition & 10 deletions src/System.Linq/src/System/Linq/Repeat.SpeedOpt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,7 @@ public TResult[] ToArray()
return array;
}

public List<TResult> ToList()
{
List<TResult> list = new List<TResult>(_count);
for (int i = 0; i != _count; ++i)
{
list.Add(_current);
}

return list;
}
public List<TResult> ToList() => new List<TResult>(this);

public int GetCount(bool onlyIfCheap) => _count;

Expand Down
51 changes: 50 additions & 1 deletion src/System.Linq/src/System/Linq/Repeat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public static IEnumerable<TResult> Repeat<TResult>(TResult element, int count)
/// An iterator that yields the same item multiple times.
/// </summary>
/// <typeparam name="TResult">The type of the item.</typeparam>
private sealed partial class RepeatIterator<TResult> : Iterator<TResult>
private sealed partial class RepeatIterator<TResult> : Iterator<TResult>, IList<TResult>, IReadOnlyList<TResult>
{
private readonly int _count;

Expand All @@ -39,6 +39,55 @@ public RepeatIterator(TResult element, int count)
_count = count;
}

public int Count => _count;

public bool IsReadOnly => true;

public TResult this[int index]
{
get
{
if ((uint)index >= (uint)_count)
{
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index);
}
return _current;
}

set => ThrowHelper.ThrowNotSupportedException();
}

public void CopyTo(TResult[] array, int arrayIndex)
{
if (array is null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);

if ((uint)arrayIndex >= (uint)array.Length)
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.arrayIndex);

unchecked
{
if (array.Length - arrayIndex < Count)
ThrowHelper.ThrowArgumentArrayPlusOffTooSmall();

int end = arrayIndex + Count;
for (int index = arrayIndex; index < end; index++)
{
array[index] = _current;
}
}
}

public bool Contains(TResult item) => EqualityComparer<TResult>.Default.Equals(_current, item);

public int IndexOf(TResult item) => EqualityComparer<TResult>.Default.Equals(_current, item) ? 0 : -1;

void ICollection<TResult>.Add(TResult item) => ThrowHelper.ThrowNotSupportedException();
bool ICollection<TResult>.Remove(TResult item) => ThrowHelper.ThrowNotSupportedException<bool>();
void ICollection<TResult>.Clear() => ThrowHelper.ThrowNotSupportedException();
void IList<TResult>.Insert(int index, TResult item) => ThrowHelper.ThrowNotSupportedException();
void IList<TResult>.RemoveAt(int index) => ThrowHelper.ThrowNotSupportedException();

public override Iterator<TResult> Clone()
{
return new RepeatIterator<TResult>(_current, _count);
Expand Down
10 changes: 10 additions & 0 deletions src/System.Linq/src/System/Linq/ThrowHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ internal static class ThrowHelper

internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument) => throw new ArgumentOutOfRangeException(GetArgumentString(argument));

internal static T ThrowArgumentOutOfRangeException<T>(ExceptionArgument argument) => throw new ArgumentOutOfRangeException(GetArgumentString(argument));

internal static void ThrowArgumentArrayPlusOffTooSmall() => throw new ArgumentException(SR.ArrayPlusOffTooSmall);

internal static void ThrowMoreThanOneElementException() => throw new InvalidOperationException(SR.MoreThanOneElement);

internal static void ThrowMoreThanOneMatchException() => throw new InvalidOperationException(SR.MoreThanOneMatch);
Expand All @@ -23,6 +27,8 @@ internal static class ThrowHelper

internal static void ThrowNotSupportedException() => throw new NotSupportedException();

internal static T ThrowNotSupportedException<T>() => throw new NotSupportedException();

private static string GetArgumentString(ExceptionArgument argument)
{
switch (argument)
Expand All @@ -44,6 +50,8 @@ private static string GetArgumentString(ExceptionArgument argument)
case ExceptionArgument.second: return nameof(ExceptionArgument.second);
case ExceptionArgument.selector: return nameof(ExceptionArgument.selector);
case ExceptionArgument.source: return nameof(ExceptionArgument.source);
case ExceptionArgument.array: return nameof(ExceptionArgument.array);
case ExceptionArgument.arrayIndex: return nameof(ExceptionArgument.arrayIndex);
default:
Debug.Fail("The ExceptionArgument value is not defined.");
return string.Empty;
Expand All @@ -70,5 +78,7 @@ internal enum ExceptionArgument
second,
selector,
source,
array,
arrayIndex,
}
}
73 changes: 73 additions & 0 deletions src/System.Linq/tests/EmptyPartitionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,5 +106,78 @@ public void ResetIsNop()
en.Reset();
en.Reset();
}

[Fact]
public void ICollection_IsReadOnly()
{
var emptyPartition = GetEmptyPartition<int>() as ICollection<int>;

Assert.Equal(true, emptyPartition.IsReadOnly);
Assert.Throws<NotSupportedException>(() => emptyPartition.Add(0));
Assert.Throws<NotSupportedException>(() => emptyPartition.Remove(0));
Assert.Throws<NotSupportedException>(() => emptyPartition.Clear());
}

[Fact]
public void ICollection_Count()
{
var emptyPartition = GetEmptyPartition<int>() as ICollection<int>;

Assert.Equal(0, emptyPartition.Count);
}

[Fact]
public void ICollection_CopyTo_ProduceCorrectSequence()
{
var emptyPartition = GetEmptyPartition<int>() as ICollection<int>;

var arrayIndex = 5;
var array = Enumerable.Range(0, 10).ToArray();
emptyPartition.CopyTo(array, arrayIndex);

for (var index = 0; index < 10; index++)
{
Assert.Equal(index, array[index]);
}
}

[Fact]
public void ICollection_Contains()
{
var emptyPartition = GetEmptyPartition<int>() as ICollection<int>;

Assert.Equal(false, emptyPartition.Contains(int.MinValue));
Assert.Equal(false, emptyPartition.Contains(0));
Assert.Equal(false, emptyPartition.Contains(int.MaxValue));
}

[Fact]
public void IList_IsReadOnly()
{
var emptyPartition = GetEmptyPartition<int>() as IList<int>;

Assert.Throws<NotSupportedException>(() => emptyPartition.Insert(0, 0));
Assert.Throws<NotSupportedException>(() => emptyPartition.RemoveAt(0));
}

[Fact]
public void IList_Indexer_ThrowExceptionOnOutOfRangeIndex()
{
var emptyPartition = GetEmptyPartition<int>() as IList<int>;

AssertExtensions.Throws<ArgumentOutOfRangeException>("index", () => emptyPartition[int.MinValue]);
AssertExtensions.Throws<ArgumentOutOfRangeException>("index", () => emptyPartition[0]);
AssertExtensions.Throws<ArgumentOutOfRangeException>("index", () => emptyPartition[int.MaxValue]);
}

[Fact]
public void IList_IndexOf()
{
var emptyPartition = GetEmptyPartition<int>() as IList<int>;

Assert.Equal(-1, emptyPartition.IndexOf(int.MinValue));
Assert.Equal(-1, emptyPartition.IndexOf(0));
Assert.Equal(-1, emptyPartition.IndexOf(int.MaxValue));
}
}
}
Loading