diff --git a/CHANGELOG.md b/CHANGELOG.md index dfdf9a8..e4354cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ - X10D: Added `IList.RemoveRange(Range)` - X10D: Added `IList.Swap(IList)` (#62) - X10D: Added `IReadOnlyList.IndexOf(T[, int[, int]])` +- X10D: Added `IReadOnlyList.Slice(int[, int]])` - X10D: Added `Point.IsOnLine(LineF)`, `Point.IsOnLine(PointF, PointF)`, and `Point.IsOnLine(Vector2, Vector2)` - X10D: Added `PointF.IsOnLine(LineF)`, `PointF.IsOnLine(PointF, PointF)`, and `PointF.IsOnLine(Vector2, Vector2)` - X10D: Added `Point.ToSize()` diff --git a/X10D.Tests/src/Collections/ListTests.cs b/X10D.Tests/src/Collections/ListTests.cs index 2f17998..06c079a 100644 --- a/X10D.Tests/src/Collections/ListTests.cs +++ b/X10D.Tests/src/Collections/ListTests.cs @@ -216,6 +216,58 @@ public class ListTests Assert.ThrowsException(() => ((List?)null)!.Shuffle()); } + [TestMethod] + public void Slice_ShouldReturnCorrectValue_GivenStartIndex() + { + int[] array = {0, 1, 2, 3, 4, 5}; + CollectionAssert.AreEqual(new[] {2, 3, 4, 5}, array.Slice(2).ToArray()); + } + + [TestMethod] + public void Slice_ShouldReturnCorrectValue_GivenStartIndexAndLength() + { + int[] array = {0, 1, 2, 3, 4, 5}; + CollectionAssert.AreEqual(new[] {2, 3, 4}, array.Slice(2, 3).ToArray()); + } + + [TestMethod] + public void Slice_ShouldReturnEmptyList_ForEmptyList() + { + int[] array = Array.Empty(); + CollectionAssert.AreEqual(Array.Empty(), array.Slice(0).ToArray()); + CollectionAssert.AreEqual(Array.Empty(), array.Slice(0, 0).ToArray()); + } + + [TestMethod] + public void Slice_ShouldThrowArgumentNullException_GivenNullList() + { + int[]? array = null; + Assert.ThrowsException(() => array!.Slice(0)); + Assert.ThrowsException(() => array!.Slice(0, 0)); + } + + [TestMethod] + public void Slice_ShouldThrowArgumentOutOfRangeException_GivenNegativeCount() + { + int[] array = Array.Empty(); + Assert.ThrowsException(() => array.Slice(0, -1)); + } + + [TestMethod] + public void Slice_ShouldThrowArgumentOutOfRangeException_GivenNegativeStartIndex() + { + int[] array = Array.Empty(); + Assert.ThrowsException(() => array.Slice(-1)); + Assert.ThrowsException(() => array.Slice(-1, 0)); + } + + [TestMethod] + public void Slice_ShouldThrowArgumentOutOfRangeException_GivenInvalidStartIndexCountPair() + { + int[] array = {0, 1, 2}; + Assert.ThrowsException(() => array.Slice(2, 4)); + } + [TestMethod] public void Swap_ShouldThrowArgumentNullException_GivenNullSource() { diff --git a/X10D/src/Collections/ListExtensions.cs b/X10D/src/Collections/ListExtensions.cs index 086b70e..6e18207 100644 --- a/X10D/src/Collections/ListExtensions.cs +++ b/X10D/src/Collections/ListExtensions.cs @@ -1,4 +1,3 @@ -using System.Diagnostics; using System.Diagnostics.Contracts; using X10D.Core; @@ -320,6 +319,80 @@ public static class ListExtensions } } + /// + /// Forms a slice out of the current list that begins at a specified index. + /// + /// The list to slice. + /// The index at which to begin the slice. + /// The type of elements in . + /// + /// A list that consists of all elements of the current list from to the end of the list. + /// + /// is . + /// + /// is less than zero or greater than . + /// + public static IReadOnlyList Slice(this IReadOnlyList source, int start) + { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(source); +#else + if (source is null) + { + throw new ArgumentNullException(nameof(source)); + } +#endif + + return source.Slice(start, source.Count - start); + } + + /// + /// Forms a slice out of the current list that begins at a specified index for a specified length. + /// + /// The list to slice. + /// The index at which to begin the slice. + /// The desired length for the slice. + /// The type of elements in . + /// + /// A list that consists of all elements of the current list from to the end of the list. + /// + /// is . + /// + /// or + is less than zero or greater than + /// . + /// + public static IReadOnlyList Slice(this IReadOnlyList source, int start, int length) + { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(source); +#else + if (source is null) + { + throw new ArgumentNullException(nameof(source)); + } +#endif + + if (start < 0 || start > source.Count) + { + throw new ArgumentOutOfRangeException(nameof(start), ExceptionMessages.IndexOutOfRange); + } + + if (length < 0 || length > source.Count - start) + { + throw new ArgumentOutOfRangeException(nameof(length), ExceptionMessages.CountMustBeInRange); + } + + var sliced = new List(); + + int endIndex = start + length; + for (int index = start; index < endIndex; index++) + { + sliced.Add(source[index]); + } + + return sliced.AsReadOnly(); + } + /// /// Swaps all elements in a list with the elements in another list. ///