Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,38 @@ int IList.Add(object? item)
// capacity or the new size, whichever is larger.
//
public void AddRange(IEnumerable<T> collection)
=> InsertRange(_size, collection);
{
if (collection == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection);
}

if (collection is ICollection<T> c)
{
int count = c.Count;
if (count > 0)
{
if (_items.Length - _size < count)
{
Grow(_size + count);
}

c.CopyTo(_items, _size);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm guessing this could regress cases where we're appending the list to itself?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regress functionally? We have this test:

public void AddRange_AddSelfAsEnumerable_ThrowsExceptionWhenNotEmpty()

Is there a case that's missing?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Functionality looks good, I meant to say regress performance.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't believe so. I just tried with:

[Benchmark]
public List<int> AddToSelf()
{
    var list = new List<int>();
    list.Add(1);
    list.Add(2);
    list.AddRange(list);
    list.AddRange(list);
    list.AddRange(list);
    list.AddRange(list);
    list.AddRange(list);
    list.AddRange(list);
    return list;
}

and depending on the run there was either no difference or a small difference in favor in of the new version.

Is there a specific aspect of the change you think would regress that? I can try to address it if so. Though I'm not particularly concerned about the performance of that case, anyway.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assuming we cared about optimizing that particular case, hardcoding the operation in the style of InsertRange might be marginally faster compared to using ICollection<T>.CopyTo, at the expense of added branching for every other case. But like you said, it doesn't seem important enough to justify.

_size += count;
_version++;
}
}
else
{
using (IEnumerator<T> en = collection.GetEnumerator())
{
while (en.MoveNext())
{
Add(en.Current);
}
}
}
}

public ReadOnlyCollection<T> AsReadOnly()
=> new ReadOnlyCollection<T>(this);
Expand Down Expand Up @@ -776,6 +807,7 @@ public void InsertRange(int index, IEnumerable<T> collection)
c.CopyTo(_items, index);
}
_size += count;
_version++;
}
}
else
Expand All @@ -788,7 +820,6 @@ public void InsertRange(int index, IEnumerable<T> collection)
}
}
}
_version++;
}

// Returns the index of the last occurrence of a given value in a range of
Expand Down