-
Notifications
You must be signed in to change notification settings - Fork 639
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: #954 - TryDequeue and TryPeek Queue extension methods #957
feat: #954 - TryDequeue and TryPeek Queue extension methods #957
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR and your willingness to help make our project better.
There are a few changes we would like you to make before we can accept this PR. First, please see the comments inline.
{ | ||
firstToken = inputWindow.Dequeue(); | ||
} | ||
inputWindow.TryDequeue(out InputWindowToken firstToken); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this doesn't align very well with the Java source, lets add a comment so it is clear that firstToken will be null if the queue is empty.
inputWindow.TryDequeue(out InputWindowToken firstToken); // LUCENENET: firstToken will be null if the queue is empty
@@ -52,12 +53,11 @@ public DoubleMetaphoneFilter(TokenStream input, int maxCodeLength, bool inject) | |||
|
|||
public override bool IncrementToken() | |||
{ | |||
for (;;) | |||
for (; ; ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As much as I dislike using a for loop this way, it is what was done in Java.
But the original source didn't have spaces. So could we please remove them again?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apologies - automatic editor linting. I've removed those spaces.
{ | ||
Queue<int> queue = null; | ||
var ex = Assert.Throws<ArgumentNullException>(() => queue.TryDequeue(out int _)); | ||
Assert.That(ex.ParamName, Is.EqualTo("queue")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assert.That()
is painfully slow. In fact, we don't use any NUnit asserts because they cause our tests to take about twice as long. Please add the following alias after the list of usings:
using Assert = Lucene.Net.TestFramework.Assert;
And change each Assert.That()
in this file to use Assert.AreEqual()
. We have optimized overloads of these asserts that accept value types.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apologies, I should have checked the existing tests to see what to use. I've updated to use Lucene Assert now.
Note that since the Lucene equivalent doesnt cast the returned exception to T
(which I guess might be for performance reasons), I'm casting it to ArgumentNullException
within two of these tests to verify the ParamName
. Please let me know if I should avoid doing do. I notice that the existing tests for Assert.Throws<ArgumentNullException>
dont bother checking the ParamName
, so maybe this is overkill?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, usually just asserting the correct error type is enough, although some tests check error messages, as well.
src/Lucene.Net/Index/IndexWriter.cs
Outdated
@@ -2690,17 +2690,12 @@ public virtual MergePolicy.OneMerge NextMerge() | |||
UninterruptableMonitor.Enter(this); | |||
try | |||
{ | |||
if (pendingMerges.Count == 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe in this case, this is a performance optimization to give up the lock as soon as possible on an empty queue.
Please revert the changes in this method, as it is easier to follow as-is.
Also, please add a comment after the method declaration:
public virtual MergePolicy.OneMerge NextMerge() // LUCENENET TODO: API - Revert name to GetNextMerge() to match Java
We will need to review more of the API before renaming to make certain that it is consistent with other method names.
@@ -487,12 +488,12 @@ protected override sealed AcceptStatus Accept(BytesRef term) | |||
{ | |||
while (currentUpperBound is null || termComp.Compare(term, currentUpperBound) > 0) | |||
{ | |||
if (rangeBounds.Count == 0) | |||
if (!rangeBounds.TryPeek(out BytesRef rangeBound)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This appears to be a performance optimization to exit the loop as soon as possible.
Please revert the changes to this method.
/// <param name="result">The removed object</param> | ||
/// <returns><c>true</c> if the object was successfully removed; <c>false</c> if the <see cref="Queue{T}"/> is empty.</returns> | ||
/// <exception cref="ArgumentNullException"></exception> | ||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this is a bit too much code to make inlining worth it. It will only apply to legacy frameworks, anyway. Please remove [MethodImpl(MethodImplOptions.AggressiveInlining)]
both here and on TryPeek()
.
/// <param name="queue">The <see cref="Queue{T}"/> to be checked</param> | ||
/// <param name="result">The removed object</param> | ||
/// <returns><c>true</c> if the object was successfully removed; <c>false</c> if the <see cref="Queue{T}"/> is empty.</returns> | ||
/// <exception cref="ArgumentNullException"></exception> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add " is null</>." within this element both here and in TryPeek().
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @NightOwl888, can you please clarify, do you mean the following?
<exception cref="ArgumentNullException">is null</exception>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My apologies. GitHub stripped the angle brackets.
<exception cref="ArgumentNullException"><paramref name="queue"/> is <c>null</>.</exception>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I apologize for adding additional requirements, but could you please add nullable reference type support? See my inline comments.
/// <param name="result">The removed object</param> | ||
/// <returns><c>true</c> if the object was successfully removed; <c>false</c> if the <see cref="Queue{T}"/> is empty.</returns> | ||
/// <exception cref="ArgumentNullException"><paramref name="queue"/> is <c>null</c>.</exception> | ||
public static bool TryDequeue<T>(this Queue<T> queue, out T result) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add the [MaybeNullWhen(false)]
attribute before the out
modifier.
/// <param name="result">If present, the object at the beginning of the <see cref="Queue{T}"/>; otherwise, the default value of <typeparamref name="T"/></param> | ||
/// <returns><c>true</c> if there is an object at the beginning of the <see cref="Queue{T}"/>; <c>false</c> if the <see cref="Queue{T}"/> is empty.</returns> | ||
/// <exception cref="ArgumentNullException"><paramref name="queue"/> is <c>null</c>.</exception> | ||
public static bool TryPeek<T>(this Queue<T> queue, out T result) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add the [MaybeNullWhen(false)]
attribute before the out
modifier.
Thanks again for your contribution. Your help is appreciated. |
Add TryDequeue and TryPeek Queue extension methods
Fixes #954
Description
New class created,
QueueExtensions
, with two new methods,TryDequeue
andTryPeek
. These are compiled based on theFEATURE_QUEUE_TRYDEQUEUE_TRYPEEK
flag.Notes:
One of the requirements on the linked ticket was to update all references to use these new functions. I have updated some of them, only where it will eliminate a check along the lines of
queue.count > 0 && queue.Dequeue/Peek()
. There are more calls toqueue.Dequeue()
andqueue.Peek()
where it did not seem suitable to replace with the Try* equivalent, so I have left them as-is.The
QueueExtensionsTests
suite of tests will be testing the actual methods on the Queue object when testing on any framework other than netstandard2.0 and .NET Framework, rather than testing our extensions. Should these tests be configured to only run for certain frameworks? Seems redundant to have unit tests targeting a built-in feature.