diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a82133..dfdf9a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ - X10D: Added `IEnumerable.WhereNot(Func)` - X10D: Added `IList.RemoveRange(Range)` - X10D: Added `IList.Swap(IList)` (#62) +- X10D: Added `IReadOnlyList.IndexOf(T[, 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 dc6574a..2f17998 100644 --- a/X10D.Tests/src/Collections/ListTests.cs +++ b/X10D.Tests/src/Collections/ListTests.cs @@ -79,6 +79,67 @@ public class ListTests Assert.ThrowsException(() => list!.Fill(0, 0, 0)); } + [TestMethod] + public void IndexOf_ShouldReturnCorrectValue_FromStartOfList() + { + int[] array = {0, 1, 2, 3, 4}; + Assert.AreEqual(2, array.IndexOf(2)); + Assert.AreEqual(2, array.IndexOf(2, 0)); + Assert.AreEqual(2, array.IndexOf(2, 0, 5)); + } + + [TestMethod] + public void IndexOf_ShouldReturnCorrectValue_GivenSubRange() + { + int[] array = {0, 1, 2, 3, 4, 0}; + Assert.AreEqual(0, array.IndexOf(0)); + Assert.AreEqual(0, array.IndexOf(0, 0)); + Assert.AreEqual(0, array.IndexOf(0, 0, 5)); + + Assert.AreEqual(5, array.IndexOf(0, 1)); + Assert.AreEqual(5, array.IndexOf(0, 1, 5)); + } + + [TestMethod] + public void IndexOf_ShouldReturnNegative1_ForEmptyList() + { + int[] array = Array.Empty(); + Assert.AreEqual(-1, array.IndexOf(0)); + Assert.AreEqual(-1, array.IndexOf(0, 0)); + Assert.AreEqual(-1, array.IndexOf(0, 0, 0)); + } + + [TestMethod] + public void IndexOf_ShouldThrowArgumentNullException_GivenNullList() + { + int[]? array = null; + Assert.ThrowsException(() => array!.IndexOf(0)); + Assert.ThrowsException(() => array!.IndexOf(0, 0)); + Assert.ThrowsException(() => array!.IndexOf(0, 0, 0)); + } + + [TestMethod] + public void IndexOf_ShouldThrowArgumentOutOfRangeException_GivenNegativeCount() + { + int[] array = Array.Empty(); + Assert.ThrowsException(() => array.IndexOf(0, 0, -1)); + } + + [TestMethod] + public void IndexOf_ShouldThrowArgumentOutOfRangeException_GivenNegativeStartIndex() + { + int[] array = Array.Empty(); + Assert.ThrowsException(() => array.IndexOf(0, -1)); + Assert.ThrowsException(() => array.IndexOf(0, -1, 0)); + } + + [TestMethod] + public void IndexOf_ShouldThrowArgumentOutOfRangeException_GivenInvalidStartIndexCountPair() + { + int[] array = {0, 1, 2}; + Assert.ThrowsException(() => array.IndexOf(0, 2, 4)); + } + [TestMethod] public void Random_ShouldReturnContainedObject_GivenNotNull() { diff --git a/X10D/src/Collections/ListExtensions.cs b/X10D/src/Collections/ListExtensions.cs index 3d35aed..086b70e 100644 --- a/X10D/src/Collections/ListExtensions.cs +++ b/X10D/src/Collections/ListExtensions.cs @@ -1,3 +1,4 @@ +using System.Diagnostics; using System.Diagnostics.Contracts; using X10D.Core; @@ -88,6 +89,131 @@ public static class ListExtensions } } + /// + /// Searches for the specified object and returns the zero-based index of the first occurrence within the entire + /// . + /// + /// The list to search + /// + /// The object to locate in the . The value can be for reference + /// types. + /// + /// The type of elements in . + /// + /// The zero-based index of the first occurrence of item within the entire , if found; otherwise, + /// -1. + /// + /// is . + public static int IndexOf(this IReadOnlyList source, T? item) + { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(source); +#else + if (source is null) + { + throw new ArgumentNullException(nameof(source)); + } +#endif + + return source.IndexOf(item, 0, source.Count); + } + + /// + /// Searches for the specified object and returns the zero-based index of the first occurrence within the range of + /// elements in the that extends from the specified index to the last element. + /// + /// The list to search + /// + /// The object to locate in the . The value can be for reference + /// types. + /// + /// The zero-based starting index of the search. 0 (zero) is valid in an empty list. + /// The type of elements in . + /// + /// The zero-based index of the first occurrence of item within the range of elements in the + /// that starts at index and contains count number of elements, if found; otherwise, -1. + /// + /// is . + /// + /// is outside the range of valid indexes for the . + /// + public static int IndexOf(this IReadOnlyList source, T? item, int startIndex) + { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(source); +#else + if (source is null) + { + throw new ArgumentNullException(nameof(source)); + } +#endif + + return source.IndexOf(item, startIndex, source.Count - startIndex); + } + + /// + /// Searches for the specified object and returns the zero-based index of the first occurrence within the range of + /// elements in the that starts at the specified index and contains the specified number + /// of elements. + /// + /// The list to search + /// + /// The object to locate in the . The value can be for reference + /// types. + /// + /// The zero-based starting index of the search. 0 (zero) is valid in an empty list. + /// The number of elements in the section to search. + /// The type of elements in . + /// + /// The zero-based index of the first occurrence of item within the range of elements in the + /// that starts at index and contains count number of elements, if found; otherwise, -1. + /// + /// is . + /// + /// + /// is outside the range of valid indexes for the . + /// + /// -or- + /// is less than 0. + /// -or- + /// + /// and do not specify a valid section in the + /// . + /// + /// + public static int IndexOf(this IReadOnlyList source, T? item, int startIndex, int count) + { +#if NET6_0_OR_GREATER + ArgumentNullException.ThrowIfNull(source); +#else + if (source is null) + { + throw new ArgumentNullException(nameof(source)); + } +#endif + + if (startIndex < 0 || startIndex > source.Count) + { + throw new ArgumentOutOfRangeException(nameof(startIndex), ExceptionMessages.IndexOutOfRange); + } + + if (count < 0 || count > source.Count - startIndex) + { + throw new ArgumentOutOfRangeException(nameof(count), ExceptionMessages.CountMustBeInRange); + } + + int endIndex = startIndex + count; + for (int index = startIndex; index < endIndex; index++) + { + if (EqualityComparer.Default.Equals(source[index]!, item!)) + { + return index; + } + } + + return -1; + } + /// /// Returns a random element from the current list using a specified instance. /// diff --git a/X10D/src/ExceptionMessages.Designer.cs b/X10D/src/ExceptionMessages.Designer.cs index 7dd2526..8e7801e 100644 --- a/X10D/src/ExceptionMessages.Designer.cs +++ b/X10D/src/ExceptionMessages.Designer.cs @@ -1,7 +1,6 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -78,6 +77,15 @@ namespace X10D { } } + /// + /// Looks up a localized string similar to Count must be positive and count must refer to a location within the string/array/collection.. + /// + internal static string CountMustBeInRange { + get { + return ResourceManager.GetString("CountMustBeInRange", resourceCulture); + } + } + /// /// Looks up a localized string similar to The end index must be less than the list count.. /// @@ -114,6 +122,15 @@ namespace X10D { } } + /// + /// Looks up a localized string similar to Index was out of range. Must be non-negative and less than or equal to the size of the collection.. + /// + internal static string IndexOutOfRange { + get { + return ResourceManager.GetString("IndexOutOfRange", resourceCulture); + } + } + /// /// Looks up a localized string similar to Length must be greater than or equal to 0.. /// diff --git a/X10D/src/ExceptionMessages.resx b/X10D/src/ExceptionMessages.resx index c2bbd2e..b2a13ce 100644 --- a/X10D/src/ExceptionMessages.resx +++ b/X10D/src/ExceptionMessages.resx @@ -26,6 +26,9 @@ The buffer is too small to contain the data. + + Count must be positive and count must refer to a location within the string/array/collection. + The end index must be greater than or equal to the start index. @@ -47,6 +50,9 @@ HashAlgorithm's Create method returned null reference. + + Index was out of range. Must be non-negative and less than or equal to the size of the collection. + Length must be greater than or equal to 0.