This is an automated email from the ASF dual-hosted git repository. nightowl888 pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/lucenenet.git
commit 0d9abf64c4eb8d3867254bc7f60c4ef1367b3b90 Author: Shad Storhaug <[email protected]> AuthorDate: Fri Jul 23 13:06:43 2021 +0700 Lucene.Net.Support.CollectionExtensions: Made more efficient RemoveAll() method and added RetainAll() for use in rare circumstances when we want to do set actions on ICollection<T> --- src/Lucene.Net/Support/CollectionExtensions.cs | 84 +++++++++++++++++++++++--- 1 file changed, 76 insertions(+), 8 deletions(-) diff --git a/src/Lucene.Net/Support/CollectionExtensions.cs b/src/Lucene.Net/Support/CollectionExtensions.cs index 6eb7ed0..12c9f70 100644 --- a/src/Lucene.Net/Support/CollectionExtensions.cs +++ b/src/Lucene.Net/Support/CollectionExtensions.cs @@ -1,7 +1,8 @@ -using System; +using J2N.Collections.Generic.Extensions; +using System; using System.Collections.Generic; using System.Diagnostics; -using System.Runtime.CompilerServices; +using JCG = J2N.Collections.Generic; namespace Lucene.Net.Support { @@ -29,23 +30,90 @@ namespace Lucene.Net.Support { /// <summary> /// Removes the given collection of elements from the source <see cref="ICollection{T}"/>. + /// <para/> + /// Usage Note: This is the same operation as <see cref="ISet{T}.ExceptWith(IEnumerable{T})"/> or + /// <see cref="List{T}.RemoveAll(Predicate{T})"/> with a predicate of <c>(value) => collection.Contains(value)</c>. It is + /// recommended to use these alternatives when possible. /// </summary> /// <typeparam name="T">The type of the elements of <paramref name="source"/>.</typeparam> /// <param name="source">An <see cref="ICollection{T}"/> to remove elements from.</param> - /// <param name="removeList">An <see cref="IEnumerable{T}"/> containing the items to remove from <paramref name="source"/>.</param> + /// <param name="collection">An <see cref="ICollection{T}"/> containing the items to remove from <paramref name="source"/>.</param> + /// <returns><c>true</c> if the collection changed as a result of the call; otherwise, <c>false</c>.</returns> [DebuggerStepThrough] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void RemoveAll<T>(this ICollection<T> source, IEnumerable<T> removeList) + public static bool RemoveAll<T>(this ICollection<T> source, ICollection<T> collection) { if (source == null) throw new ArgumentNullException(nameof(source)); + if (collection == null) + throw new ArgumentNullException(nameof(collection)); - if (source.Count == 0) return; + if (source.Count == 0) return false; - foreach (var elt in removeList) + if (source is ISet<T> set) { - source.Remove(elt); + int originalCount = set.Count; + set.ExceptWith(collection); + return originalCount != set.Count; } + else if (source is IList<T> list) + { + int removed = list.RemoveAll((value) => collection.Contains(value)); + return removed > 0; + } + + // Slow path for unknown collection types + bool modified = false; + foreach (var e in collection) + { + modified |= source.Remove(e); + } + return modified; + } + + /// <summary> + /// Retains only the elements in this list that are contained in the specified collection (optional operation). + /// In other words, removes from this list all of its elements that are not contained in the specified collection. + /// <para/> + /// Usage Note: This is the same operation as <see cref="ISet{T}.IntersectWith(IEnumerable{T})"/> or + /// <see cref="List{T}.RemoveAll(Predicate{T})"/> with a predicate of <c>(value) => !collection.Contains(value)</c>. It is + /// recommended to use these alternatives when possible. + /// </summary> + /// <typeparam name="T">The type of the elements of <paramref name="source"/>.</typeparam> + /// <param name="source">An <see cref="ICollection{T}"/> to remove elements from.</param> + /// <param name="collection">An <see cref="ICollection{T}"/> containing the items to remove from <paramref name="source"/>.</param> + /// <returns><c>true</c> if the collection changed as a result of the call; otherwise, <c>false</c>.</returns> + [DebuggerStepThrough] + public static bool RetainAll<T>(this ICollection<T> source, ICollection<T> collection) + { + if (source == null) + throw new ArgumentNullException(nameof(source)); + if (collection == null) + throw new ArgumentNullException(nameof(collection)); + + if (source.Count == 0) return false; + + if (source is ISet<T> set) + { + int originalCount = set.Count; + set.IntersectWith(collection); + return originalCount != set.Count; + } + else if (source is IList<T> list) + { + int removed = list.RemoveAll((value) => !collection.Contains(value)); + return removed > 0; + } + + // Slow path for unknown collection types + var toRemove = new JCG.HashSet<T>(); + foreach (var e in source) + { + if (!collection.Contains(e)) + toRemove.Add(e); + } + if (toRemove.Count > 0) + return source.RemoveAll(toRemove); + return false; } } }
