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 1dc0f320eb4e8e133dddb85fd14cc7f2c2952c51 Author: Shad Storhaug <[email protected]> AuthorDate: Sat Aug 29 20:38:03 2020 +0700 Lucene.Net.Util.FilterIterator<T>: Converted to FilterEnumerator<T> using a predicate passed into the constructor rather than having to subclass. Swapped only usage in FieldFilterAtomicReader with a LINQ query/yield return, since performance is better. (see #279) --- .../Index/FieldFilterAtomicReader.cs | 27 +--- src/Lucene.Net.Tests/Util/TestFilterIterator.cs | 151 +++++++++++++++------ src/Lucene.Net/Util/FilterIterator.cs | 50 +++++++ 3 files changed, 170 insertions(+), 58 deletions(-) diff --git a/src/Lucene.Net.TestFramework/Index/FieldFilterAtomicReader.cs b/src/Lucene.Net.TestFramework/Index/FieldFilterAtomicReader.cs index f1b2b29..dcdb495 100644 --- a/src/Lucene.Net.TestFramework/Index/FieldFilterAtomicReader.cs +++ b/src/Lucene.Net.TestFramework/Index/FieldFilterAtomicReader.cs @@ -1,5 +1,6 @@ using Lucene.Net.Util; using System.Collections.Generic; +using System.Linq; using System.Text; namespace Lucene.Net.Index @@ -176,29 +177,15 @@ namespace Lucene.Net.Index this.outerInstance = outerInstance; } - public override int Count => - // this information is not cheap, return -1 like MultiFields does: - -1; + // this information is not cheap, return -1 like MultiFields does: + public override int Count => -1; public override IEnumerator<string> GetEnumerator() { - return new FilterIteratorAnonymousInnerClassHelper(this, base.GetEnumerator()); - } - - private class FilterIteratorAnonymousInnerClassHelper : FilterIterator<string> - { - private readonly FieldFilterFields outerInstance; - - public FilterIteratorAnonymousInnerClassHelper(FieldFilterFields outerInstance, IEnumerator<string> iterator) - : base(iterator) - { - this.outerInstance = outerInstance; - } - - protected override bool PredicateFunction(string field) - { - return outerInstance.outerInstance.HasField(field); - } + // LUCENENET: Performance is better and code simpler with simple where clause + // and yield return. + foreach (var field in m_input.Where((f) => outerInstance.HasField(f))) + yield return field; } public override Terms GetTerms(string field) diff --git a/src/Lucene.Net.Tests/Util/TestFilterIterator.cs b/src/Lucene.Net.Tests/Util/TestFilterIterator.cs index edf8b98..3652c03 100644 --- a/src/Lucene.Net.Tests/Util/TestFilterIterator.cs +++ b/src/Lucene.Net.Tests/Util/TestFilterIterator.cs @@ -37,10 +37,105 @@ namespace Lucene.Net.Util [Test] public virtual void TestEmpty() { + IEnumerator<string> it = new FilterEnumerator<string>(set.GetEnumerator(), (s) => false); + AssertNoMore(it); + } + + [Test] + public virtual void TestA1() + { + IEnumerator<string> it = new FilterEnumerator<string>(set.GetEnumerator(), (s) => "a".Equals(s, StringComparison.Ordinal)); + Assert.IsTrue(it.MoveNext()); + Assert.AreEqual("a", it.Current); + AssertNoMore(it); + } + + [Test] + public virtual void TestA2() + { + IEnumerator<string> it = new FilterEnumerator<string>(set.GetEnumerator(), (s) => "a".Equals(s, StringComparison.Ordinal)); + // this time without check: Assert.IsTrue(it.hasNext()); + it.MoveNext(); + Assert.AreEqual("a", it.Current); + AssertNoMore(it); + } + + [Test] + public virtual void TestB1() + { + IEnumerator<string> it = new FilterEnumerator<string>(set.GetEnumerator(), (s) => "b".Equals(s, StringComparison.Ordinal)); + Assert.IsTrue(it.MoveNext()); + Assert.AreEqual("b", it.Current); + AssertNoMore(it); + } + + [Test] + public virtual void TestB2() + { + IEnumerator<string> it = new FilterEnumerator<string>(set.GetEnumerator(), (s) => "b".Equals(s, StringComparison.Ordinal)); + // this time without check: Assert.IsTrue(it.hasNext()); + it.MoveNext(); + Assert.AreEqual("b", it.Current); + AssertNoMore(it); + } + + [Test] + public virtual void TestAll1() + { + IEnumerator<string> it = new FilterEnumerator<string>(set.GetEnumerator(), (s) => true); + Assert.IsTrue(it.MoveNext()); + Assert.AreEqual("a", it.Current); + Assert.IsTrue(it.MoveNext()); + Assert.AreEqual("b", it.Current); + Assert.IsTrue(it.MoveNext()); + Assert.AreEqual("c", it.Current); + AssertNoMore(it); + } + + [Test] + public virtual void TestAll2() + { + IEnumerator<string> it = new FilterEnumerator<string>(set.GetEnumerator(), (s) => true); + it.MoveNext(); + Assert.AreEqual("a", it.Current); + it.MoveNext(); + Assert.AreEqual("b", it.Current); + it.MoveNext(); + Assert.AreEqual("c", it.Current); + AssertNoMore(it); + } + + //// LUCENENET specific: .NET doesn't support Remove(), so this test doesn't apply + //[Test] + //public virtual void TestUnmodifiable() + //{ + // IEnumerator<string> it = new FilterEnumerator<string>(Set.GetEnumerator(), (s) => true); + // it.MoveNext(); + // Assert.AreEqual("a", it.Current); + // try + // { + + // it.Remove(); + // Assert.Fail("Should throw UnsupportedOperationException"); + // } + // catch (NotSupportedException) + // { + // // pass + // } + //} + + + + + [Test] + [Obsolete("This method will be removed in 4.8.0 release candidate."), System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public virtual void TestEmptyIterator() + { IEnumerator<string> it = new FilterIteratorAnonymousInnerClassHelper(set.GetEnumerator()); AssertNoMore(it); } + [Obsolete("This class will be removed in 4.8.0 release candidate."), System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] private class FilterIteratorAnonymousInnerClassHelper : FilterIterator<string> { public FilterIteratorAnonymousInnerClassHelper(IEnumerator<string> iterator) @@ -55,7 +150,8 @@ namespace Lucene.Net.Util } [Test] - public virtual void TestA1() + [Obsolete("This method will be removed in 4.8.0 release candidate."), System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public virtual void TestA1Iterator() { IEnumerator<string> it = new FilterIteratorAnonymousInnerClassHelper2(set.GetEnumerator()); Assert.IsTrue(it.MoveNext()); @@ -63,6 +159,7 @@ namespace Lucene.Net.Util AssertNoMore(it); } + [Obsolete("This class will be removed in 4.8.0 release candidate."), System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] private class FilterIteratorAnonymousInnerClassHelper2 : FilterIterator<string> { public FilterIteratorAnonymousInnerClassHelper2(IEnumerator<string> iterator) @@ -77,7 +174,8 @@ namespace Lucene.Net.Util } [Test] - public virtual void TestA2() + [Obsolete("This method will be removed in 4.8.0 release candidate."), System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public virtual void TestA2Iterator() { IEnumerator<string> it = new FilterIteratorAnonymousInnerClassHelper3(set.GetEnumerator()); // this time without check: Assert.IsTrue(it.hasNext()); @@ -86,6 +184,7 @@ namespace Lucene.Net.Util AssertNoMore(it); } + [Obsolete("This class will be removed in 4.8.0 release candidate."), System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] private class FilterIteratorAnonymousInnerClassHelper3 : FilterIterator<string> { public FilterIteratorAnonymousInnerClassHelper3(IEnumerator<string> iterator) @@ -100,7 +199,8 @@ namespace Lucene.Net.Util } [Test] - public virtual void TestB1() + [Obsolete("This method will be removed in 4.8.0 release candidate."), System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public virtual void TestB1Iterator() { IEnumerator<string> it = new FilterIteratorAnonymousInnerClassHelper4(set.GetEnumerator()); Assert.IsTrue(it.MoveNext()); @@ -108,6 +208,7 @@ namespace Lucene.Net.Util AssertNoMore(it); } + [Obsolete("This class will be removed in 4.8.0 release candidate."), System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] private class FilterIteratorAnonymousInnerClassHelper4 : FilterIterator<string> { public FilterIteratorAnonymousInnerClassHelper4(IEnumerator<string> iterator) @@ -122,7 +223,8 @@ namespace Lucene.Net.Util } [Test] - public virtual void TestB2() + [Obsolete("This method will be removed in 4.8.0 release candidate."), System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public virtual void TestB2Iterator() { IEnumerator<string> it = new FilterIteratorAnonymousInnerClassHelper5(set.GetEnumerator()); // this time without check: Assert.IsTrue(it.hasNext()); @@ -131,6 +233,7 @@ namespace Lucene.Net.Util AssertNoMore(it); } + [Obsolete("This class will be removed in 4.8.0 release candidate."), System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] private class FilterIteratorAnonymousInnerClassHelper5 : FilterIterator<string> { public FilterIteratorAnonymousInnerClassHelper5(IEnumerator<string> iterator) @@ -145,7 +248,8 @@ namespace Lucene.Net.Util } [Test] - public virtual void TestAll1() + [Obsolete("This method will be removed in 4.8.0 release candidate."), System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public virtual void TestAll1Iterator() { IEnumerator<string> it = new FilterIteratorAnonymousInnerClassHelper6(set.GetEnumerator()); Assert.IsTrue(it.MoveNext()); @@ -157,6 +261,7 @@ namespace Lucene.Net.Util AssertNoMore(it); } + [Obsolete("This class will be removed in 4.8.0 release candidate."), System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] private class FilterIteratorAnonymousInnerClassHelper6 : FilterIterator<string> { public FilterIteratorAnonymousInnerClassHelper6(IEnumerator<string> iterator) @@ -171,7 +276,8 @@ namespace Lucene.Net.Util } [Test] - public virtual void TestAll2() + [Obsolete("This method will be removed in 4.8.0 release candidate."), System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public virtual void TestAll2Iterator() { IEnumerator<string> it = new FilterIteratorAnonymousInnerClassHelper7(set.GetEnumerator()); it.MoveNext(); @@ -183,6 +289,7 @@ namespace Lucene.Net.Util AssertNoMore(it); } + [Obsolete("This class will be removed in 4.8.0 release candidate."), System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] private class FilterIteratorAnonymousInnerClassHelper7 : FilterIterator<string> { public FilterIteratorAnonymousInnerClassHelper7(IEnumerator<string> iterator) @@ -195,37 +302,5 @@ namespace Lucene.Net.Util return true; } } - - //// LUCENENET specific: .NET doesn't support Remove(), so this test doesn't apply - //[Test] - //public virtual void TestUnmodifiable() - //{ - // IEnumerator<string> it = new FilterIteratorAnonymousInnerClassHelper8(Set.GetEnumerator()); - // it.MoveNext(); - // Assert.AreEqual("a", it.Current); - // try - // { - - // it.Remove(); - // Assert.Fail("Should throw UnsupportedOperationException"); - // } - // catch (NotSupportedException) - // { - // // pass - // } - //} - - //private class FilterIteratorAnonymousInnerClassHelper8 : FilterIterator<string> - //{ - // public FilterIteratorAnonymousInnerClassHelper8(IEnumerator<string> iterator) - // : base(iterator) - // { - // } - - // protected override bool PredicateFunction(string s) - // { - // return true; - // } - //} } } \ No newline at end of file diff --git a/src/Lucene.Net/Util/FilterIterator.cs b/src/Lucene.Net/Util/FilterIterator.cs index c8d9578..7742977 100644 --- a/src/Lucene.Net/Util/FilterIterator.cs +++ b/src/Lucene.Net/Util/FilterIterator.cs @@ -23,7 +23,57 @@ namespace Lucene.Net.Util /// <summary> /// An <see cref="IEnumerator{T}"/> implementation that filters elements with a boolean predicate. </summary> + // LUCENENET specific - simplifed the logic, as this is much easier to do in .NET + public sealed class FilterEnumerator<T> : IEnumerator<T> + { + private readonly IEnumerator<T> iter; + private readonly Predicate<T> predicateFunction; + private T current; + + /// <summary> + /// Initializes a new instance of <see cref="FilterEnumerator{T}"/> with the specified <paramref name="baseEnumerator"/> and <paramref name="predicateFunction"/>. + /// </summary> + /// <param name="baseEnumerator"></param> + /// <param name="predicateFunction">Returns <c>true</c>, if this element should be set to <see cref="Current"/> by <see cref="MoveNext()"/>.</param> + public FilterEnumerator(IEnumerator<T> baseEnumerator, Predicate<T> predicateFunction) + { + this.iter = baseEnumerator ?? throw new ArgumentNullException(nameof(baseEnumerator)); + this.predicateFunction = predicateFunction ?? throw new ArgumentNullException(nameof(predicateFunction)); + current = default; + } + + public bool MoveNext() + { + while (iter.MoveNext()) + { + if (predicateFunction(iter.Current)) + { + current = iter.Current; + return true; + } + } + current = default; + return false; + } + + // LUCENENET specific - seems logical to call reset on the underlying implementation + public void Reset() + { + current = default; + iter.Reset(); + } + + public T Current => current; + + object System.Collections.IEnumerator.Current => current; + + public void Dispose() => iter.Dispose(); + } + + /// <summary> + /// An <see cref="IEnumerator{T}"/> implementation that filters elements with a boolean predicate. </summary> /// <seealso cref="PredicateFunction(T)"/> + [Obsolete("Use FilterEnumerator<T> instead. This class will be removed in 4.8.0 release candidate."), System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public abstract class FilterIterator<T> : IEnumerator<T> { private readonly IEnumerator<T> iter;
