Skip to content
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

Fix Queue bug #4300 #4302

Merged
merged 2 commits into from Dec 4, 2016
Merged

Fix Queue bug #4300 #4302

merged 2 commits into from Dec 4, 2016

Conversation

@Darkyenus
Copy link
Contributor

Darkyenus commented Sep 11, 2016

Also adds a new test for this edge-case (verbatim from issue) and cleans up Queue and QueueTest (in separate commits for easy review).

When removeIndex removed first value in queue which was also in
the last position of values array, head would be at values.length,
which is not a correct position for head to be in.

Fixed by adding a check which would wrap head back to zero
in this case.
@Darkyenus Darkyenus mentioned this pull request Sep 11, 2016
7 of 7 tasks complete
Copy link
Member

gjroelofs left a comment

Better to be verbose than to hide in one liners, also LibGDX formatter.

gdx/src/com/badlogic/gdx/utils/Queue.java Outdated
@@ -142,8 +141,7 @@ public T removeFirst () {

final T result = values[head];
values[head] = null;
head++;

This comment has been minimized.

Copy link
@gjroelofs

gjroelofs Sep 16, 2016

Member

Personally, I'd refrain from this pattern as it just makes the code harder to read without any performance benefits.

This comment has been minimized.

Copy link
@Darkyenus

Darkyenus Sep 17, 2016

Author Contributor

I did it to be in line with libGDX's pattern of bringing object fields into method variables first before accessing them multiple times, for performance reasons (for Android, mainly, IIRC) (performance reason being, that due to multithreading, these two variants may have different semantics. It is true that JVM is free to change the semantics slightly for optimizations, I am not sure if it happens on Dalvik (or at least its earlier versions). Since this pattern is so common, I expect that it is just for this reason).

I'll let others decide on which "style" should be used, as similar pattern of inlining inc/dec operations is fairly common in libGDX's collections (just maybe not inside if()?).

This comment has been minimized.

Copy link
@gjroelofs

gjroelofs Sep 18, 2016

Member

The main comment is on the if(++head ..) format which is an inc/dec operator inside the if loop.

This comment has been minimized.

Copy link
@Darkyenus

Darkyenus Sep 19, 2016

Author Contributor

I have assumed so. My argument is that:

this.head++;
if(this.head == values.length) ...

requires two reads from the object, while:

if(++this.head == values.length) ...

has to read just once, which could be slightly faster, in some circumstances.

But it is not a big deal either way. I'll wait for core contributors to decide.

This comment has been minimized.

Copy link
@RBogie

RBogie Sep 19, 2016

Member

So, I just want to jump in on this discussion.

First of all, I want to say that for readability, I prefer having the increment out of the if.

However, I mostly want to jump in because of the argument that this would create multiple reads. Fact is, you simply can't rely on what bytecode is generated for such small syntactic differences. I did test it out for the current java version on my system (javac 1.8.0_74), and when using an instance field it actually generated the exact same bytecode:

aload_0     //Load this pointer on stack
dup         //Duplicate this pointer on stack
getfield #2 // Field test:I
iconst_1    // Push 1 to stack
iadd        // Add top 2 elements
putfield #2 // Field test:I
aload_0     // Load this pointer on stack
getfield #2 // Field test:I

However, when using a static field, it would read the field only once, but duplicate it once more on the stack. It then depends on the jit compiler whether one is faster than the other. However, in the field instance case, performance will be exactly the same.

This comment has been minimized.

Copy link
@gjroelofs

gjroelofs Sep 20, 2016

Member

@Darkyenus Apologies, I misinterpreted your explanation as I saw no assignment. To me, this level of optimization is rather done by the compiler if it comes a the expense of readability.

gdx/src/com/badlogic/gdx/utils/Queue.java Outdated
System.arraycopy(values, head, values, head + 1, index - head);
values[head] = null;
this.head++;

This comment has been minimized.

Copy link
@gjroelofs

gjroelofs Sep 16, 2016

Member

Same as l145

gdx/test/com/badlogic/gdx/utils/QueueTest.java Outdated
@@ -290,6 +313,6 @@ private void assertEqualsAndHash (Queue<?> q1, Queue<?> q2) {

private void assertValues (Queue<Integer> q, Integer... values) {
for (int i = 0, n = values.length; i < n; i++)
if (values[i] != q.get(i)) fail(q + " != " + new Array(values));
if (values[i] == null ? q.get(i) != null : !values[i].equals(q.get(i))) fail(q + " != " + new Array(values));

This comment has been minimized.

Copy link
@gjroelofs

gjroelofs Sep 16, 2016

Member

Probably better not to have ternary statements inside if statements. Better to split it up.
Also, make sure you're using the LibGDX formatter.

This comment has been minimized.

Copy link
@Darkyenus

Darkyenus Sep 17, 2016

Author Contributor

This is IntelliJ autogenerated null-safe equals check. I can split it if needed, but as it is just in Test, I didn't deem that necessary.

This comment has been minimized.

Copy link
@gjroelofs

gjroelofs Sep 20, 2016

Member

After rereading; I'd just use Assert.assertEquals().

@Darkyenus Darkyenus force-pushed the Darkyenus:queue-fix branch to 60d4c8f Sep 20, 2016
@Darkyenus
Copy link
Contributor Author

Darkyenus commented Sep 20, 2016

Fair points, thanks for comments, amended!

@gjroelofs
Copy link
Member

gjroelofs commented Sep 21, 2016

Also; thanks for the fix :-)

@badlogic badlogic merged commit 59dbc14 into libgdx:master Dec 4, 2016
1 check passed
1 check passed
LibGDX PR Check No test results found.
Details
@badlogic
Copy link
Member

badlogic commented Dec 4, 2016

Thanks!

@Darkyenus Darkyenus deleted the Darkyenus:queue-fix branch Dec 4, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

4 participants
You can’t perform that action at this time.