From 0d7bba7a42a89a3e348c6c27370425b4db33b492 Mon Sep 17 00:00:00 2001
From: devklick <58235000+devklick@users.noreply.github.com>
Date: Sun, 18 Aug 2024 14:57:36 +0100
Subject: [PATCH] feat: #954 - TryDequeue and TryPeek Queue extension methods
(#957)
* feat: #954 - Add TryDequeue and TryPeek Queue extension methods
* feat: #954 - Use TryDequeue and TryPeek Queue extension methods
* Add license
* Use Queue.TryDequeue where possible
* Use Queue.TryPeek where possible
* Use explicit type over var
* Fix tests
* Run tests depending on feature flag
* Reinstate previous performance optimizations
* Fix QueueExtensions exception docs
* Remove unnecessary ParamName assertion in QueueExtensionsTests
* Add nullable support to QueueExtensions
---
Directory.Build.targets | 1 +
.../Compound/CompoundWordTokenFilterBase.cs | 6 +-
.../Analysis/Shingle/ShingleFilter.cs | 7 +-
.../Analysis/Th/ThaiTokenizer.cs | 22 +++--
.../DoubleMetaphoneFilter.cs | 6 +-
.../Support/ToParentBlockJoinCollector.cs | 7 +-
.../ToParentBlockJoinCollector.cs | 7 +-
.../Suggest/Tst/TSTAutocomplete.cs | 2 +-
.../Util/Automaton/AutomatonTestUtil.cs | 9 +-
.../Support/QueueExtensionsTests.cs | 93 +++++++++++++++++++
.../Index/DocumentsWriterFlushControl.cs | 10 +-
.../Index/DocumentsWriterFlushQueue.cs | 6 +-
src/Lucene.Net/Index/IndexWriter.cs | 8 +-
src/Lucene.Net/Search/NumericRangeQuery.cs | 11 ++-
src/Lucene.Net/Support/QueueExtensions.cs | 81 ++++++++++++++++
src/Lucene.Net/Util/Automaton/Automaton.cs | 16 ++--
.../Util/Automaton/BasicOperations.cs | 14 ++-
.../Util/Automaton/MinimizationOperations.cs | 8 +-
18 files changed, 240 insertions(+), 74 deletions(-)
create mode 100644 src/Lucene.Net.Tests/Support/QueueExtensionsTests.cs
create mode 100644 src/Lucene.Net/Support/QueueExtensions.cs
diff --git a/Directory.Build.targets b/Directory.Build.targets
index 6da2ebe6b3..966808152a 100644
--- a/Directory.Build.targets
+++ b/Directory.Build.targets
@@ -67,6 +67,7 @@
$(DefineConstants);FEATURE_NUMBER_PARSE_READONLYSPAN
$(DefineConstants);FEATURE_STREAM_READ_SPAN
$(DefineConstants);FEATURE_STRINGBUILDER_APPEND_READONLYSPAN
+ $(DefineConstants);FEATURE_QUEUE_TRYDEQUEUE_TRYPEEK
diff --git a/src/Lucene.Net.Analysis.Common/Analysis/Compound/CompoundWordTokenFilterBase.cs b/src/Lucene.Net.Analysis.Common/Analysis/Compound/CompoundWordTokenFilterBase.cs
index f17e2e0df2..def2884f05 100644
--- a/src/Lucene.Net.Analysis.Common/Analysis/Compound/CompoundWordTokenFilterBase.cs
+++ b/src/Lucene.Net.Analysis.Common/Analysis/Compound/CompoundWordTokenFilterBase.cs
@@ -4,6 +4,7 @@
using Lucene.Net.Analysis.Util;
using Lucene.Net.Diagnostics;
using Lucene.Net.Util;
+using Lucene.Net.Support;
using System;
using System.Collections.Generic;
@@ -109,10 +110,9 @@ protected CompoundWordTokenFilterBase(LuceneVersion matchVersion, TokenStream in
public override sealed bool IncrementToken()
{
- if (m_tokens.Count > 0)
+ if (m_tokens.TryDequeue(out CompoundToken token))
{
if (Debugging.AssertsEnabled) Debugging.Assert(current != null);
- CompoundToken token = m_tokens.Dequeue();
RestoreState(current); // keep all other attributes untouched
m_termAtt.SetEmpty().Append(token.Text);
m_offsetAtt.SetOffset(token.StartOffset, token.EndOffset);
@@ -197,4 +197,4 @@ public CompoundToken(CompoundWordTokenFilterBase compoundWordTokenFilterBase, in
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Lucene.Net.Analysis.Common/Analysis/Shingle/ShingleFilter.cs b/src/Lucene.Net.Analysis.Common/Analysis/Shingle/ShingleFilter.cs
index ccd0e0bbe9..9cadafd2d2 100644
--- a/src/Lucene.Net.Analysis.Common/Analysis/Shingle/ShingleFilter.cs
+++ b/src/Lucene.Net.Analysis.Common/Analysis/Shingle/ShingleFilter.cs
@@ -1,6 +1,7 @@
// Lucene version compatibility level 4.8.1
using Lucene.Net.Analysis.TokenAttributes;
using Lucene.Net.Util;
+using Lucene.Net.Support;
using System;
using System.Collections.Generic;
using System.IO;
@@ -508,11 +509,7 @@ public override void End()
/// if there's a problem getting the next token
private void ShiftInputWindow()
{
- InputWindowToken firstToken = null;
- if (inputWindow.Count > 0)
- {
- firstToken = inputWindow.Dequeue();
- }
+ inputWindow.TryDequeue(out InputWindowToken firstToken); // LUCENENET: firstToken will be null if the queue is empty
while (inputWindow.Count < maxShingleSize)
{
if (null != firstToken) // recycle the firstToken, if available
diff --git a/src/Lucene.Net.Analysis.Common/Analysis/Th/ThaiTokenizer.cs b/src/Lucene.Net.Analysis.Common/Analysis/Th/ThaiTokenizer.cs
index aba8a4328a..1bede96190 100644
--- a/src/Lucene.Net.Analysis.Common/Analysis/Th/ThaiTokenizer.cs
+++ b/src/Lucene.Net.Analysis.Common/Analysis/Th/ThaiTokenizer.cs
@@ -5,6 +5,7 @@
using J2N;
using Lucene.Net.Analysis.TokenAttributes;
using Lucene.Net.Analysis.Util;
+using Lucene.Net.Support;
using Lucene.Net.Support.Threading;
using Lucene.Net.Util;
using System;
@@ -236,8 +237,10 @@ public int Current
{
get
{
- if (transitions.Count > 0)
- return transitions.Peek();
+ if (transitions.TryPeek(out int current))
+ {
+ return current;
+ }
return wordBreaker.Current;
}
@@ -245,11 +248,10 @@ public int Current
public int Next()
{
- if (transitions.Count > 0)
- transitions.Dequeue();
-
- if (transitions.Count > 0)
- return transitions.Peek();
+ if (transitions.TryDequeue(out _) && transitions.TryPeek(out int next))
+ {
+ return next;
+ }
return GetNext();
}
@@ -297,10 +299,10 @@ private int GetNext()
prevWasNonThai = isNonThai;
}
- if (transitions.Count > 0)
+ if (transitions.TryPeek(out int transition))
{
transitions.Enqueue(current);
- return transitions.Peek();
+ return transition;
}
}
@@ -308,4 +310,4 @@ private int GetNext()
}
}
}
-#endif
\ No newline at end of file
+#endif
diff --git a/src/Lucene.Net.Analysis.Phonetic/DoubleMetaphoneFilter.cs b/src/Lucene.Net.Analysis.Phonetic/DoubleMetaphoneFilter.cs
index b4e2592275..bd1d89d34d 100644
--- a/src/Lucene.Net.Analysis.Phonetic/DoubleMetaphoneFilter.cs
+++ b/src/Lucene.Net.Analysis.Phonetic/DoubleMetaphoneFilter.cs
@@ -1,6 +1,7 @@
// lucene version compatibility level: 4.8.1
using Lucene.Net.Analysis.Phonetic.Language;
using Lucene.Net.Analysis.TokenAttributes;
+using Lucene.Net.Support;
using System;
using System.Collections.Generic;
@@ -37,7 +38,7 @@ public sealed class DoubleMetaphoneFilter : TokenFilter
private readonly IPositionIncrementAttribute posAtt;
///
- /// Creates a with the specified maximum code length,
+ /// Creates a with the specified maximum code length,
/// and either adding encoded forms as synonyms (inject=true) or
/// replacing them.
///
@@ -54,10 +55,9 @@ public override bool IncrementToken()
{
for (;;)
{
- if (!(remainingTokens.Count == 0))
+ if (remainingTokens.TryDequeue(out State first))
{
// clearAttributes(); // not currently necessary
- var first = remainingTokens.Dequeue();
RestoreState(first);
return true;
}
diff --git a/src/Lucene.Net.Join/Support/ToParentBlockJoinCollector.cs b/src/Lucene.Net.Join/Support/ToParentBlockJoinCollector.cs
index 697027aecc..873de9fc9e 100644
--- a/src/Lucene.Net.Join/Support/ToParentBlockJoinCollector.cs
+++ b/src/Lucene.Net.Join/Support/ToParentBlockJoinCollector.cs
@@ -351,11 +351,10 @@ public virtual void SetScorer(Scorer scorer)
var queue = new Queue();
//System.out.println("\nqueue: add top scorer=" + value);
queue.Enqueue(scorer);
- while (queue.Count > 0)
+ // LUCENENET NOTE: This reuses the scorer argument variable, which
+ // differs from this.scorer.
+ while (queue.TryDequeue(out scorer))
{
- // LUCENENET NOTE: This reuses the scorer argument variable, which
- // differs from this.scorer.
- scorer = queue.Dequeue();
//System.out.println(" poll: " + value + "; " + value.getWeight().getQuery());
if (scorer is ToParentBlockJoinQuery.BlockJoinScorer blockJoinScorer)
{
diff --git a/src/Lucene.Net.Join/ToParentBlockJoinCollector.cs b/src/Lucene.Net.Join/ToParentBlockJoinCollector.cs
index f37e3c4fb6..d42fe0dac3 100644
--- a/src/Lucene.Net.Join/ToParentBlockJoinCollector.cs
+++ b/src/Lucene.Net.Join/ToParentBlockJoinCollector.cs
@@ -349,11 +349,10 @@ public virtual void SetScorer(Scorer scorer)
var queue = new Queue();
//System.out.println("\nqueue: add top scorer=" + value);
queue.Enqueue(scorer);
- while (queue.Count > 0)
+ // LUCENENET NOTE: This reuses the scorer argument variable, which
+ // differs from this.scorer.
+ while (queue.TryDequeue(out scorer))
{
- // LUCENENET NOTE: This reuses the scorer argument variable, which
- // differs from this.scorer.
- scorer = queue.Dequeue();
//System.out.println(" poll: " + value + "; " + value.getWeight().getQuery());
if (scorer is ToParentBlockJoinQuery.BlockJoinScorer blockJoinScorer)
{
diff --git a/src/Lucene.Net.Suggest/Suggest/Tst/TSTAutocomplete.cs b/src/Lucene.Net.Suggest/Suggest/Tst/TSTAutocomplete.cs
index 5186e88e24..7bcd57b34a 100644
--- a/src/Lucene.Net.Suggest/Suggest/Tst/TSTAutocomplete.cs
+++ b/src/Lucene.Net.Suggest/Suggest/Tst/TSTAutocomplete.cs
@@ -203,4 +203,4 @@ public virtual IList PrefixCompletion(TernaryTreeNode root, str
return suggest;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Lucene.Net.TestFramework/Util/Automaton/AutomatonTestUtil.cs b/src/Lucene.Net.TestFramework/Util/Automaton/AutomatonTestUtil.cs
index 700b9cd14c..10c1544cdc 100644
--- a/src/Lucene.Net.TestFramework/Util/Automaton/AutomatonTestUtil.cs
+++ b/src/Lucene.Net.TestFramework/Util/Automaton/AutomatonTestUtil.cs
@@ -1,5 +1,6 @@
using J2N;
using J2N.Runtime.CompilerServices;
+using Lucene.Net.Support;
using Lucene.Net.Diagnostics;
using RandomizedTesting.Generators;
using System;
@@ -305,9 +306,8 @@ public static void DeterminizeSimple(Automaton a, ISet initialset)
worklist.Enqueue(initialset);
a.initial = new State();
newstate[initialset] = a.initial;
- while (worklist.Count > 0)
+ while (worklist.TryDequeue(out ISet s))
{
- ISet s = worklist.Dequeue();
State r = newstate[s];
foreach (State q in s)
{
@@ -466,9 +466,8 @@ public RandomAcceptedStrings(Automaton a)
// Breadth-first search, from accept states,
// backwards:
- while (q.Count > 0)
+ while (q.TryDequeue(out State s))
{
- State s = q.Dequeue();
if (allArriving.TryGetValue(s, out IList arriving) && arriving != null)
{
foreach (ArrivingTransition at in arriving)
@@ -566,4 +565,4 @@ public int[] GetRandomAcceptedString(Random r)
return soFar.ToArray(); // LUCENENET: ArrayUtil.ToIntArray() call unnecessary
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Lucene.Net.Tests/Support/QueueExtensionsTests.cs b/src/Lucene.Net.Tests/Support/QueueExtensionsTests.cs
new file mode 100644
index 0000000000..8b11f5a130
--- /dev/null
+++ b/src/Lucene.Net.Tests/Support/QueueExtensionsTests.cs
@@ -0,0 +1,93 @@
+using System.Collections.Generic;
+using NUnit.Framework;
+
+using Lucene.Net.Attributes;
+using Lucene.Net.Util;
+using Lucene.Net.Support;
+using System;
+
+using Assert = Lucene.Net.TestFramework.Assert;
+
+
+namespace Lucene.Net
+{
+ /*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+ public class QueueExtensionsTests : LuceneTestCase
+ {
+#if !FEATURE_QUEUE_TRYDEQUEUE_TRYPEEK
+ [Test, LuceneNetSpecific]
+ public void TryDequeue_ThrowsWhenQueueNull()
+ {
+ Queue queue = null;
+ Assert.Throws(() => queue.TryDequeue(out int _));
+ }
+
+ [Test, LuceneNetSpecific]
+ public void TryDequeue_QueueEmpty()
+ {
+ Queue queue = new Queue();
+ bool found = queue.TryDequeue(out int result);
+ Assert.AreEqual(found, false);
+ Assert.AreEqual(result, default(int));
+ }
+
+ [Test, LuceneNetSpecific]
+ public void TryDequeue_QueueNotEmpty()
+ {
+ Queue queue = new Queue();
+ int item = 1;
+ queue.Enqueue(item);
+ int countBefore = queue.Count;
+ bool found = queue.TryDequeue(out int result);
+ Assert.AreEqual(found, true);
+ Assert.AreEqual(result, item);
+ Assert.AreEqual(queue.Count, countBefore - 1);
+ }
+
+ [Test, LuceneNetSpecific]
+ public void TryPeek_ThrowsWhenQueueNull()
+ {
+ Queue queue = null;
+ Assert.Throws(() => queue.TryPeek(out int _));
+ }
+
+ [Test, LuceneNetSpecific]
+ public void TryPeek_QueueEmpty()
+ {
+ Queue queue = new Queue();
+ bool found = queue.TryPeek(out int result);
+ Assert.AreEqual(found, false);
+ Assert.AreEqual(result, default(int));
+ }
+
+ [Test, LuceneNetSpecific]
+ public void TryPeek_QueueNotEmpty()
+ {
+ Queue queue = new Queue();
+ int item = 1;
+ queue.Enqueue(item);
+ int countBefore = queue.Count;
+ bool found = queue.TryPeek(out int result);
+ Assert.AreEqual(found, true);
+ Assert.AreEqual(result, item);
+ Assert.AreEqual(queue.Count, countBefore);
+ }
+#endif
+ }
+}
diff --git a/src/Lucene.Net/Index/DocumentsWriterFlushControl.cs b/src/Lucene.Net/Index/DocumentsWriterFlushControl.cs
index b26588b5ac..7986cf99a2 100644
--- a/src/Lucene.Net/Index/DocumentsWriterFlushControl.cs
+++ b/src/Lucene.Net/Index/DocumentsWriterFlushControl.cs
@@ -1,6 +1,7 @@
using J2N.Runtime.CompilerServices;
using J2N.Threading.Atomic;
using Lucene.Net.Diagnostics;
+using Lucene.Net.Support;
using Lucene.Net.Support.Threading;
using Lucene.Net.Util;
using System;
@@ -501,8 +502,7 @@ internal DocumentsWriterPerThread NextPendingFlush()
UninterruptableMonitor.Enter(this);
try
{
- DocumentsWriterPerThread poll;
- if (flushQueue.Count > 0 && (poll = flushQueue.Dequeue()) != null)
+ if (flushQueue.TryDequeue(out DocumentsWriterPerThread poll))
{
UpdateStallState();
return poll;
@@ -641,7 +641,7 @@ internal int NumFlushingDWPT
}
}
- public bool GetAndResetApplyAllDeletes()
+ public bool GetAndResetApplyAllDeletes()
{
return flushDeletes.GetAndSet(false);
}
@@ -688,7 +688,7 @@ internal void MarkForFullFlush()
if (Debugging.AssertsEnabled)
{
Debugging.Assert(!fullFlush, "called DWFC#markForFullFlush() while full flush is still running");
- Debugging.Assert(fullFlushBuffer.Count == 0,"full flush buffer should be empty: {0}", fullFlushBuffer);
+ Debugging.Assert(fullFlushBuffer.Count == 0, "full flush buffer should be empty: {0}", fullFlushBuffer);
}
fullFlush = true;
flushingQueue = documentsWriter.deleteQueue;
@@ -765,7 +765,7 @@ private bool AssertActiveDeleteQueue(DocumentsWriterDeleteQueue queue)
next.@Lock();
try
{
- if (Debugging.AssertsEnabled) Debugging.Assert(!next.IsInitialized || next.dwpt.deleteQueue == queue,"isInitialized: {0} numDocs: {1}", next.IsInitialized, (next.IsInitialized ? next.dwpt.NumDocsInRAM : 0));
+ if (Debugging.AssertsEnabled) Debugging.Assert(!next.IsInitialized || next.dwpt.deleteQueue == queue, "isInitialized: {0} numDocs: {1}", next.IsInitialized, (next.IsInitialized ? next.dwpt.NumDocsInRAM : 0));
}
finally
{
diff --git a/src/Lucene.Net/Index/DocumentsWriterFlushQueue.cs b/src/Lucene.Net/Index/DocumentsWriterFlushQueue.cs
index 0d29d8a4f1..78770e1add 100644
--- a/src/Lucene.Net/Index/DocumentsWriterFlushQueue.cs
+++ b/src/Lucene.Net/Index/DocumentsWriterFlushQueue.cs
@@ -1,6 +1,7 @@
using J2N.Threading.Atomic;
using Lucene.Net.Diagnostics;
using Lucene.Net.Support.Threading;
+using Lucene.Net.Support;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
@@ -142,7 +143,7 @@ internal virtual bool HasTickets
{
get
{
- if (Debugging.AssertsEnabled) Debugging.Assert(ticketCount >= 0,"ticketCount should be >= 0 but was: {0}", ticketCount);
+ if (Debugging.AssertsEnabled) Debugging.Assert(ticketCount >= 0, "ticketCount should be >= 0 but was: {0}", ticketCount);
return ticketCount != 0;
}
}
@@ -158,8 +159,7 @@ private int InnerPurge(IndexWriter writer)
UninterruptableMonitor.Enter(this);
try
{
- head = queue.Count <= 0 ? null : queue.Peek();
- canPublish = head != null && head.CanPublish; // do this synced
+ canPublish = queue.TryPeek(out head) && head.CanPublish; // do this synced
}
finally
{
diff --git a/src/Lucene.Net/Index/IndexWriter.cs b/src/Lucene.Net/Index/IndexWriter.cs
index 48e651ea92..23c93846ea 100644
--- a/src/Lucene.Net/Index/IndexWriter.cs
+++ b/src/Lucene.Net/Index/IndexWriter.cs
@@ -2685,7 +2685,7 @@ public virtual ICollection MergingSegments
///
/// @lucene.experimental
///
- public virtual MergePolicy.OneMerge NextMerge()
+ public virtual MergePolicy.OneMerge NextMerge() // LUCENENET TODO: API - Revert name to GetNextMerge() to match Java
{
UninterruptableMonitor.Enter(this);
try
@@ -3382,7 +3382,7 @@ public virtual void AddIndexes(params Directory[] dirs)
JCG.HashSet copiedFiles = new JCG.HashSet();
foreach (SegmentCommitInfo info in sis.Segments)
{
- if (Debugging.AssertsEnabled) Debugging.Assert(!infos.Contains(info),"dup info dir={0} name={1}", info.Info.Dir, info.Info.Name);
+ if (Debugging.AssertsEnabled) Debugging.Assert(!infos.Contains(info), "dup info dir={0} name={1}", info.Info.Dir, info.Info.Name);
string newSegName = NewSegmentName();
@@ -4439,7 +4439,7 @@ private static void SkipDeletedDoc(DocValuesFieldUpdatesIterator[] updatesIters,
// when entering the method, all iterators must already be beyond the
// deleted document, or right on it, in which case we advance them over
// and they must be beyond it now.
- if (Debugging.AssertsEnabled) Debugging.Assert(iter.Doc > deletedDoc,"updateDoc={0} deletedDoc={1}", iter.Doc, deletedDoc);
+ if (Debugging.AssertsEnabled) Debugging.Assert(iter.Doc > deletedDoc, "updateDoc={0} deletedDoc={1}", iter.Doc, deletedDoc);
}
}
@@ -5986,7 +5986,7 @@ private void StartCommit(SegmentInfos toSync)
UninterruptableMonitor.Enter(this);
try
{
- if (Debugging.AssertsEnabled) Debugging.Assert(lastCommitChangeCount <= changeCount,"lastCommitChangeCount={0} changeCount={1}", lastCommitChangeCount, changeCount);
+ if (Debugging.AssertsEnabled) Debugging.Assert(lastCommitChangeCount <= changeCount, "lastCommitChangeCount={0} changeCount={1}", lastCommitChangeCount, changeCount);
if (pendingCommitChangeCount == lastCommitChangeCount)
{
diff --git a/src/Lucene.Net/Search/NumericRangeQuery.cs b/src/Lucene.Net/Search/NumericRangeQuery.cs
index baa59a2c15..28697939ce 100644
--- a/src/Lucene.Net/Search/NumericRangeQuery.cs
+++ b/src/Lucene.Net/Search/NumericRangeQuery.cs
@@ -1,6 +1,7 @@
using Lucene.Net.Diagnostics;
using Lucene.Net.Documents;
using Lucene.Net.Util;
+using Lucene.Net.Support;
using System;
using System.Collections.Generic;
using System.Text;
@@ -35,10 +36,10 @@ namespace Lucene.Net.Search
///
/// A that matches numeric values within a
/// specified range. To use this, you must first index the
- /// numeric values using ,
- /// , or (expert:
+ /// numeric values using ,
+ /// , or (expert:
/// ). If your terms are instead textual,
- /// you should use .
+ /// you should use .
/// is the filter equivalent of this
/// query.
///
@@ -68,7 +69,7 @@ namespace Lucene.Net.Search
/// classes. See below for
/// details.
///
- /// This query defaults to
+ /// This query defaults to
/// .
/// With precision steps of <=4, this query can be run with
/// one of the rewrite methods without changing
@@ -626,4 +627,4 @@ public static NumericRangeQuery NewSingleRange(string field, float? min,
return new NumericRangeQuery(field, NumericUtils.PRECISION_STEP_DEFAULT, NumericType.SINGLE, min, max, minInclusive, maxInclusive);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Lucene.Net/Support/QueueExtensions.cs b/src/Lucene.Net/Support/QueueExtensions.cs
new file mode 100644
index 0000000000..bef4cb80ef
--- /dev/null
+++ b/src/Lucene.Net/Support/QueueExtensions.cs
@@ -0,0 +1,81 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+
+#nullable enable
+
+namespace Lucene.Net.Support
+{
+ /*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+ ///
+ /// Extensions to
+ ///
+ internal static class QueueExtensions
+ {
+#if !FEATURE_QUEUE_TRYDEQUEUE_TRYPEEK
+ ///
+ /// Removes the object at the beginning of the ,
+ /// and copies it to the parameter.
+ ///
+ /// The type of element in the
+ /// The to be checked
+ /// The removed object
+ /// true if the object was successfully removed; false if the is empty.
+ /// is null.
+ public static bool TryDequeue(this Queue queue, [MaybeNullWhen(false)] out T result)
+ {
+ if (queue is null)
+ throw new ArgumentNullException(nameof(queue));
+
+ if (queue.Count > 0)
+ {
+ result = queue.Dequeue();
+ return true;
+ }
+
+ result = default;
+ return false;
+ }
+
+ ///
+ /// Returns a value that indicates whether there is an object at the beginning of the ,
+ /// and if one is present, copies it to the parameter. The object is not removed from the .
+ ///
+ /// The type of element in the
+ /// The to be checked
+ /// If present, the object at the beginning of the ; otherwise, the default value of
+ /// true if there is an object at the beginning of the ; false if the is empty.
+ /// is null.
+ public static bool TryPeek(this Queue queue, [MaybeNullWhen(false)] out T result)
+ {
+ if (queue is null)
+ throw new ArgumentNullException(nameof(queue));
+
+ if (queue.Count > 0)
+ {
+ result = queue.Peek();
+ return true;
+ }
+
+ result = default;
+ return false;
+ }
+#endif
+ }
+}
diff --git a/src/Lucene.Net/Util/Automaton/Automaton.cs b/src/Lucene.Net/Util/Automaton/Automaton.cs
index e275c28078..784cf24499 100644
--- a/src/Lucene.Net/Util/Automaton/Automaton.cs
+++ b/src/Lucene.Net/Util/Automaton/Automaton.cs
@@ -264,9 +264,8 @@ public virtual State[] GetNumberedStates()
initial.number = upto;
states[upto] = initial;
upto++;
- while (worklist.Count > 0)
+ while (worklist.TryDequeue(out State s))
{
- State s = worklist.Dequeue();
for (int i = 0; i < s.numTransitions; i++)
{
Transition t = s.TransitionsArray[i];
@@ -336,9 +335,8 @@ public virtual ISet GetAcceptStates()
Queue worklist = new Queue(); // LUCENENET specific - Queue is much more performant than LinkedList
worklist.Enqueue(initial);
visited.Add(initial);
- while (worklist.Count > 0)
+ while (worklist.TryDequeue(out State s))
{
- State s = worklist.Dequeue();
if (s.accept)
{
accepts.Add(s);
@@ -626,10 +624,10 @@ public override bool Equals(object obj)
//throw UnsupportedOperationException.Create("use BasicOperations.sameLanguage instead");
}
- // LUCENENET specific - in .NET, we can't simply throw an exception here because
+ // LUCENENET specific - in .NET, we can't simply throw an exception here because
// collections use this to determine equality. Most of this code was pieced together from
// BasicOperations.SubSetOf (which, when done both ways determines equality).
- public override int GetHashCode()
+ public override int GetHashCode()
{
if (IsSingleton)
{
@@ -644,12 +642,10 @@ public override int GetHashCode()
Queue worklist = new Queue(); // LUCENENET specific - Queue is much more performant than LinkedList
JCG.HashSet visited = new JCG.HashSet();
- State current;
worklist.Enqueue(this.initial);
visited.Add(this.initial);
- while (worklist.Count > 0)
+ while (worklist.TryDequeue(out State current))
{
- current = worklist.Dequeue();
hash = 31 * hash + current.accept.GetHashCode();
Transition[] t1 = transitions[current.number];
@@ -962,4 +958,4 @@ public static Automaton Minimize(Automaton a)
return a;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Lucene.Net/Util/Automaton/BasicOperations.cs b/src/Lucene.Net/Util/Automaton/BasicOperations.cs
index fb6d7f409f..a2c6f0ea91 100644
--- a/src/Lucene.Net/Util/Automaton/BasicOperations.cs
+++ b/src/Lucene.Net/Util/Automaton/BasicOperations.cs
@@ -1,5 +1,6 @@
using J2N;
using Lucene.Net.Diagnostics;
+using Lucene.Net.Support;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -404,9 +405,8 @@ public static Automaton Intersection(Automaton a1, Automaton a2)
StatePair p = new StatePair(c.initial, a1.initial, a2.initial);
worklist.Enqueue(p);
newstates[p] = p;
- while (worklist.Count > 0)
+ while (worklist.TryDequeue(out p))
{
- p = worklist.Dequeue();
p.s.accept = p.s1.accept && p.s2.accept;
Transition[] t1 = transitions1[p.s1.number];
Transition[] t2 = transitions2[p.s2.number];
@@ -497,9 +497,8 @@ public static bool SubsetOf(Automaton a1, Automaton a2)
StatePair p = new StatePair(a1.initial, a2.initial);
worklist.Enqueue(p);
visited.Add(p);
- while (worklist.Count > 0)
+ while (worklist.TryDequeue(out p))
{
- p = worklist.Dequeue();
if (p.s1.accept && !p.s2.accept)
{
return false;
@@ -822,9 +821,8 @@ public static void Determinize(Automaton a)
// like SortedMap
SortedInt32Set statesSet = new SortedInt32Set(5);
- while (worklist.Count > 0)
+ while (worklist.TryDequeue(out SortedInt32Set.FrozenInt32Set s))
{
- SortedInt32Set.FrozenInt32Set s = worklist.Dequeue();
//worklist.Remove(s);
// Collate all outgoing transitions by min/1+max:
@@ -912,7 +910,7 @@ public static void Determinize(Automaton a)
points.points[i].starts.count = 0;
}
points.Reset();
- if (Debugging.AssertsEnabled) Debugging.Assert(statesSet.upto == 0,"upto={0}", statesSet.upto);
+ if (Debugging.AssertsEnabled) Debugging.Assert(statesSet.upto == 0, "upto={0}", statesSet.upto);
}
a.deterministic = true;
a.SetNumberedStates(newStatesArray, newStateUpto);
@@ -1117,4 +1115,4 @@ public static bool Run(Automaton a, string s)
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Lucene.Net/Util/Automaton/MinimizationOperations.cs b/src/Lucene.Net/Util/Automaton/MinimizationOperations.cs
index 630303e309..6cb382c3fe 100644
--- a/src/Lucene.Net/Util/Automaton/MinimizationOperations.cs
+++ b/src/Lucene.Net/Util/Automaton/MinimizationOperations.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Runtime.InteropServices;
using JCG = J2N.Collections.Generic;
+using Lucene.Net.Support;
/*
* dk.brics.automaton
@@ -85,7 +86,7 @@ public static void MinimizeHopcroft(Automaton a)
StateListNode[,] active2 = new StateListNode[statesLen, sigmaLen];
Queue pending = new Queue(); // LUCENENET specific - Queue is much more performant than LinkedList
OpenBitSet pending2 = new OpenBitSet(sigmaLen * statesLen);
- OpenBitSet split = new OpenBitSet(statesLen),
+ OpenBitSet split = new OpenBitSet(statesLen),
refine = new OpenBitSet(statesLen), refine2 = new OpenBitSet(statesLen);
for (int q = 0; q < statesLen; q++)
{
@@ -137,9 +138,8 @@ public static void MinimizeHopcroft(Automaton a)
}
// process pending until fixed point
int k = 2;
- while (pending.Count > 0)
+ while (pending.TryDequeue(out Int32Pair ip))
{
- Int32Pair ip = pending.Dequeue();
int p = ip.n1;
int x = ip.n2;
pending2.Clear(x * statesLen + p);
@@ -323,4 +323,4 @@ internal void Remove()
}
}
}
-}
\ No newline at end of file
+}